Merge pull request #359 from devchat-ai/feat/idea
feat: move views into the gui project and modify the packaging method
This commit is contained in:
commit
ba9da6d8ee
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
||||
[submodule "tools"]
|
||||
path = tools
|
||||
url = git@github.com:devchat-ai/devchat-vscode-tools.git
|
||||
[submodule "gui"]
|
||||
path = gui
|
||||
url = https://github.com/devchat-ai/devchat-gui.git
|
||||
|
1
gui
Submodule
1
gui
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 204a8b434948f124444e07f8153ea32194587d76
|
@ -797,6 +797,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build:gui":"cd ./gui && yarn && yarn vscode",
|
||||
"vscode:uninstall": "node ./dist/uninstall",
|
||||
"vscode:prepublish": "npm run package",
|
||||
"compile": "webpack",
|
||||
@ -807,8 +808,9 @@
|
||||
"pretest": "npm run compile-tests && npm run compile && npm run lint",
|
||||
"lint": "eslint src --ext ts",
|
||||
"test": "mocha",
|
||||
"build": "webpack --config webpack.config.js",
|
||||
"dev": "webpack serve --config webpack.config.js --open"
|
||||
"build": "webpack --config webpack.config.js && cd ./gui && yarn && yarn vscode",
|
||||
"dev": "webpack serve --config webpack.config.js --open",
|
||||
"idea": "webpack --config webpack.idea.config.js && mv dist/main.js dist/main.html ../devchat-intellij/src/main/resources/static && echo '🎆done'"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.8",
|
||||
@ -872,6 +874,8 @@
|
||||
"@tiptap/react": "^2.0.3",
|
||||
"@tiptap/starter-kit": "^2.0.3",
|
||||
"axios": "^1.3.6",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"dotenv": "^16.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"mdast": "^3.0.0",
|
||||
|
19
src/main.html
Normal file
19
src/main.html
Normal file
@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>DevChat</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script></script>
|
||||
</body>
|
||||
</html>
|
6
src/types/globle.d.ts
vendored
Normal file
6
src/types/globle.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
[key: string]: any;
|
||||
}
|
||||
}
|
||||
export {};
|
@ -1,26 +1,27 @@
|
||||
|
||||
// @ts-ignore
|
||||
const vscodeApi = window.acquireVsCodeApi();
|
||||
import IdeaBridge from "./ideaBridge";
|
||||
|
||||
class MessageUtil {
|
||||
|
||||
private static instance: MessageUtil;
|
||||
|
||||
handlers: { [x: string]: any; };
|
||||
handlers: { [x: string]: any };
|
||||
vscodeApi: any;
|
||||
messageListener: any;
|
||||
|
||||
constructor() {
|
||||
this.handlers = {};
|
||||
this.messageListener = null;
|
||||
if (process.env.platform === "vscode") {
|
||||
this.vscodeApi = window.acquireVsCodeApi();
|
||||
}
|
||||
|
||||
if (!this.messageListener) {
|
||||
this.messageListener = (event: { data: any; }) => {
|
||||
this.messageListener = (event: { data: any }) => {
|
||||
const message = event.data;
|
||||
this.handleMessage(message);
|
||||
};
|
||||
window.addEventListener('message', this.messageListener);
|
||||
window.addEventListener("message", this.messageListener);
|
||||
} else {
|
||||
console.log('Message listener has already been bound.');
|
||||
console.log("Message listener has already been bound.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,10 +34,14 @@ class MessageUtil {
|
||||
|
||||
// Register a message handler for a specific message type
|
||||
registerHandler(messageType: string, handler: any) {
|
||||
if (!this.handlers[messageType]) {
|
||||
this.handlers[messageType] = [];
|
||||
if (process.env.platform === "idea") {
|
||||
IdeaBridge.registerHandler(messageType, handler);
|
||||
} else {
|
||||
if (!this.handlers[messageType]) {
|
||||
this.handlers[messageType] = [];
|
||||
}
|
||||
this.handlers[messageType].push(handler);
|
||||
}
|
||||
this.handlers[messageType].push(handler);
|
||||
}
|
||||
|
||||
// Unregister a message handler for a specific message type
|
||||
@ -49,17 +54,22 @@ class MessageUtil {
|
||||
}
|
||||
|
||||
// Handle a received message
|
||||
handleMessage(message: { command: string | number; }) {
|
||||
handleMessage(message: { command: string | number }) {
|
||||
const handlers = this.handlers[message.command];
|
||||
if (handlers) {
|
||||
handlers.forEach((handler: (arg0: { command: string | number; }) => any) => handler(message));
|
||||
handlers.forEach((handler: (arg0: { command: string | number }) => any) =>
|
||||
handler(message)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Send a message to the VSCode API
|
||||
sendMessage(message: any) {
|
||||
// console.log(`${JSON.stringify(message)}`);
|
||||
vscodeApi.postMessage(message);
|
||||
if (process.env.platform === "idea") {
|
||||
IdeaBridge.sendMessage(message);
|
||||
} else {
|
||||
this.vscodeApi.postMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
70
src/util/bridge.md
Normal file
70
src/util/bridge.md
Normal file
@ -0,0 +1,70 @@
|
||||
## sendMessage
|
||||
|
||||
- getUserAccessKey // 获取 access key
|
||||
- doCommit // 提交代码
|
||||
- updateSetting // 更新设置(目前只有更换模型)
|
||||
- getSetting // 获取默认模型
|
||||
- deleteChatMessage // 删除最近一条消息
|
||||
- show_diff // 调用 editor 代码对比
|
||||
-- later --
|
||||
- stopDevChat // 停止生成
|
||||
- doCommand //
|
||||
-- content
|
||||
// 1. 打开设置
|
||||
// 2. 启动 ask code 安装
|
||||
// 3. 设置 access key
|
||||
- featureToggles ??
|
||||
- isDevChatInstalled // 判断 ask code 是否安装
|
||||
|
||||
- historyMessages // 页面的历史消息
|
||||
- contextDetail // 获取 appendContext 响应之后,发送次请求获取文件的内容
|
||||
- addContext // 点击 context 菜单(比如 git diff)之后发送到消息
|
||||
- code_file_apply // 代码应用到 editor,替换 current file
|
||||
- code_apply // 代码应用到 editor 光标位置
|
||||
- sendMessage // 发送消息
|
||||
- regeneration // 错误时重新生成
|
||||
- regContextList // git diff 之类的列表
|
||||
- regModelList // model 列表
|
||||
- regCommandList // 输入 / 之后出现的列表
|
||||
|
||||
## registerHandler
|
||||
|
||||
- getUserAccessKey // 获取 access key
|
||||
- regCommandList // 获取 / 之后出现的列表
|
||||
- appendContext // 右键添加到 context 或者 context 菜单点击的响应
|
||||
- contextDetailResponse // 获取到的文件内容
|
||||
- loadHistoryMessages // 与 historyMessages 对应
|
||||
- isDevChatInstalled // 与 isDevChatInstalled 对应
|
||||
- deletedChatMessage // 与 deleteChatMessage 对应
|
||||
- regContextList // 与 regContextList 对应
|
||||
- regModelList // 与 regModelList
|
||||
- receiveMessagePartial // 部分对话
|
||||
- receiveMessage // 对话
|
||||
- systemMessage // 没用了
|
||||
|
||||
# css
|
||||
|
||||
--vscode-editor-font-familyy
|
||||
--vscode-editor-font-size
|
||||
--vscode-dropdown-background
|
||||
--vscode-dropdown-border
|
||||
--vscode-foreground
|
||||
--vscode-sideBar-background
|
||||
--vscode-dropdown-foreground
|
||||
--vscode-menu-foreground
|
||||
--vscode-commandCenter-activeForeground
|
||||
--vscode-commandCenter-activeBackground
|
||||
--vscode-menu-border
|
||||
--vscode-menu-background
|
||||
--vscode-commandCenter-border
|
||||
--vscode-editor-foreground
|
||||
--vscode-input-background
|
||||
--vscode-input-border
|
||||
--vscode-input-foreground
|
||||
--vscode-disabledForeground
|
||||
--vscode-toolbar-activeBackground
|
||||
|
||||
1. 请求 loadHistoryMessages 根据全局 id 返回空/对应的消息
|
||||
1.1. 参数只有分页
|
||||
2. 请求 loadConversations,用于切换全局的 id
|
||||
2.1 loadConversations 的响应里,请求 1
|
487
src/util/ideaBridge.ts
Normal file
487
src/util/ideaBridge.ts
Normal file
@ -0,0 +1,487 @@
|
||||
const JStoIdea = {
|
||||
sendMessage: (message: string, context: any = [], parent: string = "") => {
|
||||
const paramsContext: any = [];
|
||||
if (Array.isArray(context) && context.length > 0) {
|
||||
context.forEach((item) => {
|
||||
paramsContext.push({
|
||||
type: "code",
|
||||
...item.context,
|
||||
});
|
||||
});
|
||||
}
|
||||
const params = {
|
||||
action: "sendMessage/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
parent: parent,
|
||||
},
|
||||
payload: {
|
||||
contexts: paramsContext,
|
||||
message: message,
|
||||
},
|
||||
};
|
||||
console.log("ready to send message: ", params);
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
getModel: () => {
|
||||
const params = {
|
||||
action: "listModels/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
getContextList: () => {
|
||||
const params = {
|
||||
action: "listContexts/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
getCommandList: () => {
|
||||
const params = {
|
||||
action: "listCommands/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
insertCode: (code) => {
|
||||
const params = {
|
||||
action: "insertCode/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
content: code,
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
replaceFileContent: (code) => {
|
||||
const params = {
|
||||
action: "replaceFileContent/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
content: code,
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
viewDiff: (code) => {
|
||||
const params = {
|
||||
action: "viewDiff/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
content: code,
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
getUserAccessKey: () => {
|
||||
// 这里需要发送一个请求,获取完整的用户设置
|
||||
const params = {
|
||||
action: "getSetting/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
etcCommand: (command: any) => {
|
||||
/**
|
||||
* 有四种命令
|
||||
* 1. workbench.action.openSettings
|
||||
* 2. AskCodeIndexStart
|
||||
* 3. AccessKey.OpenAI
|
||||
* 4. AccessKey.DevChat
|
||||
*/
|
||||
const content = Array.isArray(command.content) ? command.content[0] : "";
|
||||
switch (content) {
|
||||
case "workbench.action.openSettings":
|
||||
// 打开设置
|
||||
const params = {
|
||||
action: "showSettingDialog/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
break;
|
||||
case "AccessKey.DevChat":
|
||||
// 设置key
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
getTopicList: () => {
|
||||
// 获取 topic 列表
|
||||
const params = {
|
||||
action: "listTopics/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
updateSetting: (value: string) => {
|
||||
// 因为现在只有更换模型,所以直接取 value
|
||||
const params = {
|
||||
action: "updateSetting/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
setting: {
|
||||
currentModel: value,
|
||||
},
|
||||
},
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
commit: (code: string) => {
|
||||
const params = {
|
||||
action: "commitCode/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
message: code,
|
||||
},
|
||||
};
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
getTopicDetail: (topicHash: string) => {
|
||||
const params = {
|
||||
action: "loadConversations/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
topicHash: topicHash,
|
||||
},
|
||||
payload: {},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
historyMessages: (message) => {
|
||||
const params = {
|
||||
action: "loadHistoryMessages/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
pageIndex: message?.page || 0,
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
deleteChatMessage: (message) => {
|
||||
const params = {
|
||||
action: "deleteLastConversation/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
promptHash: message?.hash || "",
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
openLink: (message) => {
|
||||
if (!message?.url) {
|
||||
return false;
|
||||
}
|
||||
const params = {
|
||||
action: "openLink/request",
|
||||
metadata: {
|
||||
callback: "IdeaToJSMessage",
|
||||
},
|
||||
payload: {
|
||||
url: message?.url || "",
|
||||
},
|
||||
};
|
||||
|
||||
window.JSJavaBridge.callJava(JSON.stringify(params));
|
||||
},
|
||||
};
|
||||
|
||||
class IdeaBridge {
|
||||
private static instance: IdeaBridge;
|
||||
handle: any = {};
|
||||
|
||||
constructor() {
|
||||
this.handle = {};
|
||||
// 注册全局的回调函数,用于接收来自IDEA的消息
|
||||
window.IdeaToJSMessage = (res: any) => {
|
||||
console.log("IdeaToJSMessage: ", res);
|
||||
switch (res.action) {
|
||||
case "deleteLastConversation/response":
|
||||
this.resviceDeleteMessage(res);
|
||||
break;
|
||||
case "loadHistoryMessages/response":
|
||||
this.resviceHistoryMessages(res);
|
||||
break;
|
||||
case "sendMessage/response":
|
||||
this.resviceMessage(res);
|
||||
break;
|
||||
case "listModels/response":
|
||||
this.resviceModelList(res);
|
||||
break;
|
||||
case "listContexts/response":
|
||||
this.resviceContextList(res);
|
||||
break;
|
||||
case "listCommands/response":
|
||||
this.resviceCommandList(res);
|
||||
break;
|
||||
// 这里暂时不用,因为获取到的只有 key,信息不全
|
||||
// 所以用 resviceSettings 来获取
|
||||
// case "getKey/response":
|
||||
// this.resviceAccessKey(res.payload.key);
|
||||
// break;
|
||||
case "addContext/notify":
|
||||
this.resviesContext(res);
|
||||
break;
|
||||
case "getSetting/response":
|
||||
this.resviceSettings(res);
|
||||
break;
|
||||
case "listTopics/response":
|
||||
this.resviceTopicList(res);
|
||||
break;
|
||||
case "loadConversations/response":
|
||||
this.resviceTopicDetail(res);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
resviceDeleteMessage(res) {
|
||||
const hash = res?.payload?.promptHash || "";
|
||||
this.handle.deletedChatMessage({
|
||||
hash,
|
||||
});
|
||||
}
|
||||
|
||||
resviceHistoryMessages(res) {
|
||||
const list: any = [];
|
||||
if (res?.payload?.messages?.length > 0) {
|
||||
res?.payload?.messages.forEach((item) => {
|
||||
list.push({
|
||||
...item,
|
||||
response: item.responses?.join("\n"),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.handle.reloadMessage({
|
||||
entries: list.reverse(),
|
||||
pageIndex: 0,
|
||||
});
|
||||
}
|
||||
|
||||
resviceTopicDetail(res) {
|
||||
// 用于重置后端全局的 topic id
|
||||
if (res?.payload?.reset) {
|
||||
// 重置后请求历史消息
|
||||
JStoIdea.historyMessages({ page: 0 });
|
||||
}
|
||||
}
|
||||
|
||||
resviceTopicList(res) {
|
||||
const list = res.payload.topics;
|
||||
this.handle.listTopics(list);
|
||||
}
|
||||
|
||||
resviesContext(res) {
|
||||
const params = {
|
||||
file: res.payload.path,
|
||||
result: "",
|
||||
};
|
||||
const contextObj = {
|
||||
path: res.payload.path,
|
||||
content: res.payload.content,
|
||||
command: "",
|
||||
};
|
||||
params.result = JSON.stringify(contextObj);
|
||||
this.handle.contextDetailResponse(params);
|
||||
}
|
||||
|
||||
resviceSettings(res) {
|
||||
// 用户设置的回调
|
||||
const setting = res.payload.setting;
|
||||
|
||||
// 当前的默认模型
|
||||
this.handle.getSetting({
|
||||
value: setting.currentModel,
|
||||
});
|
||||
this.handle.getUserAccessKey({
|
||||
endPoint: setting.apiBase,
|
||||
accessKey: setting.apiKey,
|
||||
keyType: setting.apiKey.startsWith("DC") ? "DevChat" : "OpenAi",
|
||||
});
|
||||
}
|
||||
|
||||
resviceAccessKey(res: string = "") {
|
||||
const params = {
|
||||
endPoint: "",
|
||||
accessKey: res,
|
||||
keyType: res.startsWith("DC") ? "DevChat" : "OpenAi",
|
||||
};
|
||||
this.handle.getUserAccessKey(params);
|
||||
}
|
||||
|
||||
resviceCommandList(res) {
|
||||
const result = res.payload.commands.map((item) => ({
|
||||
name: item.name,
|
||||
pattern: item.name,
|
||||
description: item.description,
|
||||
}));
|
||||
this.handle.regCommandList({
|
||||
result,
|
||||
});
|
||||
}
|
||||
|
||||
resviceContextList(res) {
|
||||
// 接受到的上下文列表
|
||||
|
||||
const result = res.payload.contexts.map((item) => ({
|
||||
name: item.command,
|
||||
pattern: item.command,
|
||||
description: item.description,
|
||||
}));
|
||||
|
||||
this.handle.regContextList({ result });
|
||||
}
|
||||
|
||||
resviceModelList(response: any) {
|
||||
// 接受到模型列表
|
||||
this.handle["regModelList"]({
|
||||
result: response.payload.models,
|
||||
});
|
||||
}
|
||||
|
||||
resviceMessage(response: any) {
|
||||
console.log(
|
||||
"response.metadata.isFinalChunk: ",
|
||||
response.metadata.isFinalChunk
|
||||
);
|
||||
// 接受到消息
|
||||
if (response.metadata?.isFinalChunk) {
|
||||
// 结束对话
|
||||
this.handle["receiveMessage"]({
|
||||
text: response.payload?.message || response.metadata?.error || "",
|
||||
isError: response.metadata?.error.length > 0,
|
||||
hash: response.payload?.promptHash || "",
|
||||
});
|
||||
} else {
|
||||
this.handle["receiveMessagePartial"]({
|
||||
text: response?.payload?.message || "",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static getInstance(): IdeaBridge {
|
||||
if (!IdeaBridge.instance) {
|
||||
IdeaBridge.instance = new IdeaBridge();
|
||||
}
|
||||
return IdeaBridge.instance;
|
||||
}
|
||||
|
||||
registerHandler(messageType: string, handler: any) {
|
||||
// 注册回调函数
|
||||
this.handle[messageType] = handler;
|
||||
}
|
||||
|
||||
sendMessage(message: any) {
|
||||
// 根据 command 分发到不同的方法·
|
||||
switch (message.command) {
|
||||
// 发送消息
|
||||
case "sendMessage":
|
||||
JStoIdea.sendMessage(
|
||||
message.text,
|
||||
message.contextInfo,
|
||||
message.parent_hash
|
||||
);
|
||||
break;
|
||||
// 重新生成消息,用于发送失败时再次发送
|
||||
case "regeneration":
|
||||
JStoIdea.sendMessage(message.text, message.context, message.parent);
|
||||
break;
|
||||
// 请求 model 列表
|
||||
case "regModelList":
|
||||
JStoIdea.getModel();
|
||||
break;
|
||||
case "regContextList":
|
||||
JStoIdea.getContextList();
|
||||
break;
|
||||
case "regCommandList":
|
||||
JStoIdea.getCommandList();
|
||||
break;
|
||||
case "code_apply":
|
||||
JStoIdea.insertCode(message.content);
|
||||
break;
|
||||
case "code_file_apply":
|
||||
JStoIdea.replaceFileContent(message.content);
|
||||
break;
|
||||
case "getUserAccessKey":
|
||||
JStoIdea.getUserAccessKey();
|
||||
break;
|
||||
case "doCommand":
|
||||
JStoIdea.etcCommand(message);
|
||||
break;
|
||||
case "show_diff":
|
||||
JStoIdea.viewDiff(message.content);
|
||||
break;
|
||||
case "updateSetting":
|
||||
JStoIdea.updateSetting(message.value);
|
||||
break;
|
||||
case "doCommit":
|
||||
JStoIdea.commit(message.content);
|
||||
break;
|
||||
case "listTopics":
|
||||
JStoIdea.getTopicList();
|
||||
break;
|
||||
case "getTopicDetail":
|
||||
JStoIdea.getTopicDetail(message.topicHash);
|
||||
break;
|
||||
case "historyMessages":
|
||||
JStoIdea.historyMessages(message);
|
||||
break;
|
||||
case "deleteChatMessage":
|
||||
JStoIdea.deleteChatMessage(message);
|
||||
break;
|
||||
case "openLink":
|
||||
JStoIdea.openLink(message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default IdeaBridge.getInstance();
|
12
src/views/App.css
Normal file
12
src/views/App.css
Normal file
@ -0,0 +1,12 @@
|
||||
::-webkit-scrollbar {
|
||||
background-color: transparent;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: grey;
|
||||
border-radius: 6px;
|
||||
}
|
@ -5,6 +5,7 @@ import {
|
||||
} from '@mantine/core';
|
||||
import ChatPanel from '@/views/pages/ChatPanel';
|
||||
import Head from '@/views/components/Header';
|
||||
import './App.css';
|
||||
|
||||
export default function App() {
|
||||
const theme = useMantineTheme();
|
||||
|
@ -42,6 +42,7 @@ export default function WechatTip() {
|
||||
const [accessKey, setAccessKey] = useState("");
|
||||
const [env, setEnv] = useState("prod");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const platform = process.env.platform;
|
||||
|
||||
const getSettings = () => {
|
||||
messageUtil.sendMessage({
|
||||
@ -95,6 +96,15 @@ export default function WechatTip() {
|
||||
);
|
||||
}, []);
|
||||
|
||||
const openLink = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
messageUtil.sendMessage({
|
||||
command: "openLink",
|
||||
url: envMap[env].link,
|
||||
});
|
||||
};
|
||||
|
||||
if (balance === null || balance === undefined) {
|
||||
return null;
|
||||
}
|
||||
@ -105,6 +115,11 @@ export default function WechatTip() {
|
||||
position="left"
|
||||
width="200"
|
||||
withArrow={true}
|
||||
styles={{
|
||||
arrow: {
|
||||
borderColor: "var(--vscode-menu-border)",
|
||||
},
|
||||
}}
|
||||
zIndex={999}
|
||||
>
|
||||
<HoverCard.Target>
|
||||
@ -116,16 +131,25 @@ export default function WechatTip() {
|
||||
</HoverCard.Target>
|
||||
<HoverCard.Dropdown
|
||||
sx={{
|
||||
background: "var(--vscode-dropdown-background)",
|
||||
borderColor: "var(--vscode-dropdown-border)",
|
||||
color: "var(--vscode-foreground)",
|
||||
borderColor: "var(--vscode-menu-border)",
|
||||
backgroundColor: "var(--vscode-menu-background)",
|
||||
}}
|
||||
>
|
||||
<Group style={{ width: "90%" }}>
|
||||
<Text size="sm">
|
||||
Your remaining credit is {formatCurrency(balance, currency)}. Sign
|
||||
in to <a href={envMap[env].link}>web.devchat.ai </a>to{" "}
|
||||
{bindWechat ? "purchase more tokens." : "earn additional ¥8"}
|
||||
in to{" "}
|
||||
{platform === "idea" ? (
|
||||
<Text td="underline" c="blue" onClick={(e) => openLink(e)}>
|
||||
web.devchat.ai{" "}
|
||||
</Text>
|
||||
) : (
|
||||
<a href={envMap[env].link} target="_blank">
|
||||
web.devchat.ai{" "}
|
||||
</a>
|
||||
)}
|
||||
to {bindWechat ? "purchase more tokens." : "earn additional ¥8"}
|
||||
</Text>
|
||||
<LoadingOverlay visible={loading} />
|
||||
</Group>
|
||||
|
111
src/views/components/InputMessage/Topic.tsx
Normal file
111
src/views/components/InputMessage/Topic.tsx
Normal file
@ -0,0 +1,111 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ActionIcon, Drawer, Text, Box, Flex, Divider } from "@mantine/core";
|
||||
import { IconClock, IconChevronDown } from "@tabler/icons-react";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import messageUtil from "@/util/MessageUtil";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
export default function Topic({ styleName }) {
|
||||
const [drawerOpened, { open: openDrawer, close: closeDrawer }] =
|
||||
useDisclosure(false);
|
||||
const [topicList, setTopicList] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
messageUtil.sendMessage({
|
||||
command: "listTopics",
|
||||
});
|
||||
messageUtil.registerHandler("listTopics", (data) => {
|
||||
setTopicList(data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const showTopic = (root_prompt: any) => {
|
||||
closeDrawer();
|
||||
messageUtil.sendMessage({
|
||||
command: "getTopicDetail",
|
||||
topicHash: root_prompt.hash,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Drawer
|
||||
opened={drawerOpened}
|
||||
position="bottom"
|
||||
title="Devchat Topic"
|
||||
onClose={closeDrawer}
|
||||
overlayProps={{ opacity: 0.5, blur: 4 }}
|
||||
closeButtonProps={{ children: <IconChevronDown size="1rem" /> }}
|
||||
styles={{
|
||||
content: {
|
||||
background: "var(--vscode-sideBar-background)",
|
||||
color: "var(--vscode-editor-foreground)",
|
||||
overflowY: "auto",
|
||||
},
|
||||
header: {
|
||||
background: "var(--vscode-sideBar-background)",
|
||||
color: "var(--vscode-editor-foreground)",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{topicList.map((item: any, index) => (
|
||||
<Box
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
}}
|
||||
onClick={() => showTopic(item?.root_prompt)}
|
||||
>
|
||||
<Flex justify="space-between" gap="sm">
|
||||
<Text
|
||||
fz="sm"
|
||||
fw={700}
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{item?.root_prompt.title}
|
||||
</Text>
|
||||
<Text
|
||||
fz="sm"
|
||||
c="dimmed"
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{dayjs(item?.latest_time * 1000).format("MM-DD HH:mm:ss")}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Text
|
||||
c="dimmed"
|
||||
fz="sm"
|
||||
sx={{
|
||||
whiteSpace: "nowrap",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}}
|
||||
>
|
||||
{item?.root_prompt.responses?.[0]}
|
||||
</Text>
|
||||
{index !== topicList.length - 1 && (
|
||||
<Divider variant="solid" my={6} opacity="0.5" />
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</Drawer>
|
||||
<ActionIcon
|
||||
className={styleName}
|
||||
radius="xl"
|
||||
variant="default"
|
||||
onClick={openDrawer}
|
||||
>
|
||||
<IconClock size="1rem" />
|
||||
</ActionIcon>
|
||||
</>
|
||||
);
|
||||
}
|
@ -5,6 +5,7 @@ import React, { useState, useEffect } from "react";
|
||||
import { IconGitBranchChecked, IconShellCommand } from "@/views/components/ChatIcons";
|
||||
import messageUtil from '@/util/MessageUtil';
|
||||
import InputContexts from './InputContexts';
|
||||
import Topic from './Topic';
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useMst } from "@/views/stores/RootStore";
|
||||
import { ChatContext } from "@/views/stores/InputStore";
|
||||
@ -36,6 +37,7 @@ const InputMessage = observer((props: any) => {
|
||||
const { input, chat } = useMst();
|
||||
const { contexts, menuOpend, menuType, currentMenuIndex, contextMenus, commandMenus,modelMenus } = input;
|
||||
const { generating } = chat;
|
||||
const showTopic = process.env.platform === 'idea';
|
||||
|
||||
const [drawerOpened, { open: openDrawer, close: closeDrawer }] = useDisclosure(false);
|
||||
|
||||
@ -388,6 +390,9 @@ const InputMessage = observer((props: any) => {
|
||||
})}
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
{
|
||||
showTopic && <Topic styleName={classes.actionIcon}/>
|
||||
}
|
||||
</Group>
|
||||
{contexts && contexts.length > 0 &&
|
||||
<Drawer
|
||||
|
@ -1,5 +1,13 @@
|
||||
|
||||
import { Stack, Container, Divider, Box, Group,Text, Button, createStyles } from "@mantine/core";
|
||||
import {
|
||||
Stack,
|
||||
Container,
|
||||
Divider,
|
||||
Box,
|
||||
Group,
|
||||
Text,
|
||||
Button,
|
||||
createStyles,
|
||||
} from "@mantine/core";
|
||||
import React, { useEffect } from "react";
|
||||
import MessageBody from "@/views/components/MessageBody";
|
||||
import MessageAvatar from "@/views/components/MessageAvatar";
|
||||
@ -8,96 +16,142 @@ import { useMst } from "@/views/stores/RootStore";
|
||||
import { Message } from "@/views/stores/ChatStore";
|
||||
import MessageContext from "@/views/components/MessageContext";
|
||||
import CurrentMessage from "@/views/components/CurrentMessage";
|
||||
import { Card } from '@mantine/core';
|
||||
import { Card } from "@mantine/core";
|
||||
import { IconInfoSquareRounded } from "@tabler/icons-react";
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
card:{
|
||||
backgroundColor: 'var(--vscode-menu-background)',
|
||||
fontFamily: 'var(--vscode-editor-font-familyy)',
|
||||
fontSize: 'var(--vscode-editor-font-size)',
|
||||
color: 'var(--vscode-menu-foreground)',
|
||||
borderColor: 'var(--vscode-menu-border)',
|
||||
card: {
|
||||
backgroundColor: "var(--vscode-menu-background)",
|
||||
fontFamily: "var(--vscode-editor-font-familyy)",
|
||||
fontSize: "var(--vscode-editor-font-size)",
|
||||
color: "var(--vscode-menu-foreground)",
|
||||
borderColor: "var(--vscode-menu-border)",
|
||||
},
|
||||
cardDescription: {
|
||||
marginTop: 10,
|
||||
marginBottom: 10,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: "#ED6A45",
|
||||
fontFamily: "var(--vscode-editor-font-familyy)",
|
||||
fontSize: "var(--vscode-editor-font-size)",
|
||||
color: "#fff",
|
||||
"&:hover": {
|
||||
backgroundColor: "#ED6A45",
|
||||
opacity: 0.8,
|
||||
},
|
||||
cardDescription:{
|
||||
marginTop: 10,
|
||||
marginBottom: 10,
|
||||
"&:focus": {
|
||||
backgroundColor: "#ED6A45",
|
||||
opacity: 0.8,
|
||||
},
|
||||
button:{
|
||||
backgroundColor:"#ED6A45",
|
||||
fontFamily: 'var(--vscode-editor-font-familyy)',
|
||||
fontSize: 'var(--vscode-editor-font-size)',
|
||||
color:"#fff",
|
||||
"&:hover":{
|
||||
backgroundColor:"#ED6A45",
|
||||
opacity: 0.8,
|
||||
},
|
||||
"&:focus":{
|
||||
backgroundColor:"#ED6A45",
|
||||
opacity: 0.8,
|
||||
}
|
||||
}
|
||||
}));
|
||||
},
|
||||
}));
|
||||
|
||||
const MessageList = observer((props: any) => {
|
||||
const { chat } = useMst();
|
||||
const {classes} = useStyles();
|
||||
const { chat } = useMst();
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (<Stack spacing={0} sx={{margin:'0 10px 10px 10px'}}>
|
||||
{chat.messages.map((item, index: number) => {
|
||||
const { message: messageText, type: messageType, hash: messageHash, contexts, confirm } = item;
|
||||
// setMessage(messageText);
|
||||
return <Stack
|
||||
spacing={0}
|
||||
key={`message-${index}`}
|
||||
sx={{
|
||||
padding: 0,
|
||||
margin: 0
|
||||
}}>
|
||||
<MessageAvatar
|
||||
key={`message-header-${index}`}
|
||||
showDelete={index === chat.messages.length - 2}
|
||||
deleteHash={messageHash}
|
||||
avatarType={messageType}
|
||||
copyMessage={messageText}
|
||||
messageContexts={contexts} />
|
||||
<Box
|
||||
key={`message-container-${index}`}
|
||||
sx={{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
pre: {
|
||||
whiteSpace: 'break-spaces'
|
||||
},
|
||||
}}>
|
||||
{ messageType === 'bot' && confirm && <Card shadow="sm" padding="xs" radius="md" withBorder className={classes.card}>
|
||||
<Card.Section withBorder inheritPadding py="xs">
|
||||
<Group position="left">
|
||||
<IconInfoSquareRounded size={20} />
|
||||
<Text fw={500}>GPT-4 Usage Required</Text>
|
||||
</Group>
|
||||
</Card.Section>
|
||||
<Text className={classes.cardDescription}>
|
||||
DevChat will make GPT-4 API calls to analyze up to ten source files, costing <strong>approximately $0.4 USD per question</strong>.
|
||||
<br/>
|
||||
<br/>
|
||||
Would you like to proceed?
|
||||
</Text>
|
||||
<Group position="right" >
|
||||
<Button size="compact-xs" className={classes.button} onClick={()=> chat.sendLastUserMessage() }>Yes</Button>
|
||||
<Button size="compact-xs" className={classes.button} onClick={()=> chat.cancelDevchatAsk()}>No</Button>
|
||||
</Group>
|
||||
</Card>}
|
||||
<MessageContext key={`message-context-${index}`} contexts={contexts} />
|
||||
<MessageBody key={`message-codeblock-${index}`} messageType={messageType} messageDone={!(index === chat.messages.length -1 && chat.generating)}>
|
||||
{messageText}
|
||||
</MessageBody>
|
||||
</Box >
|
||||
{index !== chat.messages.length - 1 && <Divider my={3} key={`message-divider-${index}`} />}
|
||||
</Stack >;
|
||||
})}
|
||||
<CurrentMessage />
|
||||
</Stack>);
|
||||
return (
|
||||
<Stack spacing={0} sx={{ margin: "0 10px 10px 10px" }}>
|
||||
{chat.messages.map((item, index: number) => {
|
||||
const {
|
||||
message: messageText,
|
||||
type: messageType,
|
||||
hash: messageHash,
|
||||
contexts,
|
||||
confirm,
|
||||
} = item;
|
||||
// setMessage(messageText);
|
||||
return (
|
||||
<Stack
|
||||
spacing={0}
|
||||
key={`message-${index}`}
|
||||
sx={{
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
<MessageAvatar
|
||||
key={`message-header-${index}`}
|
||||
showDelete={index === chat.messages.length - 2}
|
||||
deleteHash={messageHash}
|
||||
avatarType={messageType}
|
||||
copyMessage={messageText}
|
||||
messageContexts={contexts}
|
||||
/>
|
||||
<Box
|
||||
key={`message-container-${index}`}
|
||||
sx={{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
pre: {
|
||||
whiteSpace: "break-spaces",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{messageType === "bot" && confirm && (
|
||||
<Card
|
||||
shadow="sm"
|
||||
padding="xs"
|
||||
radius="md"
|
||||
withBorder
|
||||
className={classes.card}
|
||||
>
|
||||
<Card.Section withBorder inheritPadding py="xs">
|
||||
<Group position="left">
|
||||
<IconInfoSquareRounded size={20} />
|
||||
<Text fw={500}>GPT-4 Usage Required</Text>
|
||||
</Group>
|
||||
</Card.Section>
|
||||
<Text className={classes.cardDescription}>
|
||||
DevChat will make GPT-4 API calls to analyze up to ten
|
||||
source files, costing{" "}
|
||||
<strong>approximately $0.4 USD per question</strong>.
|
||||
<br />
|
||||
<br />
|
||||
Would you like to proceed?
|
||||
</Text>
|
||||
<Group position="right">
|
||||
<Button
|
||||
size="compact-xs"
|
||||
className={classes.button}
|
||||
onClick={() => chat.sendLastUserMessage()}
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
<Button
|
||||
size="compact-xs"
|
||||
className={classes.button}
|
||||
onClick={() => chat.cancelDevchatAsk()}
|
||||
>
|
||||
No
|
||||
</Button>
|
||||
</Group>
|
||||
</Card>
|
||||
)}
|
||||
<MessageContext
|
||||
key={`message-context-${index}`}
|
||||
contexts={contexts}
|
||||
/>
|
||||
<MessageBody
|
||||
key={`message-codeblock-${index}`}
|
||||
messageType={messageType}
|
||||
messageDone={
|
||||
!(index === chat.messages.length - 1 && chat.generating)
|
||||
}
|
||||
>
|
||||
{messageText}
|
||||
</MessageBody>
|
||||
</Box>
|
||||
{index !== chat.messages.length - 1 && (
|
||||
<Divider my={3} key={`message-divider-${index}`} />
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
})}
|
||||
<CurrentMessage />
|
||||
</Stack>
|
||||
);
|
||||
});
|
||||
|
||||
export default MessageList;
|
||||
export default MessageList;
|
||||
|
@ -85,6 +85,9 @@ const chatPanel = observer(() => {
|
||||
getSettings();
|
||||
getFeatureToggles();
|
||||
chat.fetchHistoryMessages({ pageIndex: 0 }).then();
|
||||
messageUtil.registerHandler('reloadMessage',(message:any)=>{
|
||||
chat.reloadMessage(message);
|
||||
});
|
||||
messageUtil.registerHandler(
|
||||
"receiveMessagePartial",
|
||||
(message: { text: string }) => {
|
||||
|
@ -332,6 +332,33 @@ ${yaml.dump(values)}
|
||||
self.isTop = false;
|
||||
self.isBottom = false;
|
||||
},
|
||||
reloadMessage:({entries,pageIndex})=>{
|
||||
if (entries.length > 0) {
|
||||
self.pageIndex = pageIndex;
|
||||
const messages = entries
|
||||
.map((entry, index) => {
|
||||
const { hash, user, date, request, response, context } = entry;
|
||||
const chatContexts = context?.map(({ content }) => {
|
||||
return JSON.parse(content);
|
||||
});
|
||||
return [
|
||||
{ type: 'user', message: request, contexts: chatContexts, date: date, hash: hash },
|
||||
{ type: 'bot', message: response, date: date, hash: hash },
|
||||
];
|
||||
})
|
||||
.flat();
|
||||
if (self.pageIndex === 0) {
|
||||
self.messages = messages;
|
||||
} else if (self.pageIndex > 0) {
|
||||
self.messages.concat(...messages);
|
||||
}
|
||||
} else {
|
||||
self.isLastPage = true;
|
||||
if (self.messages.length === 0) {
|
||||
helpMessage(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
fetchHistoryMessages: flow(function* (params: { pageIndex: number }) {
|
||||
const { pageIndex, entries } = yield fetchHistoryMessages(params);
|
||||
if (entries.length > 0) {
|
||||
|
@ -21,6 +21,6 @@
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"test"
|
||||
"test","gui"
|
||||
]
|
||||
}
|
@ -1,36 +1,37 @@
|
||||
//@ts-check
|
||||
|
||||
'use strict';
|
||||
"use strict";
|
||||
|
||||
const path = require('path');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const { DefinePlugin } = require('webpack');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const { DefinePlugin } = require("webpack");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
|
||||
//@ts-check
|
||||
/** @typedef {import('webpack').Configuration} WebpackConfig **/
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const extensionConfig = {
|
||||
name: 'vscode extension',
|
||||
target: 'node', // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
mode: 'none', // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
name: "vscode extension",
|
||||
target: "node", // VS Code extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/
|
||||
mode: "none", // this leaves the source code as close as possible to the original (when packaging we set this to 'production')
|
||||
|
||||
entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
entry: "./src/extension.ts", // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/
|
||||
|
||||
output: {
|
||||
// the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'extension.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "extension.js",
|
||||
libraryTarget: "commonjs2",
|
||||
},
|
||||
externals: {
|
||||
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
vscode: "commonjs vscode", // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/
|
||||
// modules added here also need to be added in the .vscodeignore file
|
||||
},
|
||||
resolve: {
|
||||
// support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader
|
||||
extensions: ['.ts', '.json']
|
||||
extensions: [".ts", ".json"],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
@ -39,45 +40,47 @@ const extensionConfig = {
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'
|
||||
]
|
||||
}
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
loader: "ts-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
},
|
||||
devtool: 'nosources-source-map',
|
||||
devtool: "nosources-source-map",
|
||||
infrastructureLogging: {
|
||||
level: "log", // enables logging required for problem matchers
|
||||
},
|
||||
plugins: []
|
||||
plugins: [
|
||||
new CleanWebpackPlugin()
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
/** @type WebpackConfig */
|
||||
const webviewConfig = {
|
||||
name: 'webview',
|
||||
target: 'web',
|
||||
mode: 'development',
|
||||
name: "webview",
|
||||
target: "web",
|
||||
mode: "development",
|
||||
|
||||
entry: './src/index.tsx',
|
||||
entry: "./src/index.tsx",
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'index.js',
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "index.js",
|
||||
publicPath: "/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
||||
extensions: [".ts", ".tsx", ".js", ".json"],
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src/')
|
||||
"@": path.resolve(__dirname, "src/"),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
@ -87,89 +90,88 @@ const webviewConfig = {
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'
|
||||
]
|
||||
}
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'ts-loader'
|
||||
}
|
||||
]
|
||||
loader: "ts-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
],
|
||||
]
|
||||
use: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [["@babel/preset-env", "@babel/preset-react"]],
|
||||
},
|
||||
},
|
||||
}]
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
loader: "style-loader",
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: '[name]__[local]___[hash:base64:5]'
|
||||
}
|
||||
}
|
||||
}
|
||||
localIdentName: "[name]__[local]___[hash:base64:5]",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
include: /views/
|
||||
include: /views/,
|
||||
},
|
||||
{
|
||||
test: /\.json$/i,
|
||||
use: 'json-loader',
|
||||
type: 'asset/source'
|
||||
use: "json-loader",
|
||||
type: "asset/source",
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/, // 匹配文件类型
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader', // 使用file-loader
|
||||
loader: "file-loader", // 使用file-loader
|
||||
options: {
|
||||
name: '[name].[ext]', // 输出文件的名称和扩展名
|
||||
outputPath: 'assets/', // 输出文件的路径
|
||||
name: "[name].[ext]", // 输出文件的名称和扩展名
|
||||
outputPath: "assets/", // 输出文件的路径
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
},
|
||||
devtool: 'source-map',
|
||||
devtool: "source-map",
|
||||
infrastructureLogging: {
|
||||
level: "log",
|
||||
},
|
||||
plugins: [
|
||||
// generate an HTML file that includes the extension's JavaScript file
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, 'src', 'index.html'),
|
||||
filename: 'index.html',
|
||||
chunks: ['index']
|
||||
template: path.resolve(__dirname, "src", "index.html"),
|
||||
filename: "index.html",
|
||||
chunks: ["index"],
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, 'src', 'welcome.html'),
|
||||
filename: 'welcome.html',
|
||||
chunks: ['welcome']
|
||||
template: path.resolve(__dirname, "src", "welcome.html"),
|
||||
filename: "welcome.html",
|
||||
chunks: ["welcome"],
|
||||
}),
|
||||
]
|
||||
new DefinePlugin({
|
||||
"process.env.platform": JSON.stringify("vscode"),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
module.exports = [extensionConfig, webviewConfig];
|
||||
module.exports = extensionConfig;
|
||||
|
105
webpack.idea.config.js
Normal file
105
webpack.idea.config.js
Normal file
@ -0,0 +1,105 @@
|
||||
//@ts-check
|
||||
"use strict";
|
||||
|
||||
const path = require("path");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const webviewConfig = {
|
||||
name: "webview",
|
||||
target: "web",
|
||||
mode: "production",
|
||||
entry: "./src/index.tsx",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "main.js",
|
||||
publicPath: "/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".tsx", ".js", ".json"],
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "src/"),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript",
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: "ts-loader",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: [["@babel/preset-env", "@babel/preset-react"]],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
{
|
||||
loader: "style-loader",
|
||||
},
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
modules: {
|
||||
localIdentName: "[name]__[local]___[hash:base64:5]",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
include: /views/,
|
||||
},
|
||||
{
|
||||
test: /\.json$/i,
|
||||
use: "json-loader",
|
||||
type: "asset/source",
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|jpeg|gif|svg)$/, // 匹配文件类型
|
||||
type: "asset/inline",
|
||||
},
|
||||
],
|
||||
},
|
||||
devtool: false,
|
||||
infrastructureLogging: {
|
||||
level: "log",
|
||||
},
|
||||
plugins: [
|
||||
// generate an HTML file that includes the extension's JavaScript file
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, "src", "main.html"),
|
||||
filename: "main.html",
|
||||
chunks: ["main"],
|
||||
}),
|
||||
new CleanWebpackPlugin(),
|
||||
new webpack.ProgressPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.platform": JSON.stringify("idea"),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = webviewConfig;
|
Loading…
x
Reference in New Issue
Block a user