Files
devstar_plugin/src/home.ts

421 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as vscode from 'vscode';
import * as os from 'os';
import * as path from 'path';
import RemoteContainer from './remote-container';
import User from './user';
import * as utils from './utils'
export default class DSHome {
private context: vscode.ExtensionContext;
private remoteContainer: RemoteContainer;
private user: User;
private devstarDomain: string | undefined;
/**
* 配置项提供devstarDomain
* @param context
* @param user
*/
constructor(context: vscode.ExtensionContext, user: User)
/**
* open with vscode链接提供devstarDomain
* @param context
* @param user
* @param devstarDomain
*/
constructor(context: vscode.ExtensionContext, user: User, devstarDomain: string)
constructor(context: vscode.ExtensionContext, user: User, devstarDomain?: string) {
this.context = context;
this.user = user;
this.remoteContainer = new RemoteContainer(user);
if (devstarDomain != undefined && devstarDomain != "") {
this.devstarDomain = devstarDomain.endsWith('/') ? devstarDomain.slice(0, -1) : devstarDomain;
} else {
const devstarDomainFromConfig = utils.devstarDomain();
if (devstarDomainFromConfig != undefined && devstarDomainFromConfig != "") {
this.devstarDomain = devstarDomainFromConfig.endsWith('/') ? devstarDomainFromConfig.slice(0, -1) : devstarDomainFromConfig;
} else {
this.devstarDomain = "https://devstar.cn";
}
}
}
setUser(user: User) {
this.user = user;
}
setRemoteContainer(remoteContainer: RemoteContainer) {
this.remoteContainer = remoteContainer;
}
setDevstarDomainAndHomePageURL(devstarDomain: string) {
if (devstarDomain != undefined && devstarDomain != "") {
this.devstarDomain = devstarDomain.endsWith('/') ? devstarDomain.slice(0, -1) : devstarDomain;
} else {
console.error("devstarDomain is undefined or null");
}
}
async toggle() {
const panel = vscode.window.createWebviewPanel(
'homeWebview',
vscode.l10n.t('Home'),
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [
vscode.Uri.file(path.join(this.context.extensionPath, 'assets'))
]
}
);
panel.webview.html = await this.getWebviewContent(panel);
panel.webview.onDidReceiveMessage(
async (message) => {
const data = message.data;
const need_return = message.need_return;
if (need_return) {
// ================= need return ====================
switch (message.command) {
// ----------------- frequent -----------------------
case 'getHomeConfig':
const config = {
language: vscode.env.language
};
panel.webview.postMessage({ command: 'getHomeConfig', data: { homeConfig: config } });
break;
case 'getUserToken':
const userToken = this.user.getUserTokenFromLocal();
if (userToken === undefined) {
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: '' } });
} else {
panel.webview.postMessage({ command: 'getUserToken', data: { userToken: userToken } });
}
break;
case 'getUsername':
const username = this.user.getUsernameFromLocal();
if (username === undefined) {
panel.webview.postMessage({ command: 'getUsername', data: { username: '' } });
} else {
panel.webview.postMessage({ command: 'getUsername', data: { username: username } });
}
break;
case 'firstOpenRemoteFolder':
// data.host - project name
await this.remoteContainer.firstOpenProject(data.host, data.hostname, data.port, data.username, data.path, this.context);
break;
case 'openRemoteFolder':
this.remoteContainer.openRemoteFolder(data.host, data.port, data.username, data.path);
break;
case 'getDevstarDomain':
panel.webview.postMessage({ command: 'getDevstarDomain', data: { devstarDomain: this.devstarDomain } });
break;
// ----------------- not frequent -----------------------
case 'setUserToken':
this.user.setUserTokenToLocal(data.userToken);
if (data.userToken === this.user.getUserTokenFromLocal()) {
panel.webview.postMessage({ command: 'setUserToken', data: { ok: true } });
} else {
panel.webview.postMessage({ command: 'setUserToken', data: { ok: false } });
}
break;
case 'setUsername':
this.user.setUsernameToLocal(data.username);
if (data.username === this.user.getUsernameFromLocal()) {
panel.webview.postMessage({ command: 'setUsername', data: { ok: true } });
} else {
panel.webview.postMessage({ command: 'setUsername', data: { ok: false } });
}
break;
case 'getUserPublicKey':
let userPublicKey = '';
if (this.user.existUserPrivateKey()) {
userPublicKey = this.user.getUserPublicKey();
}
panel.webview.postMessage({ command: 'getUserPublicKey', data: { userPublicKey: userPublicKey } });
break;
case 'createUserPublicKey':
await this.user.createUserSSHKey();
if (this.user.existUserPublicKey()) {
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: true } });
} else {
panel.webview.postMessage({ command: 'createUserPublicKey', data: { ok: false } });
}
break;
case 'getMachineName':
const machineName = os.hostname();
panel.webview.postMessage({ command: 'getMachineName', data: { machineName: machineName } });
break;
}
} else {
// ================= don't need return ==============
// frequent
switch (message.command) {
// ----------------- frequent -----------------------
case 'showInformationNotification':
vscode.window.showInformationMessage(data.message);
break;
case 'showWarningNotification':
vscode.window.showWarningMessage(data.message);
break;
case 'showErrorNotification':
await utils.showErrorNotification(data.message);
break;
case 'openExternalUrl':
// 修复:直接从 message 中获取 url而不是从 data
const url = message.url || (data && data.url);
if (url) {
try {
await vscode.env.openExternal(vscode.Uri.parse(url));
vscode.window.showInformationMessage(`已在浏览器中打开: ${url}`);
} catch (error) {
vscode.window.showErrorMessage(`打开链接失败: ${url}`);
console.error('打开外部链接失败:', error);
}
} else {
console.error('openExternalUrl: url is undefined', message);
vscode.window.showErrorMessage('打开链接失败: 链接地址无效');
}
break;
}
}
},
undefined,
this.context.subscriptions
);
this.context.subscriptions.push(panel);
}
async getWebviewContent(panel?: vscode.WebviewPanel): Promise<string> {
// 获取图片的 Webview URI
let logoUri = '';
if (panel) {
const logoPath = vscode.Uri.file(
path.join(this.context.extensionPath, 'assets', 'images', 'logo.png')
);
logoUri = panel.webview.asWebviewUri(logoPath).toString();
}
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DevStar Home</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: var(--vscode-font-family);
background-color: var(--vscode-editor-background);
color: var(--vscode-editor-foreground);
}
.header {
text-align: center;
margin-bottom: 30px;
}
.logo {
width: auto;
height: 30px;
margin-bottom: 16px;
}
.feature-list {
list-style: none;
padding: 0;
}
.feature-item {
padding: 10px;
margin: 10px 0;
background-color: var(--vscode-button-background);
border-radius: 4px;
cursor: pointer;
text-align: center;
}
.feature-item:hover {
background-color: var(--vscode-button-hoverBackground);
}
.login-status {
padding: 10px;
margin: 10px 0;
border-radius: 4px;
text-align: center;
}
.logged-in {
background-color: var(--vscode-inputValidation-infoBackground);
border: 1px solid var(--vscode-inputValidation-infoBorder);
}
.logged-out {
background-color: var(--vscode-inputValidation-warningBackground);
border: 1px solid var(--vscode-inputValidation-warningBorder);
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="header">
${logoUri ? `<img src="${logoUri}" alt="DevStar Logo" class="logo">` : '🚀'}
<p>欢迎使用 DevStar 扩展</p>
</div>
<!-- 登录状态显示 -->
<div id="loginStatus" class="login-status hidden">
<span id="statusText"></span>
<span id="usernameDisplay"></span>
</div>
<ul class="feature-list">
<li class="feature-item" onclick="handleMainAction()" id="mainActionButton">
主要功能
</li>
</ul>
<script>
const vscode = acquireVsCodeApi();
let isLoggedIn = false;
let username = '';
function vscodePostMessage(command, data) {
vscode.postMessage({
command: command,
need_return: false,
data: data
});
}
async function communicateVSCode(command, data) {
return new Promise((resolve, reject) => {
vscode.postMessage({ command: command, need_return: true, data: data });
function handleResponse(event) {
const jsonData = event.data;
if (jsonData.command === command) {
window.removeEventListener('message', handleResponse);
resolve(jsonData.data);
}
}
window.addEventListener('message', handleResponse);
setTimeout(() => {
window.removeEventListener('message', handleResponse);
reject('timeout');
}, 5000);
});
}
// 检查登录状态
async function checkLoginStatus() {
try {
const userTokenResult = await communicateVSCode('getUserToken', {});
const usernameResult = await communicateVSCode('getUsername', {});
const userToken = userTokenResult.userToken;
username = usernameResult.username;
isLoggedIn = !!(userToken && userToken.trim() !== '' && username && username.trim() !== '');
updateUI();
} catch (error) {
console.error('检查登录状态失败:', error);
isLoggedIn = false;
updateUI();
}
}
// 更新UI显示
function updateUI() {
const loginStatus = document.getElementById('loginStatus');
const statusText = document.getElementById('statusText');
const usernameDisplay = document.getElementById('usernameDisplay');
const mainActionButton = document.getElementById('mainActionButton');
loginStatus.classList.remove('hidden');
if (isLoggedIn) {
loginStatus.classList.remove('logged-out');
loginStatus.classList.add('logged-in');
statusText.textContent = '已登录';
usernameDisplay.textContent = username ? ' - 用户: ' + username : '';
mainActionButton.textContent = '跳转到个人主页';
} else {
loginStatus.classList.remove('logged-in');
loginStatus.classList.add('logged-out');
statusText.textContent = '未登录';
usernameDisplay.textContent = '';
mainActionButton.textContent = '跳转到 DevStar 官网';
}
}
// 处理主要功能点击 - 修复消息发送格式
function handleMainAction() {
if (isLoggedIn) {
// 已登录:跳转到 hostname/username
// 使用 async 函数处理异步操作
(async () => {
try {
// 获取必要的用户信息
const devstarDomainResult = await communicateVSCode('getDevstarDomain', {});
const usernameResult = await communicateVSCode('getUsername', {});
const devstarDomain = devstarDomainResult.devstarDomain;
const username = usernameResult.username;
if (devstarDomain && username) {
const targetUrl = \`\${devstarDomain}/\${username}\`;
vscodePostMessage('showInformationNotification', {
message: \`跳转到 \${targetUrl}\`
});
vscode.postMessage({
command: 'openExternalUrl',
need_return: false,
url: targetUrl
});
} else {
vscodePostMessage('showErrorNotification', {
message: '无法获取域名或用户名信息'
});
}
} catch (error) {
console.error('跳转失败:', error);
vscodePostMessage('showErrorNotification', {
message: '跳转失败,请重试'
});
}
})();
} else {
// 未登录:跳转到 DevStar 官网
vscodePostMessage('showInformationNotification', {message: '跳转到 DevStar 官网'});
vscode.postMessage({
command: 'openExternalUrl',
need_return: false,
url: 'https://devstar.cn'
});
}
}
// 页面加载时检查登录状态
window.addEventListener('load', async () => {
await checkLoginStatus();
});
// 可选:添加重新检查登录状态的功能
function refreshLoginStatus() {
checkLoginStatus();
vscodePostMessage('showInformationNotification', {message: '登录状态已刷新'});
}
</script>
</body>
</html>`;
}
}