Добавил UI логику APK artifacts
Этот коммит содержится в:
@@ -140,6 +140,7 @@ async function streamRuntimeCommand(command, title, progress = 50) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ok) setError(`Ошибка: ${title || command}`);
|
if (!ok) setError(`Ошибка: ${title || command}`);
|
||||||
|
await loadApkArtifacts(false);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +167,7 @@ async function saveGitHubSettings() {
|
|||||||
function renderGroupedRuntimeButtons() {
|
function renderGroupedRuntimeButtons() {
|
||||||
const container = document.getElementById('runtimeButtons');
|
const container = document.getElementById('runtimeButtons');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
container.innerHTML = `<button onclick="runRuntimeScenario('check')">Проверить</button><button onclick="runRuntimeScenario('run_profile')">Запустить</button><button onclick="runRuntimeScenario('build')">Собрать APK</button><button onclick="runRuntimeScenario('install')">Установить APK</button><button onclick="runRuntimeScenario('diagnostics')">Диагностика</button>`;
|
container.innerHTML = `<button onclick="runRuntimeScenario('check')">Проверить</button><button onclick="runRuntimeScenario('run_profile')">Запустить</button><button onclick="runRuntimeScenario('build')">Собрать APK</button><button onclick="runRuntimeScenario('install')">Установить APK</button><button onclick="runRuntimeScenario('diagnostics')">Диагностика</button><button class="muted" onclick="loadApkArtifacts(true)">APK файлы</button>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadRuntimeCommands() { renderGroupedRuntimeButtons(); setStatus('Runtime сценарии готовы', 'done'); }
|
async function loadRuntimeCommands() { renderGroupedRuntimeButtons(); setStatus('Runtime сценарии готовы', 'done'); }
|
||||||
@@ -177,7 +178,7 @@ async function runRuntimeScenario(scenario) {
|
|||||||
if (!workspace) { setError('Workspace не выбран'); return; }
|
if (!workspace) { setError('Workspace не выбран'); return; }
|
||||||
if (scenario === 'check') { setBusy('Проверка проекта'); if (!await executeRuntimeCommand('git_pull', 'Git Pull', 25)) return; if (!await executeRuntimeCommand('flutter_pub_get', 'Flutter Pub Get', 70)) return; setDone('Проверка завершена'); return; }
|
if (scenario === 'check') { setBusy('Проверка проекта'); if (!await executeRuntimeCommand('git_pull', 'Git Pull', 25)) return; if (!await executeRuntimeCommand('flutter_pub_get', 'Flutter Pub Get', 70)) return; setDone('Проверка завершена'); return; }
|
||||||
if (scenario === 'run_profile') { if (!getSelectedDevice()) { setError('Устройство не выбрано'); return; } setBusy('Запуск на телефоне'); if (!await executeRuntimeCommand('flutter_pub_get', 'Подготовка зависимостей', 30)) return; if (!await executeRuntimeCommand('flutter_run_profile', 'Flutter Run --profile', 75)) return; setDone('Запуск завершён'); return; }
|
if (scenario === 'run_profile') { if (!getSelectedDevice()) { setError('Устройство не выбрано'); return; } setBusy('Запуск на телефоне'); if (!await executeRuntimeCommand('flutter_pub_get', 'Подготовка зависимостей', 30)) return; if (!await executeRuntimeCommand('flutter_run_profile', 'Flutter Run --profile', 75)) return; setDone('Запуск завершён'); return; }
|
||||||
if (scenario === 'build') { setBusy('Сборка APK'); if (!await executeRuntimeCommand('flutter_clean', 'Flutter Clean', 20)) return; if (!await executeRuntimeCommand('flutter_pub_get', 'Flutter Pub Get', 45)) return; if (!await executeRuntimeCommand('flutter_build_apk', 'Flutter Build APK', 80)) return; setDone('Сборка APK завершена'); return; }
|
if (scenario === 'build') { setBusy('Сборка APK'); if (!await executeRuntimeCommand('flutter_clean', 'Flutter Clean', 20)) return; if (!await executeRuntimeCommand('flutter_pub_get', 'Flutter Pub Get', 45)) return; if (!await executeRuntimeCommand('flutter_build_apk', 'Flutter Build APK', 80)) return; setDone('Сборка APK завершена'); await loadApkArtifacts(false); return; }
|
||||||
if (scenario === 'install') { setBusy('Установка APK'); await installLatestApk(); return; }
|
if (scenario === 'install') { setBusy('Установка APK'); await installLatestApk(); return; }
|
||||||
if (scenario === 'diagnostics') { setBusy('Диагностика Android runtime'); if (!await executeRuntimeCommand('adb_reconnect', 'ADB Reconnect', 40)) return; if (!await executeRuntimeCommand('adb_logcat', 'ADB Logcat Snapshot', 80)) return; setDone('Диагностика завершена'); }
|
if (scenario === 'diagnostics') { setBusy('Диагностика Android runtime'); if (!await executeRuntimeCommand('adb_reconnect', 'ADB Reconnect', 40)) return; if (!await executeRuntimeCommand('adb_logcat', 'ADB Logcat Snapshot', 80)) return; setDone('Диагностика завершена'); }
|
||||||
}
|
}
|
||||||
@@ -197,6 +198,7 @@ async function installLatestApk() {
|
|||||||
if (data.result?.stdout) appendRuntimeLog(data.result.stdout);
|
if (data.result?.stdout) appendRuntimeLog(data.result.stdout);
|
||||||
if (data.result?.stderr) appendRuntimeLog(data.result.stderr);
|
if (data.result?.stderr) appendRuntimeLog(data.result.stderr);
|
||||||
if (data.success) setDone('APK установлен'); else setError('Ошибка установки APK');
|
if (data.success) setDone('APK установлен'); else setError('Ошибка установки APK');
|
||||||
|
await loadApkArtifacts(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function restartCurrentApp() {
|
async function restartCurrentApp() {
|
||||||
@@ -212,6 +214,45 @@ async function restartCurrentApp() {
|
|||||||
if (data.success) setDone('Приложение перезапущено'); else setError('Ошибка перезапуска приложения');
|
if (data.success) setDone('Приложение перезапущено'); else setError('Ошибка перезапуска приложения');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function humanFileSize(bytes) {
|
||||||
|
const value = Number(bytes || 0);
|
||||||
|
if (value < 1024) return `${value} B`;
|
||||||
|
if (value < 1024 * 1024) return `${(value / 1024).toFixed(1)} KB`;
|
||||||
|
return `${(value / 1024 / 1024).toFixed(1)} MB`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderApkArtifacts(apks, directory) {
|
||||||
|
const box = document.getElementById('apkArtifactsList');
|
||||||
|
const meta = document.getElementById('apkArtifactsMeta');
|
||||||
|
if (!box) return;
|
||||||
|
if (meta) meta.innerText = directory || 'build/app/outputs/flutter-apk';
|
||||||
|
if (!apks || apks.length === 0) {
|
||||||
|
box.innerHTML = '<div class="note">APK пока нет. Выполни “Собрать APK”, потом обнови список.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
box.innerHTML = apks.map(apk => {
|
||||||
|
const modified = apk.mtime ? new Date(apk.mtime * 1000).toLocaleString() : '';
|
||||||
|
const openUrl = encodeURI(apk.open_url);
|
||||||
|
const downloadUrl = encodeURI(apk.download_url);
|
||||||
|
return `<div class="apk-card"><div class="apk-info"><strong>${apk.name}</strong><small>${apk.relative_path}</small><small>${humanFileSize(apk.size_bytes)} · ${modified}</small></div><div class="apk-actions"><button class="mini-btn" onclick="window.open('${openUrl}','_blank')">Открыть</button><a class="button-link" href="${downloadUrl}">Скачать</a></div></div>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadApkArtifacts(verbose = true) {
|
||||||
|
const workspace = getWorkspacePath();
|
||||||
|
const box = document.getElementById('apkArtifactsList');
|
||||||
|
if (!box) return;
|
||||||
|
if (!workspace) {
|
||||||
|
box.innerHTML = '<div class="note">Сначала выбери проект.</div>';
|
||||||
|
if (verbose) setError('Workspace не выбран');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verbose) appendLog('📦 Обновляю APK файлы');
|
||||||
|
const data = await workspaceApi(`/api/android/apks?workspace=${encodeURIComponent(workspace)}`, {}, 'GET');
|
||||||
|
if (data.success) renderApkArtifacts(data.apks || [], data.directory || '');
|
||||||
|
else box.innerHTML = '<div class="note">Не удалось загрузить APK файлы.</div>';
|
||||||
|
}
|
||||||
|
|
||||||
async function loadProjects() {
|
async function loadProjects() {
|
||||||
const container = document.getElementById('projectsList');
|
const container = document.getElementById('projectsList');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
@@ -231,6 +272,7 @@ function openProject(workspace, name = 'project') {
|
|||||||
appendLog(`Открытие проекта: ${workspace}`);
|
appendLog(`Открытие проекта: ${workspace}`);
|
||||||
setTaskProgress(100, `Проект выбран: ${name}`, false);
|
setTaskProgress(100, `Проект выбран: ${name}`, false);
|
||||||
setStatus(`Проект готов: ${name}`, 'done');
|
setStatus(`Проект готов: ${name}`, 'done');
|
||||||
|
loadApkArtifacts(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openEditProjectModal(workspace) {
|
async function openEditProjectModal(workspace) {
|
||||||
@@ -254,7 +296,7 @@ async function openEditProjectModal(workspace) {
|
|||||||
document.getElementById('otaBuild').value = ota.build || '';
|
document.getElementById('otaBuild').value = ota.build || '';
|
||||||
document.getElementById('otaNotes').value = ota.notes || '';
|
document.getElementById('otaNotes').value = ota.notes || '';
|
||||||
toggleOtaFields();
|
toggleOtaFields();
|
||||||
modal.style.display = 'flex';
|
if (modal) modal.style.display = 'flex';
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeEditProjectModal() { document.getElementById('editProjectModal').style.display = 'none'; }
|
function closeEditProjectModal() { document.getElementById('editProjectModal').style.display = 'none'; }
|
||||||
@@ -304,6 +346,14 @@ async function loadDevices() {
|
|||||||
setStatus(`Android устройства найдены: ${devices.length}`, 'done');
|
setStatus(`Android устройства найдены: ${devices.length}`, 'done');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openAddProjectModal(){document.getElementById('addProjectModal').style.display='flex';}
|
||||||
|
function closeAddProjectModal(){document.getElementById('addProjectModal').style.display='none';}
|
||||||
|
function toggleAuthFields(){document.getElementById('authFields').style.display=document.getElementById('repoNeedsAuth').checked?'block':'none';}
|
||||||
|
function toggleOtaFields(){document.getElementById('otaFields').style.display=document.getElementById('otaEnabled').checked?'block':'none';}
|
||||||
|
async function syncPubspecVersion(){const workspace=document.getElementById('editWorkspace').value;if(!workspace){appendLog('Workspace не выбран');return;}appendLog('📦 Читаю pubspec.yaml');const data=await workspaceApi(`/api/projects/pubspec-version?workspace=${encodeURIComponent(workspace)}`,{},'GET');if(data.version){document.getElementById('otaVersion').value=data.version;document.getElementById('otaBuild').value=data.build;appendLog(`✅ Pubspec version synced: ${data.full_version}`);}else{appendLog('❌ Не удалось считать pubspec.yaml');}}
|
||||||
|
function setAnalysisProgress(percent,message){const wrap=document.getElementById('analysisProgressWrap');const bar=document.getElementById('analysisProgressBar');const label=document.getElementById('analysisProgressLabel');if(wrap){wrap.style.display='block';}if(bar){bar.style.width=percent+'%';}if(label){label.innerText=percent+'% — '+message;}appendLog(percent+'% — '+message);}
|
||||||
|
async function analyzeProject(){const repo_url=document.getElementById('repoUrl').value.trim();if(!repo_url){appendLog('0% — Укажи Git URL');return;}if(document.getElementById('repoNeedsAuth').checked){await saveGitHubSettings();}setAnalysisProgress(5,'Проверяю Git URL');setAnalysisProgress(20,'Готовлю workspace');setAnalysisProgress(35,'Клонирую или обновляю репозиторий');const data=await workspaceApi('/api/projects/analyze',{repo_url});if(data.detail){setAnalysisProgress(100,'Ошибка анализа: '+data.detail);return;}setAnalysisProgress(65,'Репозиторий получен, сканирую структуру');if(data.analysis?.detected_stack?.length){setAnalysisProgress(76,'Стек: '+data.analysis.detected_stack.join(', '));}else{setAnalysisProgress(76,'Стек не определён автоматически');}if(data.analysis?.workspace){setAnalysisProgress(88,'Workspace: '+data.analysis.workspace);document.getElementById('workspacePath').value=data.analysis.workspace;setAnalysisProgress(94,'Регистрирую проект');await registerCurrentProject(repo_url,data.analysis.workspace,data.analysis.detected_stack?.join(', ')||'unknown');}setAnalysisProgress(100,'Проект добавлен');closeAddProjectModal();}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
setStatus('Запуск DevConsole runtime', 'running');
|
setStatus('Запуск DevConsole runtime', 'running');
|
||||||
appendLog('DevConsole runtime initialized...');
|
appendLog('DevConsole runtime initialized...');
|
||||||
@@ -311,5 +361,6 @@ window.addEventListener('load', () => {
|
|||||||
loadDevices();
|
loadDevices();
|
||||||
loadProjects();
|
loadProjects();
|
||||||
loadRuntimeCommands();
|
loadRuntimeCommands();
|
||||||
|
renderApkArtifacts([], 'build/app/outputs/flutter-apk');
|
||||||
appendLog('DevConsole workspace runtime готов');
|
appendLog('DevConsole workspace runtime готов');
|
||||||
});
|
});
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user