0
0
Files
vs-p/out/panels/views/ProjectView.js
2025-12-05 21:15:33 +08:00

501 lines
18 KiB
JavaScript
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.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectView = void 0;
const BaseView_1 = require("./BaseView");
class ProjectView extends BaseView_1.BaseView {
render(data) {
const projects = data?.projects || [];
const projectPaths = data?.projectPaths || new Map();
const projectsHtml = projects.map((project) => {
const isConfigured = projectPaths.has(project.id);
const statusIcon = isConfigured ? '✅' : '⚙️';
const statusText = isConfigured ? '已配置' : '待配置';
return `
<tr>
<td>
<span class="project-name" data-project-id="${project.id}">${statusIcon} ${project.name}</span>
<div style="font-size: 12px; color: var(--vscode-descriptionForeground); margin-top: 4px;">
${statusText}${isConfigured ? ` - ${projectPaths.get(project.id)}` : ''}
</div>
</td>
<td>
<span class="clickable" onclick="configureProject('${project.id}', '${project.name}', ${isConfigured})">
${isConfigured ? '打开' : '配置'}
</span>
</td>
<td>
${isConfigured ? `<button class="btn-upload" onclick="uploadProject('${project.id}', '${project.name}')" style="margin-right: 5px;">上传</button>` : ''}
<button class="btn-delete" onclick="deleteProject('${project.id}')">删除</button>
</td>
</tr>
`;
}).join('');
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数字卫星构建平台</title>
${this.getStyles()}
${this.getRepoSelectScript()}
<style>
.satellite-icon {
font-size: 2.5em;
vertical-align: middle;
margin-right: 10px;
line-height: 1;
display: inline-block;
position: relative;
top: -5px;
}
.header-title {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 20px;
}
.project-name {
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
transition: background-color 0.2s;
}
.project-name:hover {
background: var(--vscode-input-background);
}
.table-actions {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 20px;
}
.btn-action {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
display: flex;
align-items: center;
gap: 6px;
}
.btn-action:hover {
background: var(--vscode-button-hoverBackground);
}
/* 统一“主要操作按钮”的样式 */
.btn-new {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
display: flex;
align-items: center;
gap: 6px;
}
.btn-new:hover {
background: var(--vscode-button-hoverBackground);
}
.btn-open {
background: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
}
/* 仓库 & 分支树公共样式 */
.config-section {
margin-top: 30px;
margin-bottom: 30px;
}
.section-title {
margin: 30px 0 15px 0;
padding-bottom: 10px;
border-bottom: 2px solid var(--vscode-panel-border);
color: var(--vscode-titleBar-activeForeground);
}
.url-input-section {
background: var(--vscode-panel-background);
padding: 15px;
border-radius: 4px;
margin-bottom: 15px;
border: 1px solid var(--vscode-input-border);
}
.branch-selection {
border: 1px solid var(--vscode-input-border);
}
.branch-tree {
font-family: 'Courier New', monospace;
user-select: none;
margin: 0;
padding: 0;
}
.branch-node {
padding: 2px 0;
display: flex;
align-items: center;
cursor: pointer;
line-height: 1.2;
}
.branch-node:hover {
background: var(--vscode-list-hoverBackground);
}
.branch-icon {
margin-right: 4px;
font-size: 16px;
width: 16px;
text-align: center;
}
.branch-expand {
margin-right: 2px;
cursor: pointer;
width: 14px;
text-align: center;
}
.branch-checkbox {
margin-right: 6px;
}
.branch-name {
flex: 1;
font-size: 13px;
}
.branch-children {
margin-left: 16px;
border-left: 1px solid var(--vscode-panel-border);
padding-left: 8px;
}
.branch-leaf {
margin-left: 16px;
}
.current-branch {
color: var(--vscode-gitDecoration-untrackedResourceForeground);
font-weight: bold;
}
.tree-icon {
font-size: 2em;
}
.branch-tree-title {
font-size: 1.2em;
}
</style>
</head>
<body>
<div class="header">
<h2><span class="satellite-icon">🛰️</span>数字卫星构建平台</h2>
<button class="back-btn" onclick="openRepoConfig()">⚙️ 仓库配置</button>
</div>
<table class="table">
<thead>
<tr>
<th width="40%">项目</th>
<th width="40%">配置</th>
<th width="20%">操作</th>
</tr>
</thead>
<tbody>
${projectsHtml}
<tr>
<td colspan="3" style="padding: 20px;">
<div class="table-actions">
<button class="btn-action btn-open" onclick="openExistingProject()">
<span style="font-size: 14px;">📂</span> 打开项目
</button>
<button class="btn-action btn-new" onclick="createNewProject()">
<span style="font-size: 14px;">+</span> 新建项目
</button>
</div>
</td>
</tr>
</tbody>
</table>
<div class="config-section">
<h3 class="section-title">📚 项目云仓库</h3>
<div class="url-input-section">
<h4>🔗 获取项目仓库</h4>
<div style="display: flex; gap: 10px; margin-top: 10px; align-items: center;">
<button class="btn-new" onclick="openRepoSelectForProject()">获取仓库</button>
<span style="font-size: 12px; color: var(--vscode-descriptionForeground);">
从仓库配置中选择 Git 仓库,选择分支后可将完整项目克隆到本地(包含 dscp-data.json
</span>
</div>
<div id="branchSelectionContainer"></div>
</div>
</div>
<script>
const vscode = acquireVsCodeApi();
function openRepoConfig() {
vscode.postMessage({
type: 'openRepoConfig'
});
}
function configureProject(projectId, projectName, isConfigured) {
if (isConfigured) {
vscode.postMessage({
type: 'openProject',
projectId: projectId
});
} else {
vscode.postMessage({
type: 'configureProject',
projectId: projectId,
projectName: projectName
});
}
}
function openExistingProject() {
vscode.postMessage({
type: 'openExistingProject'
});
}
function createNewProject() {
showPromptDialog(
'新建项目',
'请输入项目名称:',
'',
function(name) {
if (name) {
vscode.postMessage({
type: 'createProject',
name: name
});
}
}
);
}
function deleteProject(projectId) {
showConfirmDialog(
'确认删除',
'确定删除这个项目吗?',
function() {
vscode.postMessage({
type: 'deleteProject',
projectId: projectId
});
},
function() {
// 用户取消删除
}
);
}
// 新增上传功能
function uploadProject(projectId, projectName) {
showConfirmDialog(
'上传项目仓库',
'确定将此项目目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForProjectUpload',
projectId: projectId
});
}
);
}
// 项目名称编辑功能
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('click', function(event) {
if (event.target.classList.contains('project-name')) {
const projectNameElement = event.target;
const projectId = projectNameElement.getAttribute('data-project-id');
const currentName = projectNameElement.textContent.trim().split(' ').slice(1).join(' ');
if (projectId) {
editProjectName(projectId, currentName);
}
}
});
});
function editProjectName(projectId, currentName) {
showPromptDialog(
'修改项目名称',
'请输入新的项目名称:',
currentName,
function(newName) {
if (newName && newName !== currentName) {
vscode.postMessage({
type: 'updateProjectName',
projectId: projectId,
name: newName
});
}
}
);
}
// ======== Git 仓库 & 分支树 - ProjectView 作用域 ========
let selectedBranches = new Set();
let branchTreeData = [];
function openRepoSelectForProject() {
vscode.postMessage({
type: 'openRepoSelectForProject'
});
}
function toggleBranch(branchName) {
const checkbox = document.getElementById('branch-' + branchName.replace(/[^a-zA-Z0-9-]/g, '-'));
if (checkbox && checkbox.checked) {
selectedBranches.add(branchName);
} else {
selectedBranches.delete(branchName);
}
}
function cloneSelectedBranches() {
if (selectedBranches.size === 0) {
alert('请至少选择一个分支');
return;
}
vscode.postMessage({
type: 'cloneBranches',
branches: Array.from(selectedBranches)
});
selectedBranches.clear();
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = false);
document.getElementById('branchSelectionContainer').innerHTML = '';
}
function cancelBranchSelection() {
selectedBranches.clear();
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = false);
document.getElementById('branchSelectionContainer').innerHTML = '';
vscode.postMessage({
type: 'cancelBranchSelection'
});
}
function toggleBranchNode(nodeId) {
const node = findNodeById(branchTreeData, nodeId);
if (node && !node.isLeaf) {
node.expanded = !node.expanded;
renderBranchTree(branchTreeData);
}
}
function expandAllBranches() {
setAllExpanded(branchTreeData, true);
renderBranchTree(branchTreeData);
}
function collapseAllBranches() {
setAllExpanded(branchTreeData, false);
renderBranchTree(branchTreeData);
}
function setAllExpanded(nodes, expanded) {
nodes.forEach(node => {
if (!node.isLeaf) {
node.expanded = expanded;
if (node.children) {
setAllExpanded(node.children, expanded);
}
}
});
}
function findNodeById(nodes, nodeId) {
for (const node of nodes) {
if (node.fullName === nodeId) return node;
if (node.children) {
const found = findNodeById(node.children, nodeId);
if (found) return found;
}
}
return null;
}
function renderBranchTree(treeData) {
const container = document.getElementById('branchSelectionContainer');
if (!treeData || treeData.length === 0) {
container.innerHTML = '<div style="text-align: center; padding: 10px; color: var(--vscode-descriptionForeground);">未找到分支</div>';
return;
}
let html = '<div class="branch-selection" style="margin: 10px 0; padding: 10px; background: var(--vscode-panel-background); border-radius: 4px;">';
html += '<h4 class="branch-tree-title" style="margin: 0 0 8px 0;"><span class="tree-icon">🌳</span> 分支树</h4>';
html += '<div style="margin-bottom: 8px;">';
html += '<button class="back-btn" onclick="expandAllBranches()" style="margin-right: 8px; padding: 2px 6px; font-size: 11px;">展开全部</button>';
html += '<button class="back-btn" onclick="collapseAllBranches()" style="padding: 2px 6px; font-size: 11px;">收起全部</button>';
html += '</div>';
html += '<div class="branch-tree">';
html += renderBranchNodes(treeData, 0);
html += '</div>';
html += '<div style="margin-top: 12px;">';
html += '<button class="btn-new" onclick="cloneSelectedBranches()" style="margin-right: 8px; padding: 4px 8px; font-size: 12px;">✅ 克隆选中分支</button>';
html += '<button class="back-btn" onclick="cancelBranchSelection()" style="padding: 4px 8px; font-size: 12px;">取消</button>';
html += '</div></div>';
container.innerHTML = html;
}
function renderBranchNodes(nodes, level) {
let html = '';
nodes.forEach(node => {
const indent = level * 20;
const nodeId = node.fullName.replace(/[^a-zA-Z0-9-]/g, '-');
if (node.isLeaf) {
html += '<div class="branch-node branch-leaf" style="margin-left: ' + indent + 'px;">';
html += '<input type="checkbox" id="branch-' + nodeId + '" class="branch-checkbox" ';
html += (node.branch && node.branch.selected ? 'checked' : '') + ' onchange="toggleBranch(\\'' + node.fullName + '\\')">';
html += '<span class="branch-icon">🌿</span>';
html += '<span class="branch-name ' + (node.branch && node.branch.isCurrent ? 'current-branch' : '') + '">';
html += node.name;
html += (node.branch && node.branch.isCurrent ? ' ⭐' : '');
html += '</span>';
html += '</div>';
} else {
html += '<div class="branch-node" style="margin-left: ' + indent + 'px;">';
html += '<span class="branch-expand" onclick="toggleBranchNode(\\'' + node.fullName + '\\')">';
html += (node.expanded ? '🪵' : '🪵');
html += '</span>';
html += '<span class="branch-icon">🪵</span>';
html += '<span class="branch-name">' + node.name + '</span>';
html += '</div>';
if (node.expanded && node.children && node.children.length > 0) {
html += '<div class="branch-children">';
html += renderBranchNodes(node.children, level + 1);
html += '</div>';
}
}
});
return html;
}
window.addEventListener('message', event => {
const message = event.data;
if (message.type === 'branchesFetched') {
branchTreeData = message.branchTree || [];
renderBranchTree(branchTreeData);
}
});
</script>
</body>
</html>`;
}
}
exports.ProjectView = ProjectView;
//# sourceMappingURL=ProjectView.js.map