0
0

修复了保存的绝对路径问题

This commit is contained in:
xubing
2025-11-27 22:04:32 +08:00
parent 2970f64587
commit 17e9dc1451
13 changed files with 911 additions and 984 deletions

View File

@@ -55,16 +55,15 @@ class ConfigPanel {
this.currentProjectId = ''; this.currentProjectId = '';
this.currentAircraftId = ''; this.currentAircraftId = '';
this.currentContainerId = ''; this.currentContainerId = '';
this.currentRepoId = ''; this.currentModuleFolderId = '';
// 数据存储 // 数据存储
this.projects = []; this.projects = [];
this.aircrafts = []; this.aircrafts = [];
this.containers = []; this.containers = [];
this.configs = []; this.configs = [];
this.gitRepos = []; // Git 仓库数据 this.moduleFolders = []; // 统一的模块文件夹数据
this.mergedFolders = [];
// Git 文件树 // Git 文件树
this.currentRepoFileTree = []; this.currentModuleFolderFileTree = [];
// 项目存储路径映射 // 项目存储路径映射
this.projectPaths = new Map(); this.projectPaths = new Map();
// Webview 状态跟踪 // Webview 状态跟踪
@@ -129,7 +128,7 @@ class ConfigPanel {
this.currentProjectId = ''; this.currentProjectId = '';
this.currentAircraftId = ''; this.currentAircraftId = '';
this.currentContainerId = ''; this.currentContainerId = '';
this.currentRepoId = ''; this.currentModuleFolderId = '';
this.updateWebview(); this.updateWebview();
break; break;
case 'goBackToAircrafts': case 'goBackToAircrafts':
@@ -194,20 +193,20 @@ class ConfigPanel {
console.log('❌ 取消分支选择'); console.log('❌ 取消分支选择');
this.updateWebview(); this.updateWebview();
break; break;
case 'loadGitRepo': case 'loadModuleFolder':
await this.loadGitRepo(data.repoId); await this.loadModuleFolder(data.folderId);
break; break;
case 'syncGitRepo': case 'syncGitModuleFolder':
await this.syncGitRepo(data.repoId); await this.syncGitModuleFolder(data.folderId);
break; break;
case 'deleteGitRepo': case 'deleteModuleFolder':
await this.deleteGitRepo(data.repoId); await this.deleteModuleFolder(data.folderId);
break; break;
case 'importGitFile': case 'importGitFile':
await this.importGitFile(data.filePath); await this.importGitFile(data.filePath);
break; break;
case 'openGitRepoInVSCode': case 'openModuleFolderInVSCode':
await this.openTheModuleFolder('git', data.repoId); await this.openTheModuleFolder(data.moduleType, data.folderId);
break; break;
case 'openConfigFileInVSCode': case 'openConfigFileInVSCode':
await this.openConfigFileInVSCode(data.configId); await this.openConfigFileInVSCode(data.configId);
@@ -216,7 +215,7 @@ class ConfigPanel {
await this.mergeConfigs(data.configIds, data.displayName, data.folderName); await this.mergeConfigs(data.configIds, data.displayName, data.folderName);
break; break;
case 'deleteMergedFolder': case 'deleteMergedFolder':
await this.deleteMergedFolder(data.folderId); await this.deleteModuleFolder(data.folderId);
break; break;
case 'openMergedFolderInVSCode': case 'openMergedFolderInVSCode':
await this.openTheModuleFolder('merged', data.folderId); await this.openTheModuleFolder('merged', data.folderId);
@@ -316,9 +315,9 @@ class ConfigPanel {
} }
// === Git 仓库管理方法 === // === Git 仓库管理方法 ===
/** /**
* 添加 Git 仓库到容器目录 * 添加 Git 模块文件夹到容器目录
*/ */
async addGitRepo(url, name, branch) { async addGitModuleFolder(url, name, branch) {
try { try {
// 验证 URL // 验证 URL
if (!url || !url.startsWith('http')) { if (!url || !url.startsWith('http')) {
@@ -329,8 +328,8 @@ class ConfigPanel {
vscode.window.showErrorMessage('请先选择容器'); vscode.window.showErrorMessage('请先选择容器');
return; return;
} }
const repoId = 'git-' + Date.now(); const folderId = 'git-' + Date.now();
// 构建本地路径 - 在容器目录下创建分支子目录 // 构建本地路径
const container = this.containers.find(c => c.id === this.currentContainerId); const container = this.containers.find(c => c.id === this.currentContainerId);
if (!container) { if (!container) {
vscode.window.showErrorMessage('未找到容器'); vscode.window.showErrorMessage('未找到容器');
@@ -346,33 +345,30 @@ class ConfigPanel {
vscode.window.showErrorMessage('未找到项目路径'); vscode.window.showErrorMessage('未找到项目路径');
return; return;
} }
// 为每个分支创建独立的子目录 // 构建相对路径(从项目路径开始)
const branchName = branch || 'main'; const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${name}`;
const branchSafeName = branchName.replace(/[^a-zA-Z0-9-_]/g, '-'); // 完整路径用于实际操作
const repoDirName = name; const localPath = path.join(projectPath, aircraft.name, container.name, name);
// 路径:项目路径/飞行器名/容器名/仓库名-分支名/ console.log(`📁 Git模块文件夹将保存到: ${localPath}`);
const localPath = path.join(projectPath, aircraft.name, container.name, repoDirName); console.log(`📁 相对路径: ${relativePath}`);
console.log(`📁 Git仓库将保存到: ${localPath}`); // 检查是否已存在相同名称的模块文件夹
// 检查是否已存在相同 URL 和分支的仓库 const existingFolder = this.moduleFolders.find(folder => folder.name === name && folder.containerId === this.currentContainerId);
const existingRepo = this.gitRepos.find(repo => repo.url === url && repo.branch === branchName && repo.containerId === this.currentContainerId); if (existingFolder) {
if (existingRepo) { vscode.window.showWarningMessage('该名称的模块文件夹已存在');
vscode.window.showWarningMessage('该 Git 仓库和分支组合已存在');
return; return;
} }
const newRepo = { const newFolder = {
id: repoId, id: folderId,
name: `${name} (${branchName})`, name: name,
url: url, type: 'git',
localPath: localPath, localPath: relativePath,
branch: branchName,
lastSync: new Date().toLocaleString(),
containerId: this.currentContainerId containerId: this.currentContainerId
}; };
console.log(`📁 准备克隆仓库: ${name}, 分支: ${newRepo.branch}, 路径: ${localPath}`); console.log(`📁 准备克隆仓库: ${name}, 分支: ${branch}, 路径: ${localPath}`);
// 显示进度 // 显示进度
await vscode.window.withProgress({ await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
title: `正在克隆仓库: ${name} (${newRepo.branch})`, title: `正在克隆仓库: ${name}`,
cancellable: false cancellable: false
}, async (progress) => { }, async (progress) => {
progress.report({ increment: 0 }); progress.report({ increment: 0 });
@@ -403,7 +399,7 @@ class ConfigPanel {
url: url, url: url,
singleBranch: true, singleBranch: true,
depth: 1, depth: 1,
ref: branchName, ref: branch || 'main',
onProgress: (event) => { onProgress: (event) => {
if (event.total) { if (event.total) {
const percent = (event.loaded / event.total) * 100; const percent = (event.loaded / event.total) * 100;
@@ -412,17 +408,17 @@ class ConfigPanel {
} }
}); });
console.log('✅ Git克隆成功完成'); console.log('✅ Git克隆成功完成');
this.gitRepos.push(newRepo); this.moduleFolders.push(newFolder);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
console.log('✅ Git仓库数据已保存到项目文件'); console.log('✅ Git模块文件夹数据已保存到项目文件');
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name} (${newRepo.branch})`); vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name}`);
// 检查 Webview 状态后再加载文件树 // 检查 Webview 状态后再加载文件树
if (!this.isWebviewDisposed) { if (!this.isWebviewDisposed) {
console.log('🌳 开始加载仓库文件树...'); console.log('🌳 开始加载模块文件夹文件树...');
// 自动加载仓库文件树 // 自动加载文件树
this.currentRepoId = repoId; this.currentModuleFolderId = folderId;
await this.loadGitRepoFileTree(repoId); await this.loadModuleFolderFileTree(folderId);
console.log('✅ 仓库文件树加载完成'); console.log('✅ 模块文件夹文件树加载完成');
} }
else { else {
console.log('⚠️ Webview 已被销毁,跳过文件树加载'); console.log('⚠️ Webview 已被销毁,跳过文件树加载');
@@ -435,30 +431,39 @@ class ConfigPanel {
}); });
} }
catch (error) { catch (error) {
console.error('❌ 在addGitRepo外部捕获错误:', error); console.error('❌ 在addGitModuleFolder外部捕获错误:', error);
vscode.window.showErrorMessage(`添加 Git 仓库失败: ${error}`); vscode.window.showErrorMessage(`添加 Git 模块文件夹失败: ${error}`);
} }
} }
/** /**
* 加载 Git 仓库文件 * 加载模块文件
*/ */
async loadGitRepo(repoId) { async loadModuleFolder(folderId) {
this.currentRepoId = repoId; this.currentModuleFolderId = folderId;
await this.loadGitRepoFileTree(repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (folder && folder.type === 'git') {
await this.loadModuleFolderFileTree(folderId);
}
this.updateWebview(); this.updateWebview();
} }
/** /**
* 同步 Git 仓库 * 同步 Git 模块文件夹
*/ */
async syncGitRepo(repoId) { async syncGitModuleFolder(folderId) {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) { if (!folder || folder.type !== 'git') {
vscode.window.showErrorMessage('未找到指定的 Git 仓库'); vscode.window.showErrorMessage('未找到指定的 Git 模块文件夹');
return;
}
// 获取完整路径
const fullPath = this.getModuleFolderFullPath(folder);
if (!fullPath) {
vscode.window.showErrorMessage('无法获取模块文件夹的完整路径');
return; return;
} }
await vscode.window.withProgress({ await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
title: `正在同步仓库: ${repo.name}`, title: `正在同步仓库: ${folder.name}`,
cancellable: false cancellable: false
}, async (progress) => { }, async (progress) => {
try { try {
@@ -467,16 +472,13 @@ class ConfigPanel {
await isomorphic_git_1.default.pull({ await isomorphic_git_1.default.pull({
fs: fs, fs: fs,
http: node_1.default, http: node_1.default,
dir: repo.localPath, dir: fullPath,
author: { name: 'DCSP User', email: 'user@dcsp.local' }, author: { name: 'DCSP User', email: 'user@dcsp.local' },
fastForward: true fastForward: true
}); });
// 更新最后同步时间
repo.lastSync = new Date().toLocaleString();
await this.saveCurrentProjectData();
// 重新加载文件树 // 重新加载文件树
await this.loadGitRepoFileTree(repoId); await this.loadModuleFolderFileTree(folderId);
vscode.window.showInformationMessage(`Git 仓库同步成功: ${repo.name}`); vscode.window.showInformationMessage(`Git 仓库同步成功: ${folder.name}`);
this.updateWebview(); this.updateWebview();
} }
catch (error) { catch (error) {
@@ -485,49 +487,52 @@ class ConfigPanel {
}); });
} }
/** /**
* 删除 Git 仓库 * 删除模块文件夹
*/ */
async deleteGitRepo(repoId) { async deleteModuleFolder(folderId) {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) if (!folder)
return; return;
const confirm = await vscode.window.showWarningMessage(`确定要删除 Git 仓库 "${repo.name}" 吗?这将删除本地文件。`, { modal: true }, '确定删除', '取消'); const confirm = await vscode.window.showWarningMessage(`确定要删除模块文件夹 "${folder.name}" 吗?这将删除本地文件。`, { modal: true }, '确定删除', '取消');
if (confirm === '确定删除') { if (confirm === '确定删除') {
try { try {
// 删除整个仓库目录(因为是独立目录) // 获取完整路径并删除文件夹
await fs.promises.rm(repo.localPath, { recursive: true, force: true }); const fullPath = this.getModuleFolderFullPath(folder);
// 从列表中移除 if (fullPath) {
this.gitRepos = this.gitRepos.filter(r => r.id !== repoId); await fs.promises.rm(fullPath, { recursive: true, force: true });
await this.saveCurrentProjectData();
// 如果删除的是当前仓库,清空状态
if (this.currentRepoId === repoId) {
this.currentRepoId = '';
this.currentRepoFileTree = [];
} }
vscode.window.showInformationMessage(`Git 仓库已删除: ${repo.name}`); // 从列表中移除
this.moduleFolders = this.moduleFolders.filter(f => f.id !== folderId);
await this.saveCurrentProjectData();
// 如果删除的是当前文件夹,清空状态
if (this.currentModuleFolderId === folderId) {
this.currentModuleFolderId = '';
this.currentModuleFolderFileTree = [];
}
vscode.window.showInformationMessage(`模块文件夹已删除: ${folder.name}`);
this.updateWebview(); this.updateWebview();
} }
catch (error) { catch (error) {
vscode.window.showErrorMessage(`删除 Git 仓库失败: ${error}`); vscode.window.showErrorMessage(`删除模块文件夹失败: ${error}`);
} }
} }
} }
/** /**
* 加载 Git 仓库文件树 * 加载模块文件夹文件树
*/ */
async loadGitRepoFileTree(repoId) { async loadModuleFolderFileTree(folderId) {
// 检查 Webview 是否仍然有效 // 检查 Webview 是否仍然有效
if (this.isWebviewDisposed) { if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,跳过文件树加载'); console.log('⚠️ Webview 已被销毁,跳过文件树加载');
return; return;
} }
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) if (!folder)
return; return;
// 通知前端开始加载 // 通知前端开始加载
try { try {
this.panel.webview.postMessage({ this.panel.webview.postMessage({
type: 'gitRepoLoading', type: 'moduleFolderLoading',
loading: true loading: true
}); });
} }
@@ -536,15 +541,15 @@ class ConfigPanel {
return; return;
} }
try { try {
const fileTree = await this.buildFileTree(repo.localPath); const fullPath = this.getModuleFolderFullPath(folder);
this.currentRepoFileTree = fileTree; if (fullPath) {
// 更新最后访问时间 const fileTree = await this.buildFileTree(fullPath);
repo.lastSync = new Date().toLocaleString(); this.currentModuleFolderFileTree = fileTree;
await this.saveCurrentProjectData(); }
} }
catch (error) { catch (error) {
console.error('加载仓库文件树失败:', error); console.error('加载模块文件夹文件树失败:', error);
this.currentRepoFileTree = []; this.currentModuleFolderFileTree = [];
} }
// 再次检查 Webview 状态 // 再次检查 Webview 状态
if (this.isWebviewDisposed) { if (this.isWebviewDisposed) {
@@ -554,7 +559,7 @@ class ConfigPanel {
// 通知前端加载完成 // 通知前端加载完成
try { try {
this.panel.webview.postMessage({ this.panel.webview.postMessage({
type: 'gitRepoLoading', type: 'moduleFolderLoading',
loading: false loading: false
}); });
this.updateWebview(); this.updateWebview();
@@ -607,13 +612,13 @@ class ConfigPanel {
* 导入 Git 文件到当前容器 * 导入 Git 文件到当前容器
*/ */
async importGitFile(filePath) { async importGitFile(filePath) {
if (!this.currentRepoId || !this.currentContainerId) { if (!this.currentModuleFolderId || !this.currentContainerId) {
vscode.window.showErrorMessage('请先选择 Git 仓库和容器'); vscode.window.showErrorMessage('请先选择模块文件夹和容器');
return; return;
} }
const repo = this.gitRepos.find(r => r.id === this.currentRepoId); const folder = this.moduleFolders.find(f => f.id === this.currentModuleFolderId);
if (!repo) { if (!folder || folder.type !== 'git') {
vscode.window.showErrorMessage('未找到当前 Git 仓库'); vscode.window.showErrorMessage('未找到当前 Git 模块文件夹');
return; return;
} }
const container = this.containers.find(c => c.id === this.currentContainerId); const container = this.containers.find(c => c.id === this.currentContainerId);
@@ -622,8 +627,13 @@ class ConfigPanel {
return; return;
} }
try { try {
const fullPath = path.join(repo.localPath, filePath); const fullPath = this.getModuleFolderFullPath(folder);
const content = await fs.promises.readFile(fullPath, 'utf8'); if (!fullPath) {
vscode.window.showErrorMessage('无法获取模块文件夹路径');
return;
}
const fileFullPath = path.join(fullPath, filePath);
const content = await fs.promises.readFile(fileFullPath, 'utf8');
const fileName = path.basename(filePath); const fileName = path.basename(filePath);
// 创建新配置 // 创建新配置
const newId = 'cfg' + (this.configs.length + 1); const newId = 'cfg' + (this.configs.length + 1);
@@ -685,20 +695,18 @@ class ConfigPanel {
const currentProjectContainers = this.containers.filter(c => currentAircraftIds.includes(c.aircraftId)); const currentProjectContainers = this.containers.filter(c => currentAircraftIds.includes(c.aircraftId));
const currentContainerIds = currentProjectContainers.map(c => c.id); const currentContainerIds = currentProjectContainers.map(c => c.id);
const currentProjectConfigs = this.configs.filter(cfg => currentContainerIds.includes(cfg.containerId)); const currentProjectConfigs = this.configs.filter(cfg => currentContainerIds.includes(cfg.containerId));
// 只保存与当前项目容器相关的 Git 仓库和合并文件夹 // 只保存与当前项目容器相关的模块文件夹
const currentProjectGitRepos = this.gitRepos.filter(repo => currentContainerIds.includes(repo.containerId)); const currentProjectModuleFolders = this.moduleFolders.filter(folder => currentContainerIds.includes(folder.containerId));
const currentProjectMergedFolders = this.mergedFolders.filter(folder => currentContainerIds.includes(folder.containerId));
const data = { const data = {
projects: this.projects.filter(p => p.id === this.currentProjectId), projects: this.projects.filter(p => p.id === this.currentProjectId),
aircrafts: currentProjectAircrafts, aircrafts: currentProjectAircrafts,
containers: currentProjectContainers, containers: currentProjectContainers,
configs: currentProjectConfigs, configs: currentProjectConfigs,
gitRepos: currentProjectGitRepos, moduleFolders: currentProjectModuleFolders // 保存模块文件夹数据
mergedFolders: currentProjectMergedFolders // 保存合并文件夹数据
}; };
const uint8Array = new TextEncoder().encode(JSON.stringify(data, null, 2)); const uint8Array = new TextEncoder().encode(JSON.stringify(data, null, 2));
await vscode.workspace.fs.writeFile(dataUri, uint8Array); await vscode.workspace.fs.writeFile(dataUri, uint8Array);
console.log('✅ 当前项目数据已保存,包含', currentProjectGitRepos.length, '个 Git 仓库和', currentProjectMergedFolders.length, '个合并文件夹'); console.log('✅ 当前项目数据已保存,包含', currentProjectModuleFolders.length, '个模块文件夹');
} }
catch (error) { catch (error) {
vscode.window.showErrorMessage(`保存项目数据失败: ${error}`); vscode.window.showErrorMessage(`保存项目数据失败: ${error}`);
@@ -727,8 +735,7 @@ class ConfigPanel {
this.aircrafts = []; this.aircrafts = [];
this.containers = []; this.containers = [];
this.configs = []; this.configs = [];
this.gitRepos = []; this.moduleFolders = []; // 清空模块文件夹数据
this.mergedFolders = []; // 清空合并文件夹数据
// 验证数据格式并加载 // 验证数据格式并加载
if (data.projects && Array.isArray(data.projects)) { if (data.projects && Array.isArray(data.projects)) {
this.projects = data.projects; this.projects = data.projects;
@@ -742,11 +749,8 @@ class ConfigPanel {
if (data.configs && Array.isArray(data.configs)) { if (data.configs && Array.isArray(data.configs)) {
this.configs = data.configs; this.configs = data.configs;
} }
if (data.gitRepos && Array.isArray(data.gitRepos)) { if (data.moduleFolders && Array.isArray(data.moduleFolders)) {
this.gitRepos = data.gitRepos; this.moduleFolders = data.moduleFolders; // 加载模块文件夹数据
}
if (data.mergedFolders && Array.isArray(data.mergedFolders)) {
this.mergedFolders = data.mergedFolders; // 加载合并文件夹数据
} }
// 设置当前项目为第一个项目(如果有的话) // 设置当前项目为第一个项目(如果有的话)
if (this.projects.length > 0) { if (this.projects.length > 0) {
@@ -754,7 +758,7 @@ class ConfigPanel {
this.projectPaths.set(this.currentProjectId, projectPath); this.projectPaths.set(this.currentProjectId, projectPath);
this.currentView = 'aircrafts'; this.currentView = 'aircrafts';
} }
vscode.window.showInformationMessage(`项目数据已从 ${projectPath} 加载,包含 ${this.gitRepos.length} 个 Git 仓库和 ${this.mergedFolders.length}合并文件夹`); vscode.window.showInformationMessage(`项目数据已从 ${projectPath} 加载,包含 ${this.moduleFolders.length}模块文件夹`);
this.updateWebview(); this.updateWebview();
return true; return true;
} }
@@ -905,8 +909,8 @@ class ConfigPanel {
// 删除相关的配置 // 删除相关的配置
const containerIds = this.containers.filter(c => aircraftIds.includes(c.aircraftId)).map(c => c.id); const containerIds = this.containers.filter(c => aircraftIds.includes(c.aircraftId)).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId)); this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId)); this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
// 删除项目路径映射 // 删除项目路径映射
this.projectPaths.delete(projectId); this.projectPaths.delete(projectId);
vscode.window.showInformationMessage(`删除项目: ${project.name}`); vscode.window.showInformationMessage(`删除项目: ${project.name}`);
@@ -953,8 +957,8 @@ class ConfigPanel {
// 删除相关的配置 // 删除相关的配置
const containerIds = this.containers.filter(c => c.aircraftId === aircraftId).map(c => c.id); const containerIds = this.containers.filter(c => c.aircraftId === aircraftId).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId)); this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId)); this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
vscode.window.showInformationMessage(`删除飞行器: ${aircraft.name}`); vscode.window.showInformationMessage(`删除飞行器: ${aircraft.name}`);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
this.updateWebview(); this.updateWebview();
@@ -1015,8 +1019,8 @@ class ConfigPanel {
this.containers = this.containers.filter(c => c.id !== containerId); this.containers = this.containers.filter(c => c.id !== containerId);
// 删除相关的配置 // 删除相关的配置
this.configs = this.configs.filter(cfg => cfg.containerId !== containerId); this.configs = this.configs.filter(cfg => cfg.containerId !== containerId);
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => repo.containerId !== containerId); this.moduleFolders = this.moduleFolders.filter(folder => folder.containerId !== containerId);
vscode.window.showInformationMessage(`删除容器: ${container.name}`); vscode.window.showInformationMessage(`删除容器: ${container.name}`);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
this.updateWebview(); this.updateWebview();
@@ -1204,7 +1208,7 @@ class ConfigPanel {
message: `克隆分支: ${branch} (${i + 1}/${branches.length})` message: `克隆分支: ${branch} (${i + 1}/${branches.length})`
}); });
console.log(`📥 克隆分支: ${branch}`); console.log(`📥 克隆分支: ${branch}`);
await this.addGitRepo(url, this.generateRepoName(url, branch), branch); await this.addGitModuleFolder(url, this.generateModuleFolderName(url, branch), branch);
} }
}); });
vscode.window.showInformationMessage(`成功克隆 ${branches.length} 个分支`); vscode.window.showInformationMessage(`成功克隆 ${branches.length} 个分支`);
@@ -1214,7 +1218,7 @@ class ConfigPanel {
vscode.window.showErrorMessage(`克隆分支失败: ${error}`); vscode.window.showErrorMessage(`克隆分支失败: ${error}`);
} }
} }
generateRepoName(url, branch) { generateModuleFolderName(url, branch) {
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo'; const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-'); const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
return `${repoName}-${branchSafeName}`; return `${repoName}-${branchSafeName}`;
@@ -1257,18 +1261,16 @@ class ConfigPanel {
case 'configs': case 'configs':
const currentContainer = this.containers.find(c => c.id === this.currentContainerId); const currentContainer = this.containers.find(c => c.id === this.currentContainerId);
const containerConfigs = this.configs.filter(cfg => cfg.containerId === this.currentContainerId); const containerConfigs = this.configs.filter(cfg => cfg.containerId === this.currentContainerId);
const currentRepo = this.gitRepos.find(r => r.id === this.currentRepoId); const currentModuleFolder = this.moduleFolders.find(f => f.id === this.currentModuleFolderId);
// 获取当前容器的 Git 仓库和合并文件夹 // 获取当前容器的模块文件夹
const containerGitRepos = this.gitRepos.filter(repo => repo.containerId === this.currentContainerId); const containerModuleFolders = this.moduleFolders.filter(folder => folder.containerId === this.currentContainerId);
const containerMergedFolders = this.mergedFolders.filter(folder => folder.containerId === this.currentContainerId);
return this.configView.render({ return this.configView.render({
container: currentContainer, container: currentContainer,
configs: containerConfigs, configs: containerConfigs,
gitRepos: containerGitRepos, moduleFolders: containerModuleFolders,
currentGitRepo: currentRepo, currentModuleFolder: currentModuleFolder,
gitFileTree: this.currentRepoFileTree, moduleFolderFileTree: this.currentModuleFolderFileTree,
gitLoading: false, moduleFolderLoading: false
mergedFolders: containerMergedFolders // 传递合并文件夹数据
}); });
default: default:
return this.projectView.render({ return this.projectView.render({
@@ -1277,26 +1279,27 @@ class ConfigPanel {
}); });
} }
} }
async openGitRepoInVSCode(repoId) { async openGitRepoInVSCode(folderId) {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return; return;
} }
try { try {
// 检查仓库目录是否存在 // 检查文件夹是否存在
if (!fs.existsSync(repo.localPath)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage('Git 仓库目录不存在,请重新克隆'); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹目录不存在');
return; return;
} }
// 使用 VSCode 的文件选择器让用户选择要打开的文件 // 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({ const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(repo.localPath), defaultUri: vscode.Uri.file(fullPath),
canSelectFiles: true, canSelectFiles: true,
canSelectFolders: false, canSelectFolders: false,
canSelectMany: false, canSelectMany: false,
openLabel: '选择要打开的文件', openLabel: '选择要打开的文件',
title: `${repo.name} 中选择文件` title: `${folder.name} 中选择文件`
}); });
if (fileUri && fileUri.length > 0) { if (fileUri && fileUri.length > 0) {
// 打开选中的文件 // 打开选中的文件
@@ -1306,7 +1309,7 @@ class ConfigPanel {
} }
} }
catch (error) { catch (error) {
vscode.window.showErrorMessage(`打开 Git 仓库文件失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹文件失败: ${error}`);
} }
} }
async openConfigFileInVSCode(configId) { async openConfigFileInVSCode(configId) {
@@ -1401,19 +1404,18 @@ class ConfigPanel {
console.log(`✅ 已创建配置文件: ${config.fileName}`); console.log(`✅ 已创建配置文件: ${config.fileName}`);
} }
} }
// 构建相对路径
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
// 创建合并文件夹记录 // 创建合并文件夹记录
const newFolder = { const newFolder = {
id: 'merged-' + Date.now(), id: 'merged-' + Date.now(),
displayName: displayName, name: displayName,
folderName: folderName, type: 'merged',
path: mergeFolderPath, localPath: relativePath,
fileCount: copiedFiles.length, containerId: this.currentContainerId
containerId: this.currentContainerId,
originalConfigIds: configIds,
createdAt: new Date().toLocaleString()
}; };
// 添加到合并文件夹列表 // 添加到模块文件夹列表
this.mergedFolders.push(newFolder); this.moduleFolders.push(newFolder);
// 删除原始配置文件 // 删除原始配置文件
for (const configId of configIds) { for (const configId of configIds) {
await this.deleteConfigInternal(configId); await this.deleteConfigInternal(configId);
@@ -1421,7 +1423,7 @@ class ConfigPanel {
// 保存数据 // 保存数据
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`成功合并 ${selectedConfigs.length} 个配置文件到文件夹: ${folderName}`); vscode.window.showInformationMessage(`成功合并 ${selectedConfigs.length} 个配置文件到文件夹: ${folderName}`);
// 更新UI(不自动打开文件夹) // 更新UI
this.updateWebview(); this.updateWebview();
} }
catch (error) { catch (error) {
@@ -1461,50 +1463,28 @@ class ConfigPanel {
console.error(`删除配置文件失败: ${error}`); console.error(`删除配置文件失败: ${error}`);
} }
} }
/**
* 删除合并文件夹
*/
async deleteMergedFolder(folderId) {
const folder = this.mergedFolders.find(f => f.id === folderId);
if (!folder)
return;
const confirm = await vscode.window.showWarningMessage(`确定要删除合并文件夹 "${folder.displayName}" 吗?这将删除文件夹及其所有内容。`, { modal: true }, '确定删除', '取消');
if (confirm === '确定删除') {
try {
// 删除文件夹及其所有内容
await fs.promises.rm(folder.path, { recursive: true, force: true });
// 从列表中移除
this.mergedFolders = this.mergedFolders.filter(f => f.id !== folderId);
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`合并文件夹已删除: ${folder.displayName}`);
this.updateWebview();
}
catch (error) {
vscode.window.showErrorMessage(`删除合并文件夹失败: ${error}`);
}
}
}
/** /**
* 在 VSCode 中打开合并文件夹 * 在 VSCode 中打开合并文件夹
*/ */
async openMergedFolderInVSCode(folderId) { async openMergedFolderInVSCode(folderId) {
const folder = this.mergedFolders.find(f => f.id === folderId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!folder) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return; return;
} }
try { try {
// 检查文件夹是否存在 // 检查文件夹是否存在
if (!fs.existsSync(folder.path)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage('合并文件夹不存在'); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹不存在');
return; return;
} }
// 使用 VSCode 打开文件夹 // 使用 VSCode 打开文件夹
const folderUri = vscode.Uri.file(folder.path); const folderUri = vscode.Uri.file(fullPath);
vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: false }); vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: false });
} }
catch (error) { catch (error) {
vscode.window.showErrorMessage(`打开合并文件夹失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹失败: ${error}`);
} }
} }
/** /**
@@ -1513,44 +1493,26 @@ class ConfigPanel {
* @param id 模块 ID * @param id 模块 ID
*/ */
async openTheModuleFolder(type, id) { async openTheModuleFolder(type, id) {
let folderPath; const folder = this.moduleFolders.find(f => f.id === id);
let folderName;
if (type === 'git') {
const repo = this.gitRepos.find(r => r.id === id);
if (!repo) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库');
return;
}
folderPath = repo.localPath;
folderName = repo.name;
}
else if (type === 'merged') {
const folder = this.mergedFolders.find(f => f.id === id);
if (!folder) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return;
}
folderPath = folder.path;
folderName = folder.displayName;
}
if (!folderPath) {
vscode.window.showErrorMessage('未找到文件夹路径');
return; return;
} }
try { try {
// 检查文件夹是否存在 // 检查文件夹是否存在
if (!fs.existsSync(folderPath)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage(`${type === 'git' ? 'Git 仓库' : '合并文件夹'}目录不存在`); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹目录不存在');
return; return;
} }
// 使用 VSCode 的文件选择器让用户选择要打开的文件 // 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({ const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(folderPath), defaultUri: vscode.Uri.file(fullPath),
canSelectFiles: true, canSelectFiles: true,
canSelectFolders: false, canSelectFolders: false,
canSelectMany: false, canSelectMany: false,
openLabel: '选择要打开的文件', openLabel: '选择要打开的文件',
title: `${folderName} 中选择文件` title: `${folder.name} 中选择文件`
}); });
if (fileUri && fileUri.length > 0) { if (fileUri && fileUri.length > 0) {
// 打开选中的文件 // 打开选中的文件
@@ -1560,9 +1522,29 @@ class ConfigPanel {
} }
} }
catch (error) { catch (error) {
vscode.window.showErrorMessage(`打开${type === 'git' ? 'Git 仓库' : '合并文件夹'}文件失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹文件失败: ${error}`);
} }
} }
/**
* 获取模块文件夹的完整路径
*/
getModuleFolderFullPath(folder) {
const container = this.containers.find(c => c.id === folder.containerId);
if (!container)
return null;
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft)
return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath)
return null;
// 从相对路径解析出文件夹名称
const pathParts = folder.localPath.split('/').filter(part => part);
if (pathParts.length < 4)
return null;
const folderName = pathParts[pathParts.length - 1];
return path.join(projectPath, aircraft.name, container.name, folderName);
}
} }
exports.ConfigPanel = ConfigPanel; exports.ConfigPanel = ConfigPanel;
//# sourceMappingURL=ConfigPanel.js.map //# sourceMappingURL=ConfigPanel.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
"use strict";
// src/types/DataTypes.ts
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=DataTypes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DataTypes.js","sourceRoot":"","sources":["../../../src/panels/types/DataTypes.ts"],"names":[],"mappings":";AAAA,yBAAyB"}

View File

@@ -6,14 +6,13 @@ class ConfigView extends BaseView_1.BaseView {
render(data) { render(data) {
const container = data?.container; const container = data?.container;
const configs = data?.configs || []; const configs = data?.configs || [];
const gitRepos = data?.gitRepos || []; const moduleFolders = data?.moduleFolders || [];
const currentGitRepo = data?.currentGitRepo; const currentModuleFolder = data?.currentModuleFolder;
const gitFileTree = data?.gitFileTree || []; const moduleFolderFileTree = data?.moduleFolderFileTree || [];
const gitLoading = data?.gitLoading || false; const moduleFolderLoading = data?.moduleFolderLoading || false;
const gitBranches = data?.gitBranches || []; const gitBranches = data?.gitBranches || [];
const gitRepoUrl = data?.gitRepoUrl || ''; const gitRepoUrl = data?.gitRepoUrl || '';
const mergedFolders = data?.mergedFolders || []; // 生成配置列表的 HTML - 包含配置文件和模块文件夹
// 生成配置列表的 HTML - 包含配置文件和 Git 仓库
const configsHtml = configs.map((config) => ` const configsHtml = configs.map((config) => `
<tr> <tr>
<td> <td>
@@ -28,39 +27,22 @@ class ConfigView extends BaseView_1.BaseView {
</td> </td>
</tr> </tr>
`).join(''); `).join('');
// 生成合并文件夹的 HTML - 显示在配置列表中 // 生成模块文件夹的 HTML - 统一显示 Git 和合并文件夹
const mergedFoldersHtml = mergedFolders.map((folder) => ` const moduleFoldersHtml = moduleFolders.map((folder) => {
<tr> const icon = folder.type === 'git' ? '📁' : '📁';
<td>
<span class="editable">📁 ${folder.displayName}</span>
</td>
<td>
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', 'merged')">${folder.folderName}</span>
</td>
<td>
<button class="btn-delete" onclick="deleteMergedFolder('${folder.id}')">删除</button>
</td>
</tr>
`).join('');
// 生成 Git 仓库列表的 HTML - 修改显示方式Git 仓库不可勾选
const gitReposHtml = gitRepos.map(repo => {
// 提取仓库名称从URL中获取或使用name
const repoName = repo.name.split(' (')[0]; // 移除分支名部分
// 提取分支名
const branchMatch = repo.name.match(/\(([^)]+)\)/);
const branchName = branchMatch ? branchMatch[1] : repo.branch;
return ` return `
<tr> <tr>
<td> <td>
<span class="editable">📁 ${repoName}</span> <span class="editable">${icon} ${folder.name}</span>
<div style="font-size: 12px; color: var(--vscode-descriptionForeground); margin-top: 4px;">
</div>
</td> </td>
<td> <td>
<span class="clickable" onclick="openTheModuleFolder('${repo.id}', 'git')">${branchName}</span> <span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
</td> </td>
<td> <td>
<button class="btn-delete" onclick="deleteGitRepo('${repo.id}')">删除</button> ${folder.type === 'git' ? `
<button class="btn-sync" onclick="syncModuleFolder('${folder.id}')" style="margin-right: 5px;">同步</button>
` : ''}
<button class="btn-delete" onclick="deleteModuleFolder('${folder.id}')">删除</button>
</td> </td>
</tr> </tr>
`; `;
@@ -110,6 +92,19 @@ class ConfigView extends BaseView_1.BaseView {
opacity: 0.8; opacity: 0.8;
} }
.btn-sync {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-sync:hover {
background: var(--vscode-button-hoverBackground);
}
/* 树状分支样式 */ /* 树状分支样式 */
.branch-tree { .branch-tree {
font-family: 'Courier New', monospace; font-family: 'Courier New', monospace;
@@ -251,21 +246,20 @@ class ConfigView extends BaseView_1.BaseView {
<thead> <thead>
<tr> <tr>
<th width="30%">配置</th> <th width="30%">配置</th>
<th width="40%">文件</th> <th width="40%">文件/文件夹</th>
<th width="30%">操作</th> <th width="30%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
${configsHtml} ${configsHtml}
${mergedFoldersHtml} ${moduleFoldersHtml}
${gitReposHtml}
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- Git 仓库管理部分 --> <!-- 模块文件夹管理部分 -->
<div class="config-section"> <div class="config-section">
<h3 class="section-title">📚 Git 仓库管理</h3> <h3 class="section-title">📚 模块云仓库</h3>
<!-- URL 输入区域 --> <!-- URL 输入区域 -->
<div class="url-input-section"> <div class="url-input-section">
@@ -319,8 +313,7 @@ class ConfigView extends BaseView_1.BaseView {
}); });
} }
// 统一功能:打开模块文件夹
// 统一功能:打开模块文件夹(合并 Git 仓库和合并文件夹功能)
function openTheModuleFolder(id, type) { function openTheModuleFolder(id, type) {
console.log('📂 打开模块文件夹:', { id, type }); console.log('📂 打开模块文件夹:', { id, type });
vscode.postMessage({ vscode.postMessage({
@@ -364,46 +357,34 @@ class ConfigView extends BaseView_1.BaseView {
); );
} }
// 删除合并文件夹功能 // 删除模块文件夹功能
function deleteMergedFolder(folderId) { function deleteModuleFolder(folderId) {
console.log('🗑️ 尝试删除合并文件夹:', folderId); console.log('🗑️ 尝试删除模块文件夹:', folderId);
showConfirmDialog( showConfirmDialog(
'确认删除合并文件夹', '确认删除模块文件夹',
'确定删除这个合并文件夹吗?这将删除文件夹及其所有内容。', '确定删除这个模块文件夹吗?这将删除文件夹及其所有内容。',
function() { function() {
console.log('✅ 用户确认删除合并文件夹:', folderId); console.log('✅ 用户确认删除模块文件夹:', folderId);
vscode.postMessage({ vscode.postMessage({
type: 'deleteMergedFolder', type: 'deleteModuleFolder',
folderId: folderId folderId: folderId
}); });
}, },
function() { function() {
// 用户取消删除 // 用户取消删除
console.log('❌ 用户取消删除合并文件夹'); console.log('❌ 用户取消删除模块文件夹');
} }
); );
} }
// Git 仓库删除功能 // 同步 Git 模块文件夹
function deleteGitRepo(repoId) { function syncModuleFolder(folderId) {
console.log('🗑️ 尝试删除 Git 仓库:', repoId); console.log('🔄 同步模块文件夹:', folderId);
showConfirmDialog(
'确认删除 Git 仓库',
'确定删除这个 Git 仓库吗?这将删除本地克隆的代码文件夹。',
function() {
console.log('✅ 用户确认删除 Git 仓库:', repoId);
vscode.postMessage({ vscode.postMessage({
type: 'deleteGitRepo', type: 'syncGitModuleFolder',
repoId: repoId folderId: folderId
}); });
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除 Git 仓库');
}
);
} }
function goBackToContainers() { function goBackToContainers() {
@@ -480,14 +461,6 @@ class ConfigView extends BaseView_1.BaseView {
}); });
} }
function syncGitRepo(repoId) {
console.log('🔄 同步仓库:', repoId);
vscode.postMessage({
type: 'syncGitRepo',
repoId: repoId
});
}
// 配置文件合并功能 // 配置文件合并功能
function toggleConfigSelection(configId) { function toggleConfigSelection(configId) {
const checkbox = document.querySelector('.config-checkbox[data-id="' + configId + '"]'); const checkbox = document.querySelector('.config-checkbox[data-id="' + configId + '"]');

File diff suppressed because one or more lines are too long

4
out/types/DataTypes.js Normal file
View File

@@ -0,0 +1,4 @@
"use strict";
// src/types/DataTypes.ts
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=DataTypes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"DataTypes.js","sourceRoot":"","sources":["../../src/types/DataTypes.ts"],"names":[],"mappings":";AAAA,yBAAyB"}

View File

@@ -34,15 +34,13 @@ interface Config {
containerId: string; containerId: string;
} }
// Git 仓库接口 // 统一的模块文件夹接口,合并 gitRepos 和 mergedFolders
interface GitRepo { interface ModuleFolder {
id: string; id: string;
name: string; name: string;
url: string; type: 'git' | 'merged'; // 类型标识
localPath: string; localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
branch: string; containerId: string;
lastSync: string;
containerId: string; // 关联到特定容器
} }
interface GitFileTree { interface GitFileTree {
@@ -59,25 +57,13 @@ interface GitBranch {
selected?: boolean; selected?: boolean;
} }
interface MergedFolder { // 修改 ProjectData 接口,使用统一的 moduleFolders
id: string;
displayName: string; // 配置栏显示的名称
folderName: string; // 实际文件夹名称
path: string;
fileCount: number;
containerId: string;
originalConfigIds: string[];
createdAt: string;
}
// 修改 ProjectData 接口,添加 mergedFolders
interface ProjectData { interface ProjectData {
projects: Project[]; projects: Project[];
aircrafts: Aircraft[]; aircrafts: Aircraft[];
containers: Container[]; containers: Container[];
configs: Config[]; configs: Config[];
gitRepos: GitRepo[]; moduleFolders: ModuleFolder[]; // 统一的模块文件夹数据
mergedFolders: MergedFolder[]; // 新增合并文件夹数据
} }
export class ConfigPanel { export class ConfigPanel {
@@ -89,18 +75,17 @@ export class ConfigPanel {
private currentProjectId: string = ''; private currentProjectId: string = '';
private currentAircraftId: string = ''; private currentAircraftId: string = '';
private currentContainerId: string = ''; private currentContainerId: string = '';
private currentRepoId: string = ''; private currentModuleFolderId: string = '';
// 数据存储 // 数据存储
private projects: Project[] = []; private projects: Project[] = [];
private aircrafts: Aircraft[] = []; private aircrafts: Aircraft[] = [];
private containers: Container[] = []; private containers: Container[] = [];
private configs: Config[] = []; private configs: Config[] = [];
private gitRepos: GitRepo[] = []; // Git 仓库数据 private moduleFolders: ModuleFolder[] = []; // 统一的模块文件夹数据
private mergedFolders: MergedFolder[] = [];
// Git 文件树 // Git 文件树
private currentRepoFileTree: GitFileTree[] = []; private currentModuleFolderFileTree: GitFileTree[] = [];
// 项目存储路径映射 // 项目存储路径映射
private projectPaths: Map<string, string> = new Map(); private projectPaths: Map<string, string> = new Map();
@@ -208,7 +193,7 @@ export class ConfigPanel {
this.currentProjectId = ''; this.currentProjectId = '';
this.currentAircraftId = ''; this.currentAircraftId = '';
this.currentContainerId = ''; this.currentContainerId = '';
this.currentRepoId = ''; this.currentModuleFolderId = '';
this.updateWebview(); this.updateWebview();
break; break;
@@ -291,24 +276,24 @@ export class ConfigPanel {
this.updateWebview(); this.updateWebview();
break; break;
case 'loadGitRepo': case 'loadModuleFolder':
await this.loadGitRepo(data.repoId); await this.loadModuleFolder(data.folderId);
break; break;
case 'syncGitRepo': case 'syncGitModuleFolder':
await this.syncGitRepo(data.repoId); await this.syncGitModuleFolder(data.folderId);
break; break;
case 'deleteGitRepo': case 'deleteModuleFolder':
await this.deleteGitRepo(data.repoId); await this.deleteModuleFolder(data.folderId);
break; break;
case 'importGitFile': case 'importGitFile':
await this.importGitFile(data.filePath); await this.importGitFile(data.filePath);
break; break;
case 'openGitRepoInVSCode': case 'openModuleFolderInVSCode':
await this.openTheModuleFolder('git', data.repoId); await this.openTheModuleFolder(data.moduleType, data.folderId);
break; break;
case 'openConfigFileInVSCode': case 'openConfigFileInVSCode':
@@ -320,7 +305,7 @@ export class ConfigPanel {
break; break;
case 'deleteMergedFolder': case 'deleteMergedFolder':
await this.deleteMergedFolder(data.folderId); await this.deleteModuleFolder(data.folderId);
break; break;
case 'openMergedFolderInVSCode': case 'openMergedFolderInVSCode':
@@ -434,9 +419,9 @@ export class ConfigPanel {
// === Git 仓库管理方法 === // === Git 仓库管理方法 ===
/** /**
* 添加 Git 仓库到容器目录 * 添加 Git 模块文件夹到容器目录
*/ */
private async addGitRepo(url: string, name: string, branch?: string): Promise<void> { private async addGitModuleFolder(url: string, name: string, branch?: string): Promise<void> {
try { try {
// 验证 URL // 验证 URL
if (!url || !url.startsWith('http')) { if (!url || !url.startsWith('http')) {
@@ -449,9 +434,9 @@ export class ConfigPanel {
return; return;
} }
const repoId = 'git-' + Date.now(); const folderId = 'git-' + Date.now();
// 构建本地路径 - 在容器目录下创建分支子目录 // 构建本地路径
const container = this.containers.find(c => c.id === this.currentContainerId); const container = this.containers.find(c => c.id === this.currentContainerId);
if (!container) { if (!container) {
vscode.window.showErrorMessage('未找到容器'); vscode.window.showErrorMessage('未找到容器');
@@ -470,41 +455,38 @@ export class ConfigPanel {
return; return;
} }
// 为每个分支创建独立的子目录 // 构建相对路径(从项目路径开始)
const branchName = branch || 'main'; const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${name}`;
const branchSafeName = branchName.replace(/[^a-zA-Z0-9-_]/g, '-');
const repoDirName = name;
// 路径:项目路径/飞行器名/容器名/仓库名-分支名/ // 完整路径用于实际操作
const localPath = path.join(projectPath, aircraft.name, container.name, repoDirName); const localPath = path.join(projectPath, aircraft.name, container.name, name);
console.log(`📁 Git仓库将保存到: ${localPath}`); console.log(`📁 Git模块文件夹将保存到: ${localPath}`);
console.log(`📁 相对路径: ${relativePath}`);
// 检查是否已存在相同 URL 和分支的仓库 // 检查是否已存在相同名称的模块文件夹
const existingRepo = this.gitRepos.find(repo => const existingFolder = this.moduleFolders.find(folder =>
repo.url === url && repo.branch === branchName && repo.containerId === this.currentContainerId folder.name === name && folder.containerId === this.currentContainerId
); );
if (existingRepo) { if (existingFolder) {
vscode.window.showWarningMessage('该 Git 仓库和分支组合已存在'); vscode.window.showWarningMessage('该名称的模块文件夹已存在');
return; return;
} }
const newRepo: GitRepo = { const newFolder: ModuleFolder = {
id: repoId, id: folderId,
name: `${name} (${branchName})`, // 在名称中包含分支信息 name: name,
url: url, type: 'git',
localPath: localPath, localPath: relativePath, // 存储相对路径
branch: branchName,
lastSync: new Date().toLocaleString(),
containerId: this.currentContainerId containerId: this.currentContainerId
}; };
console.log(`📁 准备克隆仓库: ${name}, 分支: ${newRepo.branch}, 路径: ${localPath}`); console.log(`📁 准备克隆仓库: ${name}, 分支: ${branch}, 路径: ${localPath}`);
// 显示进度 // 显示进度
await vscode.window.withProgress({ await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
title: `正在克隆仓库: ${name} (${newRepo.branch})`, title: `正在克隆仓库: ${name}`,
cancellable: false cancellable: false
}, async (progress) => { }, async (progress) => {
progress.report({ increment: 0 }); progress.report({ increment: 0 });
@@ -545,7 +527,7 @@ export class ConfigPanel {
url: url, url: url,
singleBranch: true, singleBranch: true,
depth: 1, depth: 1,
ref: branchName, ref: branch || 'main',
onProgress: (event: any) => { onProgress: (event: any) => {
if (event.total) { if (event.total) {
const percent = (event.loaded / event.total) * 100; const percent = (event.loaded / event.total) * 100;
@@ -556,19 +538,19 @@ export class ConfigPanel {
console.log('✅ Git克隆成功完成'); console.log('✅ Git克隆成功完成');
this.gitRepos.push(newRepo); this.moduleFolders.push(newFolder);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
console.log('✅ Git仓库数据已保存到项目文件'); console.log('✅ Git模块文件夹数据已保存到项目文件');
vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name} (${newRepo.branch})`); vscode.window.showInformationMessage(`Git 仓库克隆成功: ${name}`);
// 检查 Webview 状态后再加载文件树 // 检查 Webview 状态后再加载文件树
if (!this.isWebviewDisposed) { if (!this.isWebviewDisposed) {
console.log('🌳 开始加载仓库文件树...'); console.log('🌳 开始加载模块文件夹文件树...');
// 自动加载仓库文件树 // 自动加载文件树
this.currentRepoId = repoId; this.currentModuleFolderId = folderId;
await this.loadGitRepoFileTree(repoId); await this.loadModuleFolderFileTree(folderId);
console.log('✅ 仓库文件树加载完成'); console.log('✅ 模块文件夹文件树加载完成');
} else { } else {
console.log('⚠️ Webview 已被销毁,跳过文件树加载'); console.log('⚠️ Webview 已被销毁,跳过文件树加载');
} }
@@ -580,33 +562,43 @@ export class ConfigPanel {
}); });
} catch (error) { } catch (error) {
console.error('❌ 在addGitRepo外部捕获错误:', error); console.error('❌ 在addGitModuleFolder外部捕获错误:', error);
vscode.window.showErrorMessage(`添加 Git 仓库失败: ${error}`); vscode.window.showErrorMessage(`添加 Git 模块文件夹失败: ${error}`);
} }
} }
/** /**
* 加载 Git 仓库文件 * 加载模块文件
*/ */
private async loadGitRepo(repoId: string): Promise<void> { private async loadModuleFolder(folderId: string): Promise<void> {
this.currentRepoId = repoId; this.currentModuleFolderId = folderId;
await this.loadGitRepoFileTree(repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (folder && folder.type === 'git') {
await this.loadModuleFolderFileTree(folderId);
}
this.updateWebview(); this.updateWebview();
} }
/** /**
* 同步 Git 仓库 * 同步 Git 模块文件夹
*/ */
private async syncGitRepo(repoId: string): Promise<void> { private async syncGitModuleFolder(folderId: string): Promise<void> {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) { if (!folder || folder.type !== 'git') {
vscode.window.showErrorMessage('未找到指定的 Git 仓库'); vscode.window.showErrorMessage('未找到指定的 Git 模块文件夹');
return;
}
// 获取完整路径
const fullPath = this.getModuleFolderFullPath(folder);
if (!fullPath) {
vscode.window.showErrorMessage('无法获取模块文件夹的完整路径');
return; return;
} }
await vscode.window.withProgress({ await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification, location: vscode.ProgressLocation.Notification,
title: `正在同步仓库: ${repo.name}`, title: `正在同步仓库: ${folder.name}`,
cancellable: false cancellable: false
}, async (progress) => { }, async (progress) => {
try { try {
@@ -616,19 +608,15 @@ export class ConfigPanel {
await git.pull({ await git.pull({
fs: fs, fs: fs,
http: http, http: http,
dir: repo.localPath, dir: fullPath,
author: { name: 'DCSP User', email: 'user@dcsp.local' }, author: { name: 'DCSP User', email: 'user@dcsp.local' },
fastForward: true fastForward: true
}); });
// 更新最后同步时间
repo.lastSync = new Date().toLocaleString();
await this.saveCurrentProjectData();
// 重新加载文件树 // 重新加载文件树
await this.loadGitRepoFileTree(repoId); await this.loadModuleFolderFileTree(folderId);
vscode.window.showInformationMessage(`Git 仓库同步成功: ${repo.name}`); vscode.window.showInformationMessage(`Git 仓库同步成功: ${folder.name}`);
this.updateWebview(); this.updateWebview();
} catch (error) { } catch (error) {
@@ -638,14 +626,14 @@ export class ConfigPanel {
} }
/** /**
* 删除 Git 仓库 * 删除模块文件夹
*/ */
private async deleteGitRepo(repoId: string): Promise<void> { private async deleteModuleFolder(folderId: string): Promise<void> {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) return; if (!folder) return;
const confirm = await vscode.window.showWarningMessage( const confirm = await vscode.window.showWarningMessage(
`确定要删除 Git 仓库 "${repo.name}" 吗?这将删除本地文件。`, `确定要删除模块文件夹 "${folder.name}" 吗?这将删除本地文件。`,
{ modal: true }, { modal: true },
'确定删除', '确定删除',
'取消' '取消'
@@ -653,45 +641,48 @@ export class ConfigPanel {
if (confirm === '确定删除') { if (confirm === '确定删除') {
try { try {
// 删除整个仓库目录(因为是独立目录) // 获取完整路径并删除文件夹
await fs.promises.rm(repo.localPath, { recursive: true, force: true }); const fullPath = this.getModuleFolderFullPath(folder);
if (fullPath) {
// 从列表中移除 await fs.promises.rm(fullPath, { recursive: true, force: true });
this.gitRepos = this.gitRepos.filter(r => r.id !== repoId);
await this.saveCurrentProjectData();
// 如果删除的是当前仓库,清空状态
if (this.currentRepoId === repoId) {
this.currentRepoId = '';
this.currentRepoFileTree = [];
} }
vscode.window.showInformationMessage(`Git 仓库已删除: ${repo.name}`); // 从列表中移除
this.moduleFolders = this.moduleFolders.filter(f => f.id !== folderId);
await this.saveCurrentProjectData();
// 如果删除的是当前文件夹,清空状态
if (this.currentModuleFolderId === folderId) {
this.currentModuleFolderId = '';
this.currentModuleFolderFileTree = [];
}
vscode.window.showInformationMessage(`模块文件夹已删除: ${folder.name}`);
this.updateWebview(); this.updateWebview();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`删除 Git 仓库失败: ${error}`); vscode.window.showErrorMessage(`删除模块文件夹失败: ${error}`);
} }
} }
} }
/** /**
* 加载 Git 仓库文件树 * 加载模块文件夹文件树
*/ */
private async loadGitRepoFileTree(repoId: string): Promise<void> { private async loadModuleFolderFileTree(folderId: string): Promise<void> {
// 检查 Webview 是否仍然有效 // 检查 Webview 是否仍然有效
if (this.isWebviewDisposed) { if (this.isWebviewDisposed) {
console.log('⚠️ Webview 已被销毁,跳过文件树加载'); console.log('⚠️ Webview 已被销毁,跳过文件树加载');
return; return;
} }
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) return; if (!folder) return;
// 通知前端开始加载 // 通知前端开始加载
try { try {
this.panel.webview.postMessage({ this.panel.webview.postMessage({
type: 'gitRepoLoading', type: 'moduleFolderLoading',
loading: true loading: true
}); });
} catch (error) { } catch (error) {
@@ -700,16 +691,15 @@ export class ConfigPanel {
} }
try { try {
const fileTree = await this.buildFileTree(repo.localPath); const fullPath = this.getModuleFolderFullPath(folder);
this.currentRepoFileTree = fileTree; if (fullPath) {
const fileTree = await this.buildFileTree(fullPath);
// 更新最后访问时间 this.currentModuleFolderFileTree = fileTree;
repo.lastSync = new Date().toLocaleString(); }
await this.saveCurrentProjectData();
} catch (error) { } catch (error) {
console.error('加载仓库文件树失败:', error); console.error('加载模块文件夹文件树失败:', error);
this.currentRepoFileTree = []; this.currentModuleFolderFileTree = [];
} }
// 再次检查 Webview 状态 // 再次检查 Webview 状态
@@ -721,7 +711,7 @@ export class ConfigPanel {
// 通知前端加载完成 // 通知前端加载完成
try { try {
this.panel.webview.postMessage({ this.panel.webview.postMessage({
type: 'gitRepoLoading', type: 'moduleFolderLoading',
loading: false loading: false
}); });
@@ -776,14 +766,14 @@ export class ConfigPanel {
* 导入 Git 文件到当前容器 * 导入 Git 文件到当前容器
*/ */
private async importGitFile(filePath: string): Promise<void> { private async importGitFile(filePath: string): Promise<void> {
if (!this.currentRepoId || !this.currentContainerId) { if (!this.currentModuleFolderId || !this.currentContainerId) {
vscode.window.showErrorMessage('请先选择 Git 仓库和容器'); vscode.window.showErrorMessage('请先选择模块文件夹和容器');
return; return;
} }
const repo = this.gitRepos.find(r => r.id === this.currentRepoId); const folder = this.moduleFolders.find(f => f.id === this.currentModuleFolderId);
if (!repo) { if (!folder || folder.type !== 'git') {
vscode.window.showErrorMessage('未找到当前 Git 仓库'); vscode.window.showErrorMessage('未找到当前 Git 模块文件夹');
return; return;
} }
@@ -794,8 +784,14 @@ export class ConfigPanel {
} }
try { try {
const fullPath = path.join(repo.localPath, filePath); const fullPath = this.getModuleFolderFullPath(folder);
const content = await fs.promises.readFile(fullPath, 'utf8'); if (!fullPath) {
vscode.window.showErrorMessage('无法获取模块文件夹路径');
return;
}
const fileFullPath = path.join(fullPath, filePath);
const content = await fs.promises.readFile(fileFullPath, 'utf8');
const fileName = path.basename(filePath); const fileName = path.basename(filePath);
// 创建新配置 // 创建新配置
@@ -868,11 +864,8 @@ export class ConfigPanel {
const currentContainerIds = currentProjectContainers.map(c => c.id); const currentContainerIds = currentProjectContainers.map(c => c.id);
const currentProjectConfigs = this.configs.filter(cfg => currentContainerIds.includes(cfg.containerId)); const currentProjectConfigs = this.configs.filter(cfg => currentContainerIds.includes(cfg.containerId));
// 只保存与当前项目容器相关的 Git 仓库和合并文件夹 // 只保存与当前项目容器相关的模块文件夹
const currentProjectGitRepos = this.gitRepos.filter(repo => const currentProjectModuleFolders = this.moduleFolders.filter(folder =>
currentContainerIds.includes(repo.containerId)
);
const currentProjectMergedFolders = this.mergedFolders.filter(folder =>
currentContainerIds.includes(folder.containerId) currentContainerIds.includes(folder.containerId)
); );
@@ -881,18 +874,17 @@ export class ConfigPanel {
aircrafts: currentProjectAircrafts, aircrafts: currentProjectAircrafts,
containers: currentProjectContainers, containers: currentProjectContainers,
configs: currentProjectConfigs, configs: currentProjectConfigs,
gitRepos: currentProjectGitRepos, moduleFolders: currentProjectModuleFolders // 保存模块文件夹数据
mergedFolders: currentProjectMergedFolders // 保存合并文件夹数据
}; };
const uint8Array = new TextEncoder().encode(JSON.stringify(data, null, 2)); const uint8Array = new TextEncoder().encode(JSON.stringify(data, null, 2));
await vscode.workspace.fs.writeFile(dataUri, uint8Array); await vscode.workspace.fs.writeFile(dataUri, uint8Array);
console.log('✅ 当前项目数据已保存,包含', currentProjectGitRepos.length, '个 Git 仓库和', currentProjectMergedFolders.length, '个合并文件夹'); console.log('✅ 当前项目数据已保存,包含', currentProjectModuleFolders.length, '个模块文件夹');
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`保存项目数据失败: ${error}`); vscode.window.showErrorMessage(`保存项目数据失败: ${error}`);
} }
} }
/** /**
* 从项目路径加载数据 * 从项目路径加载数据
@@ -919,8 +911,7 @@ export class ConfigPanel {
this.aircrafts = []; this.aircrafts = [];
this.containers = []; this.containers = [];
this.configs = []; this.configs = [];
this.gitRepos = []; this.moduleFolders = []; // 清空模块文件夹数据
this.mergedFolders = []; // 清空合并文件夹数据
// 验证数据格式并加载 // 验证数据格式并加载
if (data.projects && Array.isArray(data.projects)) { if (data.projects && Array.isArray(data.projects)) {
@@ -935,11 +926,8 @@ export class ConfigPanel {
if (data.configs && Array.isArray(data.configs)) { if (data.configs && Array.isArray(data.configs)) {
this.configs = data.configs; this.configs = data.configs;
} }
if (data.gitRepos && Array.isArray(data.gitRepos)) { if (data.moduleFolders && Array.isArray(data.moduleFolders)) {
this.gitRepos = data.gitRepos; this.moduleFolders = data.moduleFolders; // 加载模块文件夹数据
}
if (data.mergedFolders && Array.isArray(data.mergedFolders)) {
this.mergedFolders = data.mergedFolders; // 加载合并文件夹数据
} }
// 设置当前项目为第一个项目(如果有的话) // 设置当前项目为第一个项目(如果有的话)
@@ -949,14 +937,14 @@ export class ConfigPanel {
this.currentView = 'aircrafts'; this.currentView = 'aircrafts';
} }
vscode.window.showInformationMessage(`项目数据已从 ${projectPath} 加载,包含 ${this.gitRepos.length} 个 Git 仓库和 ${this.mergedFolders.length}合并文件夹`); vscode.window.showInformationMessage(`项目数据已从 ${projectPath} 加载,包含 ${this.moduleFolders.length}模块文件夹`);
this.updateWebview(); this.updateWebview();
return true; return true;
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`加载项目数据失败: ${error}`); vscode.window.showErrorMessage(`加载项目数据失败: ${error}`);
return false; return false;
} }
} }
/** /**
* 检查项目路径是否已存在数据 * 检查项目路径是否已存在数据
@@ -1122,8 +1110,8 @@ export class ConfigPanel {
// 删除相关的配置 // 删除相关的配置
const containerIds = this.containers.filter(c => aircraftIds.includes(c.aircraftId)).map(c => c.id); const containerIds = this.containers.filter(c => aircraftIds.includes(c.aircraftId)).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId)); this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId)); this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
// 删除项目路径映射 // 删除项目路径映射
this.projectPaths.delete(projectId); this.projectPaths.delete(projectId);
@@ -1177,8 +1165,8 @@ export class ConfigPanel {
// 删除相关的配置 // 删除相关的配置
const containerIds = this.containers.filter(c => c.aircraftId === aircraftId).map(c => c.id); const containerIds = this.containers.filter(c => c.aircraftId === aircraftId).map(c => c.id);
this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId)); this.configs = this.configs.filter(cfg => !containerIds.includes(cfg.containerId));
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => !containerIds.includes(repo.containerId)); this.moduleFolders = this.moduleFolders.filter(folder => !containerIds.includes(folder.containerId));
vscode.window.showInformationMessage(`删除飞行器: ${aircraft.name}`); vscode.window.showInformationMessage(`删除飞行器: ${aircraft.name}`);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
@@ -1252,8 +1240,8 @@ export class ConfigPanel {
// 删除相关的配置 // 删除相关的配置
this.configs = this.configs.filter(cfg => cfg.containerId !== containerId); this.configs = this.configs.filter(cfg => cfg.containerId !== containerId);
// 删除相关的 Git 仓库 // 删除相关的模块文件夹
this.gitRepos = this.gitRepos.filter(repo => repo.containerId !== containerId); this.moduleFolders = this.moduleFolders.filter(folder => folder.containerId !== containerId);
vscode.window.showInformationMessage(`删除容器: ${container.name}`); vscode.window.showInformationMessage(`删除容器: ${container.name}`);
await this.saveCurrentProjectData(); await this.saveCurrentProjectData();
@@ -1426,12 +1414,12 @@ export class ConfigPanel {
console.error('❌ 获取分支失败:', error); console.error('❌ 获取分支失败:', error);
vscode.window.showErrorMessage(`获取分支失败: ${error}`); vscode.window.showErrorMessage(`获取分支失败: ${error}`);
} }
} }
/** /**
* 构建分支树状结构 * 构建分支树状结构
*/ */
private buildBranchTree(branches: GitBranch[]): any[] { private buildBranchTree(branches: GitBranch[]): any[] {
const root: any[] = []; const root: any[] = [];
branches.forEach(branch => { branches.forEach(branch => {
@@ -1467,7 +1455,7 @@ private buildBranchTree(branches: GitBranch[]): any[] {
}); });
return root; return root;
} }
private async cloneBranches(url: string, branches: string[]): Promise<void> { private async cloneBranches(url: string, branches: string[]): Promise<void> {
try { try {
@@ -1488,7 +1476,7 @@ private buildBranchTree(branches: GitBranch[]): any[] {
}); });
console.log(`📥 克隆分支: ${branch}`); console.log(`📥 克隆分支: ${branch}`);
await this.addGitRepo(url, this.generateRepoName(url, branch), branch); await this.addGitModuleFolder(url, this.generateModuleFolderName(url, branch), branch);
} }
}); });
@@ -1500,7 +1488,7 @@ private buildBranchTree(branches: GitBranch[]): any[] {
} }
} }
private generateRepoName(url: string, branch: string): string { private generateModuleFolderName(url: string, branch: string): string {
const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo'; const repoName = url.split('/').pop()?.replace('.git', '') || 'unknown-repo';
const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-'); const branchSafeName = branch.replace(/[^a-zA-Z0-9-_]/g, '-');
return `${repoName}-${branchSafeName}`; return `${repoName}-${branchSafeName}`;
@@ -1546,20 +1534,18 @@ private buildBranchTree(branches: GitBranch[]): any[] {
case 'configs': case 'configs':
const currentContainer = this.containers.find(c => c.id === this.currentContainerId); const currentContainer = this.containers.find(c => c.id === this.currentContainerId);
const containerConfigs = this.configs.filter(cfg => cfg.containerId === this.currentContainerId); const containerConfigs = this.configs.filter(cfg => cfg.containerId === this.currentContainerId);
const currentRepo = this.gitRepos.find(r => r.id === this.currentRepoId); const currentModuleFolder = this.moduleFolders.find(f => f.id === this.currentModuleFolderId);
// 获取当前容器的 Git 仓库和合并文件夹 // 获取当前容器的模块文件夹
const containerGitRepos = this.gitRepos.filter(repo => repo.containerId === this.currentContainerId); const containerModuleFolders = this.moduleFolders.filter(folder => folder.containerId === this.currentContainerId);
const containerMergedFolders = this.mergedFolders.filter(folder => folder.containerId === this.currentContainerId);
return this.configView.render({ return this.configView.render({
container: currentContainer, container: currentContainer,
configs: containerConfigs, configs: containerConfigs,
gitRepos: containerGitRepos, moduleFolders: containerModuleFolders,
currentGitRepo: currentRepo, currentModuleFolder: currentModuleFolder,
gitFileTree: this.currentRepoFileTree, moduleFolderFileTree: this.currentModuleFolderFileTree,
gitLoading: false, moduleFolderLoading: false
mergedFolders: containerMergedFolders // 传递合并文件夹数据
}); });
default: default:
return this.projectView.render({ return this.projectView.render({
@@ -1567,30 +1553,31 @@ private buildBranchTree(branches: GitBranch[]): any[] {
projectPaths: this.projectPaths projectPaths: this.projectPaths
}); });
} }
} }
private async openGitRepoInVSCode(repoId: string): Promise<void> { private async openGitRepoInVSCode(folderId: string): Promise<void> {
const repo = this.gitRepos.find(r => r.id === repoId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!repo) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return; return;
} }
try { try {
// 检查仓库目录是否存在 // 检查文件夹是否存在
if (!fs.existsSync(repo.localPath)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage('Git 仓库目录不存在,请重新克隆'); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹目录不存在');
return; return;
} }
// 使用 VSCode 的文件选择器让用户选择要打开的文件 // 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({ const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(repo.localPath), defaultUri: vscode.Uri.file(fullPath),
canSelectFiles: true, canSelectFiles: true,
canSelectFolders: false, canSelectFolders: false,
canSelectMany: false, canSelectMany: false,
openLabel: '选择要打开的文件', openLabel: '选择要打开的文件',
title: `${repo.name} 中选择文件` title: `${folder.name} 中选择文件`
}); });
if (fileUri && fileUri.length > 0) { if (fileUri && fileUri.length > 0) {
@@ -1601,7 +1588,7 @@ private buildBranchTree(branches: GitBranch[]): any[] {
} }
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`打开 Git 仓库文件失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹文件失败: ${error}`);
} }
} }
@@ -1653,7 +1640,7 @@ private buildBranchTree(branches: GitBranch[]): any[] {
} }
} }
private async mergeConfigs(configIds: string[], displayName: string, folderName: string): Promise<void> { private async mergeConfigs(configIds: string[], displayName: string, folderName: string): Promise<void> {
try { try {
if (!this.currentContainerId) { if (!this.currentContainerId) {
vscode.window.showErrorMessage('未找到当前容器'); vscode.window.showErrorMessage('未找到当前容器');
@@ -1712,20 +1699,20 @@ private async mergeConfigs(configIds: string[], displayName: string, folderName:
} }
} }
// 构建相对路径
const relativePath = `/${aircraft.projectId}/${aircraft.name}/${container.name}/${folderName}`;
// 创建合并文件夹记录 // 创建合并文件夹记录
const newFolder: MergedFolder = { const newFolder: ModuleFolder = {
id: 'merged-' + Date.now(), id: 'merged-' + Date.now(),
displayName: displayName, // 使用传入的显示名称 name: displayName,
folderName: folderName, // 使用传入的文件夹名称 type: 'merged',
path: mergeFolderPath, localPath: relativePath,
fileCount: copiedFiles.length, containerId: this.currentContainerId
containerId: this.currentContainerId,
originalConfigIds: configIds,
createdAt: new Date().toLocaleString()
}; };
// 添加到合并文件夹列表 // 添加到模块文件夹列表
this.mergedFolders.push(newFolder); this.moduleFolders.push(newFolder);
// 删除原始配置文件 // 删除原始配置文件
for (const configId of configIds) { for (const configId of configIds) {
@@ -1737,19 +1724,19 @@ private async mergeConfigs(configIds: string[], displayName: string, folderName:
vscode.window.showInformationMessage(`成功合并 ${selectedConfigs.length} 个配置文件到文件夹: ${folderName}`); vscode.window.showInformationMessage(`成功合并 ${selectedConfigs.length} 个配置文件到文件夹: ${folderName}`);
// 更新UI(不自动打开文件夹) // 更新UI
this.updateWebview(); this.updateWebview();
} catch (error) { } catch (error) {
console.error('❌ 合并配置文件失败:', error); console.error('❌ 合并配置文件失败:', error);
vscode.window.showErrorMessage(`合并配置文件失败: ${error}`); vscode.window.showErrorMessage(`合并配置文件失败: ${error}`);
} }
} }
/** /**
* 内部删除配置文件方法(不显示确认对话框) * 内部删除配置文件方法(不显示确认对话框)
*/ */
private async deleteConfigInternal(configId: string): Promise<void> { private async deleteConfigInternal(configId: string): Promise<void> {
try { try {
const config = this.configs.find(c => c.id === configId); const config = this.configs.find(c => c.id === configId);
if (!config) return; if (!config) return;
@@ -1780,64 +1767,34 @@ private async deleteConfigInternal(configId: string): Promise<void> {
} catch (error) { } catch (error) {
console.error(`删除配置文件失败: ${error}`); console.error(`删除配置文件失败: ${error}`);
} }
}
/**
* 删除合并文件夹
*/
private async deleteMergedFolder(folderId: string): Promise<void> {
const folder = this.mergedFolders.find(f => f.id === folderId);
if (!folder) return;
const confirm = await vscode.window.showWarningMessage(
`确定要删除合并文件夹 "${folder.displayName}" 吗?这将删除文件夹及其所有内容。`,
{ modal: true },
'确定删除',
'取消'
);
if (confirm === '确定删除') {
try {
// 删除文件夹及其所有内容
await fs.promises.rm(folder.path, { recursive: true, force: true });
// 从列表中移除
this.mergedFolders = this.mergedFolders.filter(f => f.id !== folderId);
await this.saveCurrentProjectData();
vscode.window.showInformationMessage(`合并文件夹已删除: ${folder.displayName}`);
this.updateWebview();
} catch (error) {
vscode.window.showErrorMessage(`删除合并文件夹失败: ${error}`);
} }
}
}
/** /**
* 在 VSCode 中打开合并文件夹 * 在 VSCode 中打开合并文件夹
*/ */
private async openMergedFolderInVSCode(folderId: string): Promise<void> { private async openMergedFolderInVSCode(folderId: string): Promise<void> {
const folder = this.mergedFolders.find(f => f.id === folderId); const folder = this.moduleFolders.find(f => f.id === folderId);
if (!folder) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return; return;
} }
try { try {
// 检查文件夹是否存在 // 检查文件夹是否存在
if (!fs.existsSync(folder.path)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage('合并文件夹不存在'); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹不存在');
return; return;
} }
// 使用 VSCode 打开文件夹 // 使用 VSCode 打开文件夹
const folderUri = vscode.Uri.file(folder.path); const folderUri = vscode.Uri.file(fullPath);
vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: false }); vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: false });
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`打开合并文件夹失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹失败: ${error}`);
}
} }
}
/** /**
* 统一方法:在 VSCode 中打开模块文件夹中的文件 * 统一方法:在 VSCode 中打开模块文件夹中的文件
@@ -1845,47 +1802,28 @@ private async openMergedFolderInVSCode(folderId: string): Promise<void> {
* @param id 模块 ID * @param id 模块 ID
*/ */
private async openTheModuleFolder(type: 'git' | 'merged', id: string): Promise<void> { private async openTheModuleFolder(type: 'git' | 'merged', id: string): Promise<void> {
let folderPath: string | undefined; const folder = this.moduleFolders.find(f => f.id === id);
let folderName: string | undefined;
if (type === 'git') {
const repo = this.gitRepos.find(r => r.id === id);
if (!repo) {
vscode.window.showErrorMessage('未找到指定的 Git 仓库');
return;
}
folderPath = repo.localPath;
folderName = repo.name;
} else if (type === 'merged') {
const folder = this.mergedFolders.find(f => f.id === id);
if (!folder) { if (!folder) {
vscode.window.showErrorMessage('未找到指定的合并文件夹'); vscode.window.showErrorMessage('未找到指定的模块文件夹');
return;
}
folderPath = folder.path;
folderName = folder.displayName;
}
if (!folderPath) {
vscode.window.showErrorMessage('未找到文件夹路径');
return; return;
} }
try { try {
// 检查文件夹是否存在 // 检查文件夹是否存在
if (!fs.existsSync(folderPath)) { const fullPath = this.getModuleFolderFullPath(folder);
vscode.window.showErrorMessage(`${type === 'git' ? 'Git 仓库' : '合并文件夹'}目录不存在`); if (!fullPath || !fs.existsSync(fullPath)) {
vscode.window.showErrorMessage('模块文件夹目录不存在');
return; return;
} }
// 使用 VSCode 的文件选择器让用户选择要打开的文件 // 使用 VSCode 的文件选择器让用户选择要打开的文件
const fileUri = await vscode.window.showOpenDialog({ const fileUri = await vscode.window.showOpenDialog({
defaultUri: vscode.Uri.file(folderPath), defaultUri: vscode.Uri.file(fullPath),
canSelectFiles: true, canSelectFiles: true,
canSelectFolders: false, canSelectFolders: false,
canSelectMany: false, canSelectMany: false,
openLabel: '选择要打开的文件', openLabel: '选择要打开的文件',
title: `${folderName} 中选择文件` title: `${folder.name} 中选择文件`
}); });
if (fileUri && fileUri.length > 0) { if (fileUri && fileUri.length > 0) {
@@ -1896,7 +1834,28 @@ private async openMergedFolderInVSCode(folderId: string): Promise<void> {
} }
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(`打开${type === 'git' ? 'Git 仓库' : '合并文件夹'}文件失败: ${error}`); vscode.window.showErrorMessage(`打开模块文件夹文件失败: ${error}`);
} }
} }
/**
* 获取模块文件夹的完整路径
*/
private getModuleFolderFullPath(folder: ModuleFolder): string | null {
const container = this.containers.find(c => c.id === folder.containerId);
if (!container) return null;
const aircraft = this.aircrafts.find(a => a.id === container.aircraftId);
if (!aircraft) return null;
const projectPath = this.projectPaths.get(aircraft.projectId);
if (!projectPath) return null;
// 从相对路径解析出文件夹名称
const pathParts = folder.localPath.split('/').filter(part => part);
if (pathParts.length < 4) return null;
const folderName = pathParts[pathParts.length - 1];
return path.join(projectPath, aircraft.name, container.name, folderName);
}
} }

View File

@@ -16,6 +16,7 @@ export interface Container {
name: string; name: string;
aircraftId: string; aircraftId: string;
configs: Config[]; configs: Config[];
moduleFolders: ModuleFolder[]; // 新增:模块文件夹列表
} }
export interface Config { export interface Config {
@@ -25,3 +26,12 @@ export interface Config {
content: string; content: string;
containerId: string; containerId: string;
} }
// 新增:统一的模块文件夹接口
export interface ModuleFolder {
id: string;
name: string;
type: 'git' | 'merged'; // 类型标识
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
containerId: string;
}

View File

@@ -0,0 +1,45 @@
// src/types/DataTypes.ts
// 统一的模块文件夹接口
export interface ModuleFolder {
id: string;
name: string;
type: 'git' | 'merged'; // 类型标识
localPath: string; // 相对路径,如 "/项目1/飞行器1/容器1/test-code"
containerId: string;
}
// 项目数据接口
export interface ProjectData {
projects: Project[];
aircrafts: Aircraft[];
containers: Container[];
configs: Config[];
moduleFolders: ModuleFolder[]; // 统一的模块文件夹数据
}
// 基础数据接口
export interface Project {
id: string;
name: string;
}
export interface Aircraft {
id: string;
name: string;
projectId: string;
}
export interface Container {
id: string;
name: string;
aircraftId: string;
}
export interface Config {
id: string;
name: string;
fileName: string;
content: string;
containerId: string;
}

9
src/panels/types/ViewTypes.ts Normal file → Executable file
View File

@@ -39,14 +39,13 @@ export interface ContainerConfigData {
configs: ConfigViewData[]; configs: ConfigViewData[];
} }
// 新增 Git 相关类型 // 新增模块文件夹相关类型
export interface GitRepoData { export interface ModuleFolderData {
id: string; id: string;
name: string; name: string;
url: string; type: 'git' | 'merged';
localPath: string; localPath: string;
branch: string; containerId: string;
lastSync: string;
} }
export interface GitFileTree { export interface GitFileTree {

View File

@@ -1,5 +1,6 @@
import { BaseView } from './BaseView'; import { BaseView } from './BaseView';
import { ContainerConfigData, ConfigViewData } from '../types/ViewTypes'; import { ContainerConfigData, ConfigViewData } from '../types/ViewTypes';
import { ModuleFolder } from '../types/DataTypes';
// Git 分支接口 // Git 分支接口
interface GitBranch { interface GitBranch {
@@ -26,29 +27,6 @@ interface GitFileTree {
children?: GitFileTree[]; children?: GitFileTree[];
} }
// Git 仓库接口
interface GitRepo {
id: string;
name: string;
url: string;
localPath: string;
branch: string;
lastSync: string;
containerId: string;
}
// 合并文件夹接口
interface MergedFolder {
id: string;
displayName: string; // 配置栏显示的名称
folderName: string; // 实际文件夹名称
path: string;
fileCount: number;
containerId: string;
originalConfigIds: string[];
createdAt: string;
}
// 树状分支节点接口 // 树状分支节点接口
interface BranchTreeNode { interface BranchTreeNode {
name: string; name: string;
@@ -62,25 +40,23 @@ interface BranchTreeNode {
export class ConfigView extends BaseView { export class ConfigView extends BaseView {
render(data?: ContainerConfigData & { render(data?: ContainerConfigData & {
gitRepos?: GitRepo[]; moduleFolders?: ModuleFolder[];
currentGitRepo?: GitRepo; currentModuleFolder?: ModuleFolder;
gitFileTree?: GitFileTree[]; moduleFolderFileTree?: GitFileTree[];
gitLoading?: boolean; moduleFolderLoading?: boolean;
gitBranches?: GitBranch[]; gitBranches?: GitBranch[];
gitRepoUrl?: string; gitRepoUrl?: string;
mergedFolders?: MergedFolder[];
}): string { }): string {
const container = data?.container; const container = data?.container;
const configs = data?.configs || []; const configs = data?.configs || [];
const gitRepos = data?.gitRepos || []; const moduleFolders = data?.moduleFolders || [];
const currentGitRepo = data?.currentGitRepo; const currentModuleFolder = data?.currentModuleFolder;
const gitFileTree = data?.gitFileTree || []; const moduleFolderFileTree = data?.moduleFolderFileTree || [];
const gitLoading = data?.gitLoading || false; const moduleFolderLoading = data?.moduleFolderLoading || false;
const gitBranches = data?.gitBranches || []; const gitBranches = data?.gitBranches || [];
const gitRepoUrl = data?.gitRepoUrl || ''; const gitRepoUrl = data?.gitRepoUrl || '';
const mergedFolders = data?.mergedFolders || [];
// 生成配置列表的 HTML - 包含配置文件和 Git 仓库 // 生成配置列表的 HTML - 包含配置文件和模块文件夹
const configsHtml = configs.map((config: ConfigViewData) => ` const configsHtml = configs.map((config: ConfigViewData) => `
<tr> <tr>
<td> <td>
@@ -96,41 +72,23 @@ export class ConfigView extends BaseView {
</tr> </tr>
`).join(''); `).join('');
// 生成合并文件夹的 HTML - 显示在配置列表中 // 生成模块文件夹的 HTML - 统一显示 Git 和合并文件夹
const mergedFoldersHtml = mergedFolders.map((folder: MergedFolder) => ` const moduleFoldersHtml = moduleFolders.map((folder: ModuleFolder) => {
<tr> const icon = folder.type === 'git' ? '📁' : '📁';
<td>
<span class="editable">📁 ${folder.displayName}</span>
</td>
<td>
<span class="clickable" onclick="openTheModuleFolder('${folder.id}', 'merged')">${folder.folderName}</span>
</td>
<td>
<button class="btn-delete" onclick="deleteMergedFolder('${folder.id}')">删除</button>
</td>
</tr>
`).join('');
// 生成 Git 仓库列表的 HTML - 修改显示方式Git 仓库不可勾选
const gitReposHtml = gitRepos.map(repo => {
// 提取仓库名称从URL中获取或使用name
const repoName = repo.name.split(' (')[0]; // 移除分支名部分
// 提取分支名
const branchMatch = repo.name.match(/\(([^)]+)\)/);
const branchName = branchMatch ? branchMatch[1] : repo.branch;
return ` return `
<tr> <tr>
<td> <td>
<span class="editable">📁 ${repoName}</span> <span class="editable">${icon} ${folder.name}</span>
<div style="font-size: 12px; color: var(--vscode-descriptionForeground); margin-top: 4px;">
</div>
</td> </td>
<td> <td>
<span class="clickable" onclick="openTheModuleFolder('${repo.id}', 'git')">${branchName}</span> <span class="clickable" onclick="openTheModuleFolder('${folder.id}', '${folder.type}')">${folder.localPath.split('/').pop()}</span>
</td> </td>
<td> <td>
<button class="btn-delete" onclick="deleteGitRepo('${repo.id}')">删除</button> ${folder.type === 'git' ? `
<button class="btn-sync" onclick="syncModuleFolder('${folder.id}')" style="margin-right: 5px;">同步</button>
` : ''}
<button class="btn-delete" onclick="deleteModuleFolder('${folder.id}')">删除</button>
</td> </td>
</tr> </tr>
`; `;
@@ -182,6 +140,19 @@ export class ConfigView extends BaseView {
opacity: 0.8; opacity: 0.8;
} }
.btn-sync {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-sync:hover {
background: var(--vscode-button-hoverBackground);
}
/* 树状分支样式 */ /* 树状分支样式 */
.branch-tree { .branch-tree {
font-family: 'Courier New', monospace; font-family: 'Courier New', monospace;
@@ -323,21 +294,20 @@ export class ConfigView extends BaseView {
<thead> <thead>
<tr> <tr>
<th width="30%">配置</th> <th width="30%">配置</th>
<th width="40%">文件</th> <th width="40%">文件/文件夹</th>
<th width="30%">操作</th> <th width="30%">操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
${configsHtml} ${configsHtml}
${mergedFoldersHtml} ${moduleFoldersHtml}
${gitReposHtml}
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- Git 仓库管理部分 --> <!-- 模块文件夹管理部分 -->
<div class="config-section"> <div class="config-section">
<h3 class="section-title">📚 Git 仓库管理</h3> <h3 class="section-title">📚 模块云仓库</h3>
<!-- URL 输入区域 --> <!-- URL 输入区域 -->
<div class="url-input-section"> <div class="url-input-section">
@@ -391,8 +361,7 @@ export class ConfigView extends BaseView {
}); });
} }
// 统一功能:打开模块文件夹
// 统一功能:打开模块文件夹(合并 Git 仓库和合并文件夹功能)
function openTheModuleFolder(id, type) { function openTheModuleFolder(id, type) {
console.log('📂 打开模块文件夹:', { id, type }); console.log('📂 打开模块文件夹:', { id, type });
vscode.postMessage({ vscode.postMessage({
@@ -436,46 +405,34 @@ export class ConfigView extends BaseView {
); );
} }
// 删除合并文件夹功能 // 删除模块文件夹功能
function deleteMergedFolder(folderId) { function deleteModuleFolder(folderId) {
console.log('🗑️ 尝试删除合并文件夹:', folderId); console.log('🗑️ 尝试删除模块文件夹:', folderId);
showConfirmDialog( showConfirmDialog(
'确认删除合并文件夹', '确认删除模块文件夹',
'确定删除这个合并文件夹吗?这将删除文件夹及其所有内容。', '确定删除这个模块文件夹吗?这将删除文件夹及其所有内容。',
function() { function() {
console.log('✅ 用户确认删除合并文件夹:', folderId); console.log('✅ 用户确认删除模块文件夹:', folderId);
vscode.postMessage({ vscode.postMessage({
type: 'deleteMergedFolder', type: 'deleteModuleFolder',
folderId: folderId folderId: folderId
}); });
}, },
function() { function() {
// 用户取消删除 // 用户取消删除
console.log('❌ 用户取消删除合并文件夹'); console.log('❌ 用户取消删除模块文件夹');
} }
); );
} }
// Git 仓库删除功能 // 同步 Git 模块文件夹
function deleteGitRepo(repoId) { function syncModuleFolder(folderId) {
console.log('🗑️ 尝试删除 Git 仓库:', repoId); console.log('🔄 同步模块文件夹:', folderId);
showConfirmDialog(
'确认删除 Git 仓库',
'确定删除这个 Git 仓库吗?这将删除本地克隆的代码文件夹。',
function() {
console.log('✅ 用户确认删除 Git 仓库:', repoId);
vscode.postMessage({ vscode.postMessage({
type: 'deleteGitRepo', type: 'syncGitModuleFolder',
repoId: repoId folderId: folderId
}); });
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除 Git 仓库');
}
);
} }
function goBackToContainers() { function goBackToContainers() {
@@ -552,14 +509,6 @@ export class ConfigView extends BaseView {
}); });
} }
function syncGitRepo(repoId) {
console.log('🔄 同步仓库:', repoId);
vscode.postMessage({
type: 'syncGitRepo',
repoId: repoId
});
}
// 配置文件合并功能 // 配置文件合并功能
function toggleConfigSelection(configId) { function toggleConfigSelection(configId) {
const checkbox = document.querySelector('.config-checkbox[data-id="' + configId + '"]'); const checkbox = document.querySelector('.config-checkbox[data-id="' + configId + '"]');