916 lines
28 KiB
HTML
916 lines
28 KiB
HTML
<?php
|
|
header("Access-Control-Allow-Origin: *");
|
|
header("Access-Control-Allow-Headers: X-API-KEY, Origin, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method");
|
|
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
|
|
header("Allow: GET, POST, OPTIONS, PUT, DELETE");
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Embedded page</title>
|
|
<link rel="stylesheet" href="web_src/css/themes/theme-gitea-auto.css">
|
|
<style>
|
|
/* 弹窗基本样式 */
|
|
.modal {
|
|
display: none;
|
|
/* 默认隐藏 */
|
|
position: fixed;
|
|
/* 固定定位 */
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
/* 全屏宽 */
|
|
height: 100%;
|
|
/* 全屏高 */
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
/* 半透明黑色背景 */
|
|
z-index: 1;
|
|
/* 确保在顶部 */
|
|
}
|
|
|
|
/* 弹窗内容框样式 */
|
|
.modal-content {
|
|
background-color: #fefefe;
|
|
margin: 15% auto;
|
|
/* 15% 从顶部开始,自动水平居中 */
|
|
padding: 20px;
|
|
border: 1px solid #888;
|
|
width: 30%;
|
|
/* 弹窗宽度 */
|
|
}
|
|
|
|
/* 关闭按钮样式 */
|
|
.close {
|
|
color: #aaa;
|
|
float: right;
|
|
font-size: 28px;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.close:hover,
|
|
.close:focus {
|
|
color: black;
|
|
text-decoration: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.alert {
|
|
position: fixed;
|
|
top: 20px;
|
|
/* 距离顶部20px */
|
|
left: 50%;
|
|
/* 水平居中 */
|
|
transform: translateX(-50%);
|
|
/* 水平居中调整 */
|
|
background-color: green;
|
|
color: white;
|
|
text-align: center;
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
display: none;
|
|
z-index: 2;
|
|
width: auto;
|
|
/* 自动宽度 */
|
|
max-width: 60%;
|
|
/* 最大宽度60% */
|
|
}
|
|
|
|
/* table样式 */
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
border: 1px solid black;
|
|
padding: 8px;
|
|
text-align: left;
|
|
}
|
|
|
|
.required::before {
|
|
content: "*";
|
|
color: red;
|
|
}
|
|
|
|
form {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
label,
|
|
input,
|
|
textarea {
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
input,
|
|
textarea {
|
|
padding: 8px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.button-container {
|
|
display: flex;
|
|
/* justify-content: space-between; */
|
|
}
|
|
|
|
ton {
|
|
width: 100px;
|
|
height: 30px;
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
button:hover {
|
|
background-color: #45a049;
|
|
}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
<h1>DevStar Home</h1>
|
|
<!-- login -->
|
|
<div id="loginModal" class="modal">
|
|
<div class="modal-content">
|
|
<span class="close" onclick="closeLoginModal()">×</span>
|
|
<div>
|
|
<h2>Login</h2>
|
|
<form id="loginForm">
|
|
<label for="username">Username:</label>
|
|
<input type="text" id="username" name="username" required><br><br>
|
|
<label for="password">Password:</label>
|
|
<input type="password" id="password" name="password" required><br><br>
|
|
<button type="button" onclick="login()">Login</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button onclick="openLoginModal()">Login</button>
|
|
<button onclick="logout()">Logout</button>
|
|
<!-- create new project -->
|
|
<!-- 触发弹窗的按钮 -->
|
|
<button onclick="openModal()">Create New Project</button>
|
|
<!-- 弹窗本体 -->
|
|
<div id="myModal" class="modal">
|
|
<div class="modal-content">
|
|
<span class="close" onclick="closeModal()">×</span>
|
|
<h2>Create New Project</h2>
|
|
<form>
|
|
<!-- project settings -->
|
|
<label class="required" for="projectName">Name</label>
|
|
<input type="text" id="projectName" name="projectName"><br><br>
|
|
<label for="projectDesc">Description</label>
|
|
<textarea id="projectDesc" name="projectDesc" placeholder="(Optional)"></textarea><br><br>
|
|
<label for="repoURL">Repo URL</label>
|
|
<input type="text" id="repoURL" name="repoURL"
|
|
placeholder="(Optional) Project repository you want to clone"><br><br>
|
|
<hr>
|
|
<!-- repo settings-->
|
|
<label for="template">
|
|
As template?
|
|
<input type="checkbox" id="template">
|
|
</label>
|
|
|
|
<button type="button" onclick="submitRepo()">Create</button>
|
|
</form>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="alertBox" class="alert"></div>
|
|
|
|
<!-- ====================== Created Repository ==========================-->
|
|
<h2>Created Repositories</h2>
|
|
<button onclick="loadRepositories()">Load Repositories</button>
|
|
<table id="reposTable">
|
|
<thead>
|
|
<tr>
|
|
<th>repoName</th>
|
|
<th>repoURL</th>
|
|
<th>Operation</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- 动态加载 -->
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- ====================== open created project ==========================-->
|
|
<!-- <h2>Created Project</h2>
|
|
<button onclick="loadProjects()">Load Projects</button>
|
|
<table id="projectsTable">
|
|
<thead>
|
|
<tr>
|
|
<th>devContainerName</th>
|
|
<th>devContainerWorkDir</th>
|
|
<th>Operation</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table> -->
|
|
|
|
<!-- ======================================= Script ==================================-->`
|
|
<script>
|
|
// ===================================== Initialization ===========================
|
|
// Global variables
|
|
DEVSTAR_HOME = "https://devstar.cn"
|
|
var USERTOKEN = null
|
|
var USERNAME = null
|
|
var REPOLIST = []
|
|
var PROJECTLIST = []
|
|
|
|
window.onload = async function () {
|
|
await getUserTokenFromVSCode()
|
|
.then(async userToken => {
|
|
// verify user token
|
|
await verifyToken(userToken)
|
|
.then(result => {
|
|
// initialize user token
|
|
USERTOKEN = userToken
|
|
})
|
|
.catch(error => {
|
|
console.error('Error in verifying token:', error)
|
|
})
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to get user token from vscode: ", error)
|
|
})
|
|
|
|
await getUsernameFromVSCode()
|
|
.then(async username => {
|
|
USERNAME = username
|
|
})
|
|
.catch(error => {
|
|
console.error('Failed to get user name from vscode: ', error)
|
|
})
|
|
|
|
if (USERTOKEN && USERNAME) {
|
|
loadPageModules()
|
|
} else {
|
|
// TODO : do nothing or remind user to login
|
|
}
|
|
}
|
|
|
|
function loadPageModules() {
|
|
loadRepositories()
|
|
// loadProjects()
|
|
}
|
|
|
|
async function getUserTokenFromVSCode() {
|
|
return new Promise(async (resolve, reject) => {
|
|
await communicateVSCodeByWebview('getUserToken', null)
|
|
.then(async data => {
|
|
const userToken = data.userToken
|
|
|
|
if (userToken === undefined) {
|
|
reject("userToken is undefined")
|
|
}
|
|
resolve(userToken)
|
|
})
|
|
.catch(error => {
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
async function getUsernameFromVSCode() {
|
|
return new Promise(async (resolve, reject) => {
|
|
await communicateVSCodeByWebview('getUsername', null)
|
|
.then(async data => {
|
|
const username = data.username
|
|
if (username === undefined) {
|
|
reject('username is undefined')
|
|
}
|
|
|
|
resolve(username)
|
|
})
|
|
.catch(error => {
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
function verifyToken(token) {
|
|
return new Promise((resolve, reject) => {
|
|
fetch(DEVSTAR_HOME + '/api/devcontainer/user', {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
})
|
|
.then(response => {
|
|
if (response.ok) {
|
|
resolve(response.status)
|
|
} else {
|
|
reject(new Error("Error code", response.status))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
// ===================================== login and logout ===========================
|
|
// login model
|
|
function openLoginModal() {
|
|
// check if user has logged in, only show login modal when user has not logged in
|
|
if (USERTOKEN) {
|
|
verifyToken(USERTOKEN)
|
|
.then(result => {
|
|
console.log('User has logged in')
|
|
showAlert('已登录', 3000) // 消息显示3秒后消失
|
|
return
|
|
})
|
|
.catch(error => {
|
|
// need to login
|
|
document.getElementById('loginModal').style.display = 'block';
|
|
})
|
|
} else {
|
|
document.getElementById('loginModal').style.display = 'block';
|
|
}
|
|
}
|
|
|
|
function closeLoginModal() {
|
|
document.getElementById('loginModal').style.display = 'none';
|
|
}
|
|
|
|
async function login() {
|
|
var username = document.getElementById('username').value;
|
|
var password = document.getElementById('password').value;
|
|
const url = DEVSTAR_HOME + `/api/v1/users/${username}/tokens`;
|
|
|
|
// Base64编码用户名和密码
|
|
const base64Credentials = btoa(username + ':' + password);
|
|
|
|
const tokenName = generateTokenName(10);
|
|
postData = {
|
|
"name": tokenName,
|
|
"scopes": ["write:user", "write:repository"]
|
|
}
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'Basic ' + base64Credentials
|
|
},
|
|
body: JSON.stringify(postData)
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Error in logging ' + response.statusText);
|
|
closeLoginModal()
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(async data => {
|
|
// store token in global variable and vscode global state
|
|
USERTOKEN = data.sha1;
|
|
USERNAME = username;
|
|
setUserTokenToVSCode(USERTOKEN);
|
|
setUsernameToVSCode(username);
|
|
loadPageModules()
|
|
|
|
// if user public key exist, meaning that public key has been uploaded
|
|
await getUserPublicKeyFromVSCode()
|
|
.then(async userPublicKey => {
|
|
if (userPublicKey == '') {
|
|
await createUserPublicKeyByVSCode()
|
|
.then(async () => {
|
|
// only upload new created public key
|
|
await getUserPublicKeyFromVSCode()
|
|
.then(async userPublicKey => {
|
|
const dataFromResp = await communicateVSCodeByWebview('getMachineName', {});
|
|
const machineName = dataFromResp.machineName;
|
|
|
|
const keyTitle = `${USERNAME}-${machineName}`
|
|
await uploadNewCreatedPublicKey(userPublicKey, keyTitle);
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to get NEW CREATED user public key from vscode: ", error)
|
|
})
|
|
})
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error("Failed to get user public key from vscode: ", error)
|
|
})
|
|
|
|
closeLoginModal()
|
|
})
|
|
.catch(error => {
|
|
closeLoginModal()
|
|
console.error('There has been a problem when logging', error);
|
|
});
|
|
}
|
|
|
|
function generateTokenName(length = 10) {
|
|
// tokenName is random string and number and _ combination (10 characters)
|
|
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';
|
|
let name = '';
|
|
const charactersLength = characters.length;
|
|
for (let i = 0; i < length; i++) {
|
|
name += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
}
|
|
return name
|
|
}
|
|
|
|
async function logout() {
|
|
// remove token and username from global variable and vscode global state
|
|
USERTOKEN = null
|
|
USERNAME = null
|
|
await setUserTokenToVSCode('')
|
|
await setUsernameToVSCode('')
|
|
|
|
location.reload()
|
|
}
|
|
|
|
async function setUserTokenToVSCode(userToken) {
|
|
var removeUserToken = false;
|
|
if (userToken == '') {
|
|
removeUserToken = true
|
|
}
|
|
|
|
communicateVSCodeByWebview('setUserToken', { userToken: userToken })
|
|
.then(result => {
|
|
if (result.ok) {
|
|
console.log(removeUserToken ? 'User token has been removed from vscode' : 'User token has been stored in vscode')
|
|
} else {
|
|
console.error(removeUserToken ? 'Failed to remove user token from vscode' : 'Failed to store user token into vscode')
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Failed to set user token into vscode:', error)
|
|
})
|
|
}
|
|
|
|
async function setUsernameToVSCode(username) {
|
|
var removeUsername = false;
|
|
if (username == '') {
|
|
removeUsername = true;
|
|
}
|
|
|
|
await communicateVSCodeByWebview('setUsername', { username: username })
|
|
.then(result => {
|
|
if (result.ok) {
|
|
console.log(removeUsername ? 'User name has been removed from vscode' : 'User name has been stored in vscode')
|
|
} else {
|
|
console.error(removeUsername ? 'Failed to removing user name from vscode' : 'Failed to store user name in vscode')
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error("Error happened when setting user name: ", error)
|
|
})
|
|
}
|
|
|
|
async function getUserPublicKeyFromVSCode() {
|
|
return new Promise(async (resolve, reject) => {
|
|
await communicateVSCodeByWebview('getUserPublicKey', {})
|
|
.then(data => {
|
|
const publicKey = data.userPublicKey;
|
|
resolve(publicKey)
|
|
})
|
|
.catch(error => {
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
async function createUserPublicKeyByVSCode() {
|
|
await communicateVSCodeByWebview('createUserPublicKey', {})
|
|
.then(res => {
|
|
if (res.ok) {
|
|
console.log('User public key has been created')
|
|
} else {
|
|
console.error('Failed to create user public key')
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Failed to request to create user public key: ', erro)
|
|
})
|
|
}
|
|
|
|
async function uploadNewCreatedPublicKey(userPublicKey, keyTitle) {
|
|
const postData = {
|
|
"key": userPublicKey,
|
|
"title": keyTitle
|
|
}
|
|
|
|
const uploadUrl = DEVSTAR_HOME + `/api/v1/user/keys`;
|
|
|
|
fetch(uploadUrl, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + USERTOKEN
|
|
},
|
|
body: JSON.stringify(postData)
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Error in logging ' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(async data => {
|
|
console.log("Successfully upload new created public key.\n", data)
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
});
|
|
}
|
|
|
|
// ===================================== Repo ===========================
|
|
function loadRepositories() {
|
|
// clear old data
|
|
const tableBody = document.getElementById('reposTable').getElementsByTagName('tbody')[0];
|
|
tableBody.innerHTML = '';
|
|
|
|
// load new data
|
|
var url = DEVSTAR_HOME + "/api/v1/user/repos?page=1&limit=20"
|
|
var token = USERTOKEN
|
|
fetch(url, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok when loading repos' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
var repos = data;
|
|
repos.forEach((repo, index) => {
|
|
var row = tableBody.insertRow(-1); // 在表格末尾插入一行
|
|
var cell1 = row.insertCell(0);
|
|
var cell2 = row.insertCell(1);
|
|
var cell3 = row.insertCell(2);
|
|
|
|
const repoFullName = repo.full_name;
|
|
const repoURL = repo.html_url;
|
|
const repoID = repo.id;
|
|
|
|
cell1.textContent = repoFullName;
|
|
cell2.textContent = repoURL;
|
|
cell3.innerHTML = `<button onclick="openProject('${repoID}')">Open Project</button>
|
|
<button onclick="deleteDevContainer('${repoID}')">Delete Project</button>
|
|
`;
|
|
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
});
|
|
}
|
|
|
|
// 打开弹窗
|
|
function openModal() {
|
|
// make sure login first
|
|
if (!USERTOKEN || !USERNAME) {
|
|
showAlert('请先登录!', 3000)
|
|
return
|
|
}
|
|
document.getElementById('myModal').style.display = "block";
|
|
}
|
|
// 关闭弹窗
|
|
function closeModal() {
|
|
document.getElementById('myModal').style.display = "none";
|
|
}
|
|
// 点击窗外关闭弹窗
|
|
window.onclick = function (event) {
|
|
if (event.target == document.getElementById('myModal')) {
|
|
closeModal();
|
|
}
|
|
}
|
|
|
|
function submitRepo() {
|
|
// 这里添加实际的表单提交逻辑
|
|
// 模拟表单处理
|
|
var projectName = document.getElementById('projectName').value;
|
|
var projectDesc = document.getElementById('projectDesc').value;
|
|
var projectTemplate = document.getElementById('template').checked;
|
|
|
|
// check required fields
|
|
if (projectName == '') {
|
|
showAlert('请填写必要的项目信息!', 3000) // 消息显示3秒后消失
|
|
} else {
|
|
}
|
|
|
|
const url = DEVSTAR_HOME + "/api/v1/user/repos"
|
|
var token = USERTOKEN
|
|
|
|
const postData = {
|
|
"name": projectName,
|
|
"description": projectDesc,
|
|
"template": projectTemplate,
|
|
}
|
|
|
|
fetch(url, {
|
|
method: 'POST', // 或者 'POST', 根据API要求
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
body: JSON.stringify(postData)
|
|
})
|
|
.then(response => {
|
|
console.log(response)
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok when creating project' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
console.log(data);
|
|
showAlert('项目创建成功!', 1500) // 消息显示1.5秒后消失
|
|
loadRepositories()
|
|
closeModal(); // 关闭创建项目弹窗
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
});
|
|
}
|
|
|
|
// ===================================== Projects ===========================
|
|
|
|
async function openProject(repoId) {
|
|
var newCreated = false;
|
|
// check if container exist
|
|
await hasDevContainer(repoId)
|
|
.then(async hasDevContainer => {
|
|
if (!hasDevContainer) {
|
|
showAlert("正在创建开发容器...", 1500)
|
|
await createDevContainer(repoId)
|
|
.then(res => {
|
|
newCreated = true;
|
|
showAlert("创建容器成功!", 1500)
|
|
console.log(`Succeed to create dev container for repo ${repoId}`)
|
|
})
|
|
.catch(error => {
|
|
showAlert("创建容器失败!", 1500)
|
|
console.log(`Fail to create dev container for repo ${repoId}: `, error)
|
|
return;
|
|
})
|
|
}
|
|
}).catch(error => {
|
|
console.log("There has a problem when check if the repo has devContainer:", error)
|
|
return;
|
|
})
|
|
|
|
console.log("opening project")
|
|
|
|
// open devcontainer through repoId
|
|
var url = DEVSTAR_HOME + "/api/devcontainer"
|
|
var token = USERTOKEN
|
|
|
|
const queryParams = new URLSearchParams({
|
|
repoId: repoId,
|
|
wait: true
|
|
}).toString();
|
|
const urlWithParams = `${url}?${queryParams}`;
|
|
|
|
fetch(urlWithParams, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok when querying devContainer by repoId' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
const responseCode = data.code
|
|
const reponseMsg = data.msg
|
|
|
|
if (responseCode == 0) {
|
|
// container start successfully
|
|
// get devContainer ssh connection information
|
|
const devContainerHost = data.data.devContainerHost
|
|
const devContainerUsername = data.data.devContainerUsername
|
|
const devContainerPort = data.data.devContainerPort
|
|
const devContainerWorkDir = data.data.devContainerWorkDir
|
|
|
|
// default: open with key
|
|
communicateVSCodeByWebview('firstOpenRemoteFolder', { host: `${devContainerHost}`, username: `${devContainerUsername}`, port: `${devContainerPort}`, path: `${devContainerWorkDir}` })
|
|
} else {
|
|
// show Error to User
|
|
showAlert("打开容器失败!", 1500)
|
|
const responseErrorMsg = data.data.ErrorMsg
|
|
console.error("Error happen when starting dev container", responseErrorMsg)
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
});
|
|
}
|
|
|
|
async function hasDevContainer(repoId) {
|
|
return new Promise((resolve, reject) => {
|
|
url = DEVSTAR_HOME + "/api/devcontainer/user"
|
|
token = USERTOKEN
|
|
|
|
fetch(url, {
|
|
method: 'GET', // 或者 'POST', 根据API要求
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok when querying devContainer list' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
const devContainers = data.data.devContainers;
|
|
devContainers.forEach((c, index) => {
|
|
if (c.repoId == repoId) {
|
|
// has devContainer
|
|
resolve(true)
|
|
return
|
|
}
|
|
});
|
|
resolve(false)
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
reject(error)
|
|
});
|
|
})
|
|
}
|
|
|
|
async function createDevContainer(repoId) {
|
|
return new Promise(async (resolve, reject) => {
|
|
// request creating container
|
|
const url = DEVSTAR_HOME + "/api/devcontainer"
|
|
var token = USERTOKEN
|
|
|
|
const postData = {
|
|
"repoId": repoId.toString(),
|
|
// "sshPublicKeyList": [publicKey]
|
|
}
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
body: JSON.stringify(postData)
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error(`Network response was not ok when creating devContainer ${repoId}` + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
const responseCode = data.code
|
|
|
|
if (responseCode == 0) {
|
|
resolve("success")
|
|
} else {
|
|
reject(data.data.ErrorMsg)
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('There has been a problem with your fetch operation:', error);
|
|
reject(error)
|
|
});
|
|
|
|
})
|
|
}
|
|
|
|
async function getDefaultPublicKeyFromVSCode() {
|
|
try {
|
|
const data = await communicateVSCodeByWebview('getDefaultPublicKey', null);
|
|
const defaultPublicKey = data.defaultPublicKey;
|
|
|
|
return defaultPublicKey;
|
|
} catch (error) {
|
|
console.log("Failed to get default public key: ", error)
|
|
}
|
|
}
|
|
|
|
function deleteDevContainer(repoId) {
|
|
var url = DEVSTAR_HOME + "/api/devcontainer"
|
|
var token = USERTOKEN
|
|
|
|
const queryParams = new URLSearchParams({
|
|
repoId: repoId,
|
|
}).toString();
|
|
const urlWithParams = `${url}?${queryParams}`;
|
|
|
|
fetch(urlWithParams, {
|
|
method: 'DELETE',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': 'token ' + token
|
|
},
|
|
})
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok when DELETEING devContainer by repoId' + response.statusText);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
const respCode = data.code;
|
|
if (0 == respCode) {
|
|
console.log('Successfully delete dev container belong to repoId:', repoId, data)
|
|
showAlert("删除容器成功!", 1500)
|
|
} else {
|
|
const errorMsg = data.data.ErrorMsg
|
|
throw new Error(errorMsg)
|
|
}
|
|
})
|
|
.catch(error => {
|
|
showAlert(`删除容器失败\n${error}`, 3000)
|
|
console.error(`Failed to delete dev container belong to repoId: ${repoId}\n`, error)
|
|
})
|
|
}
|
|
|
|
function firstOpenRemoteFolder(host, username, password, port, path) {
|
|
const message = {
|
|
action: 'firstOpenRemoteFolder',
|
|
host: host,
|
|
username: username,
|
|
password: password,
|
|
port: port,
|
|
path: path,
|
|
}
|
|
// 向iframe父页面发送消息
|
|
window.parent.postMessage(message, '*');
|
|
}
|
|
|
|
function openRemoteFolder(host, path) {
|
|
const message = {
|
|
action: 'openRemoteFolder',
|
|
host: host,
|
|
path: path,
|
|
}
|
|
// 向iframe父页面发送消息
|
|
window.parent.postMessage(message, '*');
|
|
}
|
|
|
|
// ===================================== Utils ===========================
|
|
|
|
// 消息提示
|
|
function showAlert(alertText, duration) {
|
|
document.getElementById('alertBox').innerHTML = alertText;
|
|
document.getElementById('alertBox').style.display = 'block';
|
|
setTimeout(function () {
|
|
document.getElementById('alertBox').style.display = 'none';
|
|
}, duration); // 消息显示 duration/1000 秒后消失
|
|
}
|
|
|
|
async function communicateVSCodeByWebview(action, data) {
|
|
return new Promise((resolve, reject) => {
|
|
// request to webview
|
|
window.parent.postMessage({ target: "vscode", action: action, data: data }, '*');
|
|
|
|
// response from webview
|
|
function handleResponse(event) {
|
|
const jsonData = event.data
|
|
if (jsonData.action === action) {
|
|
// return webview response
|
|
console.log("dataFromVSCodeByWebview", jsonData.data)
|
|
|
|
window.removeEventListener('message', handleResponse) // 清理监听器
|
|
resolve(jsonData.data)
|
|
}
|
|
}
|
|
|
|
window.addEventListener('message', handleResponse)
|
|
|
|
setTimeout(() => {
|
|
window.removeEventListener('message', handleResponse)
|
|
reject('timeout')
|
|
}, 5000); // 5秒超时
|
|
|
|
})
|
|
}
|
|
|
|
|
|
</script>
|
|
</body>
|
|
|
|
</html> |