0
0

给项目页面、飞行器页面

This commit is contained in:
xubing
2025-12-05 21:15:33 +08:00
parent 2c314b9b0b
commit 46c184b920
18 changed files with 498 additions and 57 deletions

View File

@@ -116,7 +116,7 @@ class ConfigPanel {
return this.openRepoSelectForScope('config');
}
/**
* 弹出“上传代码”时的仓库 + 分支选择弹窗
* 弹出“上传代码”时的仓库 + 分支选择弹窗 (模块文件夹专用)
*/
async openUploadRepoSelect(folderId, folderType) {
await this.loadRepoConfigs();
@@ -133,6 +133,24 @@ class ConfigPanel {
folderType
});
}
/**
* 弹出“上传代码”时的仓库 + 分支选择弹窗 (Project/Aircraft/Container 专用)
*/
async openUploadRepoSelectForScope(scope, id) {
await this.loadRepoConfigs();
if (this.repoConfigs.length === 0) {
vscode.window.showWarningMessage('尚未配置任何仓库,请先点击右上角 "仓库配置" 按钮编辑 dcsp-repos.json。');
return;
}
if (this.isWebviewDisposed)
return;
this.panel.webview.postMessage({
type: 'showUploadRepoSelect',
repos: this.repoConfigs.map(r => ({ name: r.name })),
folderId: id,
folderType: scope // 传递 scope 作为类型
});
}
/**
* “获取仓库”弹窗确认后:用于拉取分支
*/
@@ -147,9 +165,11 @@ class ConfigPanel {
await this.fetchBranchesForRepo(repo);
}
/**
* “上传代码”弹窗确认后:根据 folderType 决定上传逻辑,并使用用户输入的 branchName
* “上传代码”弹窗确认后:根据 type 决定上传逻辑,并使用用户输入的 branchName
*/
async handleUploadRepoSelected(folderId, folderType, repoName, branchName) {
async handleUploadRepoSelected(id, // 现在是通用 ID (folderId, projectId, aircraftId, containerId)
type, // 扩展类型
repoName, branchName) {
const trimmedBranch = (branchName || '').trim();
if (!trimmedBranch) {
vscode.window.showErrorMessage('分支名称不能为空');
@@ -161,13 +181,17 @@ class ConfigPanel {
vscode.window.showErrorMessage(`在仓库配置中未找到名为 "${repoName}" 的仓库`);
return;
}
if (folderType === 'local') {
// 本地模块 -> 选中仓库 + 指定分支
await this.uploadLocalModuleFolder(folderId, repo.url, trimmedBranch, repo.username, repo.token);
if (type === 'local') {
// 本地模块 -> 选中仓库 + 指定分支 (原逻辑)
await this.uploadLocalModuleFolder(id, repo.url, trimmedBranch, repo.username, repo.token);
}
else if (type === 'git') {
// Git 模块 -> 选中仓库 + 指定分支 (原逻辑)
await this.processGitUploadWithBranch(id, repo, trimmedBranch);
}
else {
// Git 模块 -> 选中仓库 + 指定分支
await this.processGitUploadWithBranch(folderId, repo, trimmedBranch);
// 新增逻辑Project, Aircraft, Container 上传
await this.uploadProjectAircraftContainer(id, type, repo, trimmedBranch);
}
}
/**
@@ -201,6 +225,7 @@ class ConfigPanel {
}, async (progress) => {
try {
progress.report({ increment: 0, message: '准备上传...' });
// 这里使用 GitService.pushToRepoUrl它负责 checkout 和 push
await GitService_1.GitService.pushToRepoUrl(fullPath, repo.url, branchName, repo.username, repo.token);
this.projectService.updateModuleFolder(folderId, {
uploaded: true,
@@ -285,13 +310,18 @@ class ConfigPanel {
'importGitFile': (data) => this.importGitFile(data.filePath),
'openTheModuleFolder': (data) => this.openTheModuleFolder(data.moduleType, data.id),
'renameModuleFolder': (data) => this.renameModuleFolder(data.folderId, data.newName),
// 上传功能
// 模块上传功能 (原逻辑)
'uploadGitModuleFolder': (data) => this.uploadGitModuleFolder(data.folderId, data.username, data.password),
'openRepoSelectForUpload': (data) => this.openUploadRepoSelect(data.folderId, 'local'),
'uploadLocalModuleFolder': (data) => this.uploadLocalModuleFolder(data.folderId, data.repoUrl, data.branchName),
'openRepoSelectForGitUpload': (data) => this.openUploadRepoSelect(data.folderId, 'git'),
// 上传时 仓库+分支 选择确认
'uploadRepoSelected': (data) => this.handleUploadRepoSelected(data.folderId, data.folderType, data.repoName, data.branchName)
// 新增Project/Aircraft/Container 上传
'openRepoSelectForProjectUpload': (data) => this.openUploadRepoSelectForScope('project', data.projectId),
'openRepoSelectForAircraftUpload': (data) => this.openUploadRepoSelectForScope('aircraft', data.aircraftId),
'openRepoSelectForContainerUpload': (data) => this.openUploadRepoSelectForScope('container', data.containerId),
// 统一的上传时 仓库+分支 选择确认
'uploadRepoSelected': (data) => this.handleUploadRepoSelected(data.folderId, data.folderType, // 此时 data.folderType 可能是 'project' | 'aircraft' | 'container'
data.repoName, data.branchName)
};
const handler = messageHandlers[data.type];
if (handler) {
@@ -1072,6 +1102,87 @@ class ConfigPanel {
// =============================================
// 上传功能方法
// =============================================
/**
* 上传 Project / Aircraft / Container 目录到 Git 仓库
*/
async uploadProjectAircraftContainer(id, type, repo, branchName) {
let fullPath = null;
let name = '';
// 1. 获取目标目录的完整路径和名称
if (type === 'project') {
fullPath = this.projectService.getProjectPath(id) || null;
name = this.projectService.getProjects().find(p => p.id === id)?.name || 'Project';
}
else if (type === 'aircraft') {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === id);
name = aircraft?.name || 'Aircraft';
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name);
}
}
else if (type === 'container') {
const container = this.projectService.getContainersByAircraft(this.currentAircraftId).find(c => c.id === id);
name = container?.name || 'Container';
if (container) {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === container.aircraftId);
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name, container.name);
}
}
}
if (!fullPath || !require('fs').existsSync(fullPath)) {
vscode.window.showErrorMessage(`无法获取 ${type} "${name}" 的有效路径或目录不存在。请先配置项目路径并确保目录存在。`);
return;
}
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在上传 ${type}: ${name}`,
cancellable: false
}, async (progress) => {
try {
progress.report({ increment: 0, message: '检查目录...' });
const fs = require('fs');
// 检查目录是否为空
const dirContents = await fs.promises.readdir(fullPath);
if (dirContents.length === 0) {
throw new Error('目录为空,无法上传');
}
// 2. 检查是否为 Git 仓库并初始化
let isGitRepo = false;
try {
// Check for .git directory
if (fs.existsSync(path.join(fullPath, '.git'))) {
isGitRepo = true;
}
}
catch (e) { /* ignore */ }
if (!isGitRepo) {
progress.report({ increment: 10, message: '初始化 Git 仓库...' });
// initRepository 内部会创建并切换到指定分支
await GitService_1.GitService.initRepository(fullPath, branchName);
}
// 3. 配置远程仓库
progress.report({ increment: 20, message: '配置远程仓库...' });
try {
// 尝试移除旧的 origin 远程,以避免冲突
await GitService_1.GitService.removeRemote(fullPath);
}
catch (e) { /* ignore if no remote */ }
await GitService_1.GitService.addRemote(fullPath, repo.url, repo.username, repo.token);
// 4. 提交并推送
progress.report({ increment: 40, message: '提交并推送到远程仓库...' });
// commitAndPushToBranch 内部会 add, commit, checkout -B, push
await GitService_1.GitService.commitAndPushToBranch(fullPath, branchName, repo.url, repo.username, repo.token);
progress.report({ increment: 100, message: '完成' });
vscode.window.showInformationMessage(`${type} ${name} 已成功上传到 ${repo.name} 的分支 ${branchName}`);
this.updateWebview();
}
catch (error) {
console.error(`${type} 上传失败:`, error);
vscode.window.showErrorMessage(`推送失败: ${error.message || error}`);
}
});
}
async uploadGitModuleFolder(folderId, username, password) {
const folder = this.projectService.getModuleFolder(folderId);
if (!folder || folder.type !== 'git') {

File diff suppressed because one or more lines are too long

View File

@@ -164,17 +164,38 @@ class GitService {
* 初始化Git仓库
*/
static async initRepository(localPath, branchName) {
// 使用 -b 参数初始化时直接设置分支名
await execAsync(`git init && git checkout -b "${branchName}"`, { cwd: localPath });
}
/**
* 移除远程仓库
*/
static async removeRemote(localPath) {
try {
await execAsync('git remote remove origin', { cwd: localPath });
}
catch (error) {
// 忽略“没有该远程仓库”的错误
if (error.stderr && !error.stderr.includes("No such remote")) {
throw error;
}
if (error.stdout && !error.stdout.includes("No such remote")) {
throw error;
}
}
}
/**
* 添加远程仓库
*/
static async addRemote(localPath, repoUrl, username, token) {
let finalUrl = repoUrl;
if (username && token) {
const u = encodeURIComponent(username);
const t = encodeURIComponent(token);
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
if (username || token) {
const u = encodeURIComponent(username || '');
const t = encodeURIComponent(token || '');
// 注意: 仅在 URL 是 http/https 时添加 auth
if (repoUrl.startsWith('http')) {
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
}
}
await execAsync(`git remote add origin "${finalUrl}"`, { cwd: localPath });
}
@@ -202,7 +223,7 @@ class GitService {
await execAsync(`git push -u origin "${branchName}" --force`, { cwd: localPath });
}
/**
* 使用Git命令提交并推送
* 使用Git命令提交并推送 (用于原有的 Git 模块更新)
*/
static async commitAndPush(localPath) {
await execAsync('git add .', { cwd: localPath });
@@ -238,6 +259,29 @@ class GitService {
];
await execAsync(commands.join(' && '), { cwd: localPath });
}
/**
* 提交并推送到指定分支和远程 (用于 Project/Aircraft/Container 上传)
*/
static async commitAndPushToBranch(localPath, branchName, repoUrl, // 这里的 repoUrl 是为了构造带 auth 的 finalUrl
username, token) {
let finalUrl = repoUrl || 'origin';
if (repoUrl && (username || token)) {
const u = encodeURIComponent(username || '');
const t = encodeURIComponent(token || '');
// 注意: 仅在 URL 是 http/https 时添加 auth
if (repoUrl.startsWith('http')) {
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
}
}
const commands = [
'git add .',
// 允许没有更改时 commit 失败 (Exit code 1),所以使用 || true
`git commit -m "Auto commit from DCSP - ${new Date().toLocaleString()}" || true`,
`git checkout -B "${branchName}"`,
`git push -u "${finalUrl}" "${branchName}" --force` // 强制推送
];
await execAsync(commands.join(' && '), { cwd: localPath });
}
/**
* 生成模块文件夹名称
*/
@@ -257,9 +301,9 @@ class GitService {
/**
* 构建文件树
* 这里显式忽略:
* - .git 目录
* - .dcsp-data.json
* - 其它以 . 开头的隐藏文件/目录
* - .git 目录
* - .dcsp-data.json
* - 其它以 . 开头的隐藏文件/目录
*/
static async buildFileTree(dir, relativePath = '') {
try {

File diff suppressed because one or more lines are too long

View File

@@ -14,6 +14,7 @@ class AircraftView extends BaseView_1.BaseView {
<span class="clickable" onclick="openAircraftConfig('${aircraft.id}', '${aircraft.projectId}')">配置容器</span>
</td>
<td>
<button class="btn-upload" onclick="uploadAircraft('${aircraft.id}', '${aircraft.name}')" style="margin-right: 5px;">上传</button>
<button class="btn-delete" onclick="deleteAircraft('${aircraft.id}')">删除</button>
</td>
</tr>
@@ -178,7 +179,6 @@ class AircraftView extends BaseView_1.BaseView {
</tbody>
</table>
<!-- 飞行器云仓库 -->
<div class="config-section">
<h3 class="section-title">🛫 飞行器云仓库</h3>
<div class="url-input-section">
@@ -241,6 +241,20 @@ class AircraftView extends BaseView_1.BaseView {
}
);
}
// 新增上传功能
function uploadAircraft(aircraftId, aircraftName) {
showConfirmDialog(
'上传飞行器仓库',
'确定将此飞行器目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForAircraftUpload',
aircraftId: aircraftId
});
}
);
}
// 飞行器名称编辑功能
document.addEventListener('DOMContentLoaded', function() {

View File

@@ -1 +1 @@
{"version":3,"file":"AircraftView.js","sourceRoot":"","sources":["../../../src/panels/views/AircraftView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,YAAa,SAAQ,mBAAQ;IACtC,MAAM,CAAC,IAAwC;QAC3C,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;QAExC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;;;oEAGY,QAAQ,CAAC,EAAE,QAAQ,QAAQ,CAAC,IAAI;;;2EAGzB,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,SAAS;;;0EAGrC,QAAQ,CAAC,EAAE;;;SAG5E,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgJlB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwQnB,CAAC;IACL,CAAC;CACJ;AAnbD,oCAmbC"}
{"version":3,"file":"AircraftView.js","sourceRoot":"","sources":["../../../src/panels/views/AircraftView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,YAAa,SAAQ,mBAAQ;IACtC,MAAM,CAAC,IAAwC;QAC3C,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;QAExC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;;;oEAGY,QAAQ,CAAC,EAAE,QAAQ,QAAQ,CAAC,IAAI;;;2EAGzB,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,SAAS;;;0EAGrC,QAAQ,CAAC,EAAE,OAAO,QAAQ,CAAC,IAAI;0EAC/B,QAAQ,CAAC,EAAE;;;SAG5E,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgJlB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAqRnB,CAAC;IACL,CAAC;CACJ;AAjcD,oCAicC"}

View File

@@ -68,6 +68,17 @@ class BaseView {
border-radius: 2px;
cursor: pointer;
}
.btn-upload {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-upload:hover {
background: var(--vscode-button-hoverBackground);
}
.back-btn {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
@@ -464,6 +475,7 @@ class BaseView {
showRepoSelectDialog(message.repos || []);
} else if (message.type === 'showUploadRepoSelect') {
// 新逻辑:上传代码用(仓库 + 分支)
// 这里的 folderId/folderType 现在可能是 Project/Aircraft/Container 的 ID/Type
showUploadRepoSelectDialog(message.repos || [], message.folderId, message.folderType);
}
});

View File

@@ -1 +1 @@
{"version":3,"file":"BaseView.js","sourceRoot":"","sources":["../../../src/panels/views/BaseView.ts"],"names":[],"mappings":";;;AAEA,MAAsB,QAAQ;IAG1B,YAAY,YAAwB;QAChC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAID;;OAEG;IACO,uBAAuB;QAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAmPN,CAAC;IACN,CAAC;IAED;;OAEG;IACO,mBAAmB;QACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAmNN,CAAC;IACN,CAAC;IAED;;OAEG;IACO,SAAS;QACf,OAAO,IAAI,CAAC,uBAAuB,EAAE,CAAC;IAC1C,CAAC;CACJ;AAneD,4BAmeC"}
{"version":3,"file":"BaseView.js","sourceRoot":"","sources":["../../../src/panels/views/BaseView.ts"],"names":[],"mappings":";;;AAEA,MAAsB,QAAQ;IAG1B,YAAY,YAAwB;QAChC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACrC,CAAC;IAID;;OAEG;IACO,uBAAuB;QAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SA8PN,CAAC;IACN,CAAC;IAED;;OAEG;IACO,mBAAmB;QACzB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAoNN,CAAC;IACN,CAAC;IAED;;OAEG;IACO,SAAS;QACf,OAAO,IAAI,CAAC,uBAAuB,EAAE,CAAC;IAC1C,CAAC;CACJ;AA/eD,4BA+eC"}

View File

@@ -16,6 +16,7 @@ class ContainerView extends BaseView_1.BaseView {
<span class="clickable" onclick="openContainerConfig('${container.id}')">配置文件</span>
</td>
<td>
<button class="btn-upload" onclick="uploadContainer('${container.id}', '${container.name}')" style="margin-right: 5px;">上传</button>
<button class="btn-delete" onclick="deleteContainer('${container.id}')">删除</button>
</td>
</tr>
@@ -163,7 +164,6 @@ class ContainerView extends BaseView_1.BaseView {
</tbody>
</table>
<!-- 容器云仓库 -->
<div class="config-section">
<h3 class="section-title">📦 容器云仓库</h3>
<div class="url-input-section">
@@ -240,6 +240,20 @@ class ContainerView extends BaseView_1.BaseView {
}
);
}
// 新增上传功能
function uploadContainer(containerId, containerName) {
showConfirmDialog(
'上传容器仓库',
'确定将此容器目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForContainerUpload',
containerId: containerId
});
}
);
}
// ======== Git 仓库 & 分支树 - ContainerView 作用域 ========

View File

@@ -1 +1 @@
{"version":3,"file":"ContainerView.js","sourceRoot":"","sources":["../../../src/panels/views/ContainerView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,aAAc,SAAQ,mBAAQ;IACvC,MAAM,CAAC,IAAyB;QAC5B,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC;QAC9B,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC;QAE1C,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAA4B,EAAE,EAAE,CAAC;;;yEAGP,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC,IAAI,UAAU,SAAS,CAAC,IAAI;;;4EAGtD,SAAS,CAAC,EAAE;;;2EAGb,SAAS,CAAC,EAAE;;;SAG9E,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gFAkHgD,QAAQ,EAAE,IAAI,IAAI,OAAO;;;;;;;;;;;;;cAa3F,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAsPpB,CAAC;IACL,CAAC;CACJ;AAlZD,sCAkZC"}
{"version":3,"file":"ContainerView.js","sourceRoot":"","sources":["../../../src/panels/views/ContainerView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,aAAc,SAAQ,mBAAQ;IACvC,MAAM,CAAC,IAAyB;QAC5B,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC;QAC9B,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC;QAE1C,MAAM,cAAc,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,SAA4B,EAAE,EAAE,CAAC;;;yEAGP,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC,IAAI,UAAU,SAAS,CAAC,IAAI;;;4EAGtD,SAAS,CAAC,EAAE;;;2EAGb,SAAS,CAAC,EAAE,OAAO,SAAS,CAAC,IAAI;2EACjC,SAAS,CAAC,EAAE;;;SAG9E,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gFAkHgD,QAAQ,EAAE,IAAI,IAAI,OAAO;;;;;;;;;;;;;cAa3F,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAmQpB,CAAC;IACL,CAAC;CACJ;AAhaD,sCAgaC"}

View File

@@ -24,6 +24,7 @@ class ProjectView extends BaseView_1.BaseView {
</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>
@@ -212,7 +213,6 @@ class ProjectView extends BaseView_1.BaseView {
</tbody>
</table>
<!-- 项目云仓库 -->
<div class="config-section">
<h3 class="section-title">📚 项目云仓库</h3>
<div class="url-input-section">
@@ -288,6 +288,20 @@ class ProjectView extends BaseView_1.BaseView {
}
);
}
// 新增上传功能
function uploadProject(projectId, projectName) {
showConfirmDialog(
'上传项目仓库',
'确定将此项目目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForProjectUpload',
projectId: projectId
});
}
);
}
// 项目名称编辑功能
document.addEventListener('DOMContentLoaded', function() {

View File

@@ -1 +1 @@
{"version":3,"file":"ProjectView.js","sourceRoot":"","sources":["../../../src/panels/views/ProjectView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,WAAY,SAAQ,mBAAQ;IACrC,MAAM,CAAC,IAA0E;QAC7E,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;QACtC,MAAM,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,IAAI,GAAG,EAAE,CAAC;QAErD,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAwB,EAAE,EAAE;YAC3D,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7C,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YAEhD,OAAO;;;kEAG+C,OAAO,CAAC,EAAE,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI;;0BAEjF,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;;;;yEAItB,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,IAAI,MAAM,YAAY;0BAC9F,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;yEAIqB,OAAO,CAAC,EAAE;;;SAG1E,CAAA;QAAA,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEb,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgKlB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA4RlB,CAAC;IACL,CAAC;CACJ;AAleD,kCAkeC"}
{"version":3,"file":"ProjectView.js","sourceRoot":"","sources":["../../../src/panels/views/ProjectView.ts"],"names":[],"mappings":";;;AAAA,yCAAsC;AAGtC,MAAa,WAAY,SAAQ,mBAAQ;IACrC,MAAM,CAAC,IAA0E;QAC7E,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;QACtC,MAAM,YAAY,GAAG,IAAI,EAAE,YAAY,IAAI,IAAI,GAAG,EAAE,CAAC;QAErD,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAwB,EAAE,EAAE;YAC3D,MAAM,YAAY,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7C,MAAM,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YAEhD,OAAO;;;kEAG+C,OAAO,CAAC,EAAE,KAAK,UAAU,IAAI,OAAO,CAAC,IAAI;;0BAEjF,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;;;;yEAItB,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,IAAI,MAAM,YAAY;0BAC9F,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI;;;;sBAI9B,YAAY,CAAC,CAAC,CAAC,sDAAsD,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,IAAI,4CAA4C,CAAC,CAAC,CAAC,EAAE;yEAChG,OAAO,CAAC,EAAE;;;SAG1E,CAAA;QAAA,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAEb,OAAO;;;;;;MAMT,IAAI,CAAC,SAAS,EAAE;MAChB,IAAI,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgKlB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAySlB,CAAC;IACL,CAAC;CACJ;AAhfD,kCAgfC"}

View File

@@ -150,7 +150,7 @@ export class ConfigPanel {
}
/**
* 弹出“上传代码”时的仓库 + 分支选择弹窗
* 弹出“上传代码”时的仓库 + 分支选择弹窗 (模块文件夹专用)
*/
private async openUploadRepoSelect(folderId: string, folderType: 'git' | 'local'): Promise<void> {
await this.loadRepoConfigs();
@@ -169,6 +169,30 @@ export class ConfigPanel {
folderType
});
}
/**
* 弹出“上传代码”时的仓库 + 分支选择弹窗 (Project/Aircraft/Container 专用)
*/
private async openUploadRepoSelectForScope(
scope: 'project' | 'aircraft' | 'container',
id: string
): Promise<void> {
await this.loadRepoConfigs();
if (this.repoConfigs.length === 0) {
vscode.window.showWarningMessage('尚未配置任何仓库,请先点击右上角 "仓库配置" 按钮编辑 dcsp-repos.json。');
return;
}
if (this.isWebviewDisposed) return;
this.panel.webview.postMessage({
type: 'showUploadRepoSelect',
repos: this.repoConfigs.map(r => ({ name: r.name })),
folderId: id,
folderType: scope // 传递 scope 作为类型
});
}
/**
* “获取仓库”弹窗确认后:用于拉取分支
@@ -187,11 +211,11 @@ export class ConfigPanel {
}
/**
* “上传代码”弹窗确认后:根据 folderType 决定上传逻辑,并使用用户输入的 branchName
* “上传代码”弹窗确认后:根据 type 决定上传逻辑,并使用用户输入的 branchName
*/
private async handleUploadRepoSelected(
folderId: string,
folderType: 'git' | 'local',
id: string, // 现在是通用 ID (folderId, projectId, aircraftId, containerId)
type: 'git' | 'local' | 'project' | 'aircraft' | 'container', // 扩展类型
repoName: string,
branchName: string
): Promise<void> {
@@ -208,18 +232,21 @@ export class ConfigPanel {
return;
}
if (folderType === 'local') {
// 本地模块 -> 选中仓库 + 指定分支
if (type === 'local') {
// 本地模块 -> 选中仓库 + 指定分支 (原逻辑)
await this.uploadLocalModuleFolder(
folderId,
id,
repo.url,
trimmedBranch,
repo.username,
repo.token
);
} else if (type === 'git') {
// Git 模块 -> 选中仓库 + 指定分支 (原逻辑)
await this.processGitUploadWithBranch(id, repo, trimmedBranch);
} else {
// Git 模块 -> 选中仓库 + 指定分支
await this.processGitUploadWithBranch(folderId, repo, trimmedBranch);
// 新增逻辑Project, Aircraft, Container 上传
await this.uploadProjectAircraftContainer(id, type, repo, trimmedBranch);
}
}
@@ -264,6 +291,7 @@ export class ConfigPanel {
try {
progress.report({ increment: 0, message: '准备上传...' });
// 这里使用 GitService.pushToRepoUrl它负责 checkout 和 push
await GitService.pushToRepoUrl(
fullPath,
repo.url,
@@ -367,16 +395,21 @@ export class ConfigPanel {
'openTheModuleFolder': (data) => this.openTheModuleFolder(data.moduleType, data.id),
'renameModuleFolder': (data) => this.renameModuleFolder(data.folderId, data.newName),
// 上传功能
// 模块上传功能 (原逻辑)
'uploadGitModuleFolder': (data) => this.uploadGitModuleFolder(data.folderId, data.username, data.password),
'openRepoSelectForUpload': (data) => this.openUploadRepoSelect(data.folderId, 'local'),
'uploadLocalModuleFolder': (data) => this.uploadLocalModuleFolder(data.folderId, data.repoUrl, data.branchName),
'openRepoSelectForGitUpload': (data) => this.openUploadRepoSelect(data.folderId, 'git'),
// 新增Project/Aircraft/Container 上传
'openRepoSelectForProjectUpload': (data) => this.openUploadRepoSelectForScope('project', data.projectId),
'openRepoSelectForAircraftUpload': (data) => this.openUploadRepoSelectForScope('aircraft', data.aircraftId),
'openRepoSelectForContainerUpload': (data) => this.openUploadRepoSelectForScope('container', data.containerId),
// 上传时 仓库+分支 选择确认
// 统一的上传时 仓库+分支 选择确认
'uploadRepoSelected': (data) => this.handleUploadRepoSelected(
data.folderId,
data.folderType,
data.folderType, // 此时 data.folderType 可能是 'project' | 'aircraft' | 'container'
data.repoName,
data.branchName
)
@@ -1350,6 +1383,98 @@ export class ConfigPanel {
// =============================================
// 上传功能方法
// =============================================
/**
* 上传 Project / Aircraft / Container 目录到 Git 仓库
*/
private async uploadProjectAircraftContainer(
id: string,
type: 'project' | 'aircraft' | 'container',
repo: RepoConfigItem,
branchName: string
): Promise<void> {
let fullPath: string | null = null;
let name: string = '';
// 1. 获取目标目录的完整路径和名称
if (type === 'project') {
fullPath = this.projectService.getProjectPath(id) || null;
name = this.projectService.getProjects().find(p => p.id === id)?.name || 'Project';
} else if (type === 'aircraft') {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === id);
name = aircraft?.name || 'Aircraft';
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name);
}
} else if (type === 'container') {
const container = this.projectService.getContainersByAircraft(this.currentAircraftId).find(c => c.id === id);
name = container?.name || 'Container';
if (container) {
const aircraft = this.projectService.getAircraftsByProject(this.currentProjectId).find(a => a.id === container.aircraftId);
if (aircraft) {
fullPath = path.join(this.projectService.getProjectPath(aircraft.projectId) || '', aircraft.name, container.name);
}
}
}
if (!fullPath || !require('fs').existsSync(fullPath)) {
vscode.window.showErrorMessage(`无法获取 ${type} "${name}" 的有效路径或目录不存在。请先配置项目路径并确保目录存在。`);
return;
}
await vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
title: `正在上传 ${type}: ${name}`,
cancellable: false
}, async (progress) => {
try {
progress.report({ increment: 0, message: '检查目录...' });
const fs = require('fs');
// 检查目录是否为空
const dirContents = await fs.promises.readdir(fullPath!);
if (dirContents.length === 0) {
throw new Error('目录为空,无法上传');
}
// 2. 检查是否为 Git 仓库并初始化
let isGitRepo = false;
try {
// Check for .git directory
if (fs.existsSync(path.join(fullPath!, '.git'))) {
isGitRepo = true;
}
} catch (e) { /* ignore */ }
if (!isGitRepo) {
progress.report({ increment: 10, message: '初始化 Git 仓库...' });
// initRepository 内部会创建并切换到指定分支
await GitService.initRepository(fullPath!, branchName);
}
// 3. 配置远程仓库
progress.report({ increment: 20, message: '配置远程仓库...' });
try {
// 尝试移除旧的 origin 远程,以避免冲突
await GitService.removeRemote(fullPath!);
} catch(e) { /* ignore if no remote */ }
await GitService.addRemote(fullPath!, repo.url, repo.username, repo.token);
// 4. 提交并推送
progress.report({ increment: 40, message: '提交并推送到远程仓库...' });
// commitAndPushToBranch 内部会 add, commit, checkout -B, push
await GitService.commitAndPushToBranch(fullPath!, branchName, repo.url, repo.username, repo.token);
progress.report({ increment: 100, message: '完成' });
vscode.window.showInformationMessage(`${type} ${name} 已成功上传到 ${repo.name} 的分支 ${branchName}`);
this.updateWebview();
} catch (error: any) {
console.error(`${type} 上传失败:`, error);
vscode.window.showErrorMessage(`推送失败: ${error.message || error}`);
}
});
}
private async uploadGitModuleFolder(folderId: string, username?: string, password?: string): Promise<void> {
const folder = this.projectService.getModuleFolder(folderId);
@@ -1845,4 +1970,4 @@ export class ConfigPanel {
});
}
}
}
}

View File

@@ -171,9 +171,27 @@ export class GitService {
* 初始化Git仓库
*/
static async initRepository(localPath: string, branchName: string): Promise<void> {
// 使用 -b 参数初始化时直接设置分支名
await execAsync(`git init && git checkout -b "${branchName}"`, { cwd: localPath });
}
/**
* 移除远程仓库
*/
static async removeRemote(localPath: string): Promise<void> {
try {
await execAsync('git remote remove origin', { cwd: localPath });
} catch (error: any) {
// 忽略“没有该远程仓库”的错误
if (error.stderr && !error.stderr.includes("No such remote")) {
throw error;
}
if (error.stdout && !error.stdout.includes("No such remote")) {
throw error;
}
}
}
/**
* 添加远程仓库
*/
@@ -185,10 +203,13 @@ export class GitService {
): Promise<void> {
let finalUrl = repoUrl;
if (username && token) {
const u = encodeURIComponent(username);
const t = encodeURIComponent(token);
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
if (username || token) {
const u = encodeURIComponent(username || '');
const t = encodeURIComponent(token || '');
// 注意: 仅在 URL 是 http/https 时添加 auth
if (repoUrl.startsWith('http')) {
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
}
}
await execAsync(`git remote add origin "${finalUrl}"`, { cwd: localPath });
@@ -221,7 +242,7 @@ export class GitService {
}
/**
* 使用Git命令提交并推送
* 使用Git命令提交并推送 (用于原有的 Git 模块更新)
*/
static async commitAndPush(localPath: string): Promise<void> {
await execAsync('git add .', { cwd: localPath });
@@ -270,6 +291,38 @@ export class GitService {
await execAsync(commands.join(' && '), { cwd: localPath });
}
/**
* 提交并推送到指定分支和远程 (用于 Project/Aircraft/Container 上传)
*/
static async commitAndPushToBranch(
localPath: string,
branchName: string,
repoUrl?: string, // 这里的 repoUrl 是为了构造带 auth 的 finalUrl
username?: string,
token?: string
): Promise<void> {
let finalUrl = repoUrl || 'origin';
if (repoUrl && (username || token)) {
const u = encodeURIComponent(username || '');
const t = encodeURIComponent(token || '');
// 注意: 仅在 URL 是 http/https 时添加 auth
if (repoUrl.startsWith('http')) {
finalUrl = repoUrl.replace('://', `://${u}:${t}@`);
}
}
const commands = [
'git add .',
// 允许没有更改时 commit 失败 (Exit code 1),所以使用 || true
`git commit -m "Auto commit from DCSP - ${new Date().toLocaleString()}" || true`,
`git checkout -B "${branchName}"`, // 切换到指定分支
`git push -u "${finalUrl}" "${branchName}" --force` // 强制推送
];
await execAsync(commands.join(' && '), { cwd: localPath });
}
/**
* 生成模块文件夹名称
@@ -292,9 +345,9 @@ export class GitService {
/**
* 构建文件树
* 这里显式忽略:
* - .git 目录
* - .dcsp-data.json
* - 其它以 . 开头的隐藏文件/目录
* - .git 目录
* - .dcsp-data.json
* - 其它以 . 开头的隐藏文件/目录
*/
static async buildFileTree(dir: string, relativePath: string = ''): Promise<GitFileTree[]> {
try {
@@ -338,4 +391,4 @@ export class GitService {
return [];
}
}
}
}

View File

@@ -14,6 +14,7 @@ export class AircraftView extends BaseView {
<span class="clickable" onclick="openAircraftConfig('${aircraft.id}', '${aircraft.projectId}')">配置容器</span>
</td>
<td>
<button class="btn-upload" onclick="uploadAircraft('${aircraft.id}', '${aircraft.name}')" style="margin-right: 5px;">上传</button>
<button class="btn-delete" onclick="deleteAircraft('${aircraft.id}')">删除</button>
</td>
</tr>
@@ -179,7 +180,6 @@ export class AircraftView extends BaseView {
</tbody>
</table>
<!-- 飞行器云仓库 -->
<div class="config-section">
<h3 class="section-title">🛫 飞行器云仓库</h3>
<div class="url-input-section">
@@ -242,6 +242,20 @@ export class AircraftView extends BaseView {
}
);
}
// 新增上传功能
function uploadAircraft(aircraftId, aircraftName) {
showConfirmDialog(
'上传飞行器仓库',
'确定将此飞行器目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForAircraftUpload',
aircraftId: aircraftId
});
}
);
}
// 飞行器名称编辑功能
document.addEventListener('DOMContentLoaded', function() {
@@ -436,4 +450,4 @@ export class AircraftView extends BaseView {
</body>
</html>`;
}
}
}

View File

@@ -72,6 +72,17 @@ export abstract class BaseView {
border-radius: 2px;
cursor: pointer;
}
.btn-upload {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-upload:hover {
background: var(--vscode-button-hoverBackground);
}
.back-btn {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
@@ -469,6 +480,7 @@ export abstract class BaseView {
showRepoSelectDialog(message.repos || []);
} else if (message.type === 'showUploadRepoSelect') {
// 新逻辑:上传代码用(仓库 + 分支)
// 这里的 folderId/folderType 现在可能是 Project/Aircraft/Container 的 ID/Type
showUploadRepoSelectDialog(message.repos || [], message.folderId, message.folderType);
}
});
@@ -483,4 +495,4 @@ export abstract class BaseView {
protected getStyles(): string {
return this.getBaseStylesAndScripts();
}
}
}

View File

@@ -16,6 +16,7 @@ export class ContainerView extends BaseView {
<span class="clickable" onclick="openContainerConfig('${container.id}')">配置文件</span>
</td>
<td>
<button class="btn-upload" onclick="uploadContainer('${container.id}', '${container.name}')" style="margin-right: 5px;">上传</button>
<button class="btn-delete" onclick="deleteContainer('${container.id}')">删除</button>
</td>
</tr>
@@ -164,7 +165,6 @@ export class ContainerView extends BaseView {
</tbody>
</table>
<!-- 容器云仓库 -->
<div class="config-section">
<h3 class="section-title">📦 容器云仓库</h3>
<div class="url-input-section">
@@ -241,6 +241,20 @@ export class ContainerView extends BaseView {
}
);
}
// 新增上传功能
function uploadContainer(containerId, containerName) {
showConfirmDialog(
'上传容器仓库',
'确定将此容器目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForContainerUpload',
containerId: containerId
});
}
);
}
// ======== Git 仓库 & 分支树 - ContainerView 作用域 ========
@@ -403,4 +417,4 @@ export class ContainerView extends BaseView {
</body>
</html>`;
}
}
}

View File

@@ -25,6 +25,7 @@ export class ProjectView extends BaseView {
</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>
@@ -213,7 +214,6 @@ export class ProjectView extends BaseView {
</tbody>
</table>
<!-- 项目云仓库 -->
<div class="config-section">
<h3 class="section-title">📚 项目云仓库</h3>
<div class="url-input-section">
@@ -289,6 +289,20 @@ export class ProjectView extends BaseView {
}
);
}
// 新增上传功能
function uploadProject(projectId, projectName) {
showConfirmDialog(
'上传项目仓库',
'确定将此项目目录(包括所有子文件夹和文件)上传到一个新的 Git 仓库分支吗?',
function() {
vscode.postMessage({
type: 'openRepoSelectForProjectUpload',
projectId: projectId
});
}
);
}
// 项目名称编辑功能
document.addEventListener('DOMContentLoaded', function() {
@@ -483,4 +497,4 @@ export class ProjectView extends BaseView {
</body>
</html>`;
}
}
}