给项目页面、飞行器页面
This commit is contained in:
@@ -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
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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"}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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"}
|
||||
@@ -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 作用域 ========
|
||||
|
||||
|
||||
@@ -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"}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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"}
|
||||
@@ -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 {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user