fix: make backend/.env optional in compose.yml to fix first-run error on clean servers
This commit is contained in:
@@ -480,7 +480,8 @@ function onServerChange() {
|
||||
// ===== Nodes =====
|
||||
async function fetchNodes(serverId) {
|
||||
try {
|
||||
const data = await fetchWithAuth(`/proxmox/api/servers/${serverId}/cluster-info`);
|
||||
const resp = await fetchWithAuth(`/proxmox/api/servers/${serverId}/cluster-info`);
|
||||
const data = await resp.json();
|
||||
return (data.nodes || []).filter(Boolean);
|
||||
} catch { return []; }
|
||||
}
|
||||
@@ -495,7 +496,7 @@ function fillNodeSelect(selectId, nodes) {
|
||||
async function populateStorageDropdown(targetId = 'storageSelectBackups') {
|
||||
if (!currentServerId) return;
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`);
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`)).json();
|
||||
const backupStorages = (r.storages || []).filter(s => (s.content || '').includes('backup'));
|
||||
const sel = document.getElementById(targetId);
|
||||
sel.innerHTML = '<option value="">{{ t("select_storage") }}</option>';
|
||||
@@ -521,7 +522,7 @@ async function loadBackups() {
|
||||
let url = `/proxmox/api/backups/list/${currentServerId}?node=${node}&storage=${storage}`;
|
||||
if (vmid) url += `&vmid=${vmid}`;
|
||||
try {
|
||||
const r = await fetchWithAuth(url);
|
||||
const r = await (await fetchWithAuth(url)).json();
|
||||
const backups = r.backups || [];
|
||||
const tbody = document.getElementById('backupsTbody');
|
||||
if (!backups.length) { tbody.innerHTML = '<tr><td colspan="7" class="text-center py-3 text-muted">{{ t("backup_empty") }}</td></tr>'; return; }
|
||||
@@ -562,10 +563,10 @@ function formatSize(bytes) {
|
||||
async function deleteBackup(volid, node, storage) {
|
||||
if (!confirm('{{ t("backup_delete_confirm") }}')) return;
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/${currentServerId}/backup`, {
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/${currentServerId}/backup`, {
|
||||
method: 'DELETE',
|
||||
body: JSON.stringify({ node, storage, volid }),
|
||||
});
|
||||
})).json();
|
||||
if (r.success) { showToast('{{ t("success") }}', '{{ t("backup_deleted") }}', 'success'); loadBackups(); }
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
@@ -591,7 +592,7 @@ async function submitCreateBackup() {
|
||||
notes: document.getElementById('cbNotes').value || null,
|
||||
};
|
||||
try {
|
||||
const r = await fetchWithAuth('/proxmox/api/backups/create', { method: 'POST', body: JSON.stringify(payload) });
|
||||
const r = await (await fetchWithAuth('/proxmox/api/backups/create', { method: 'POST', body: JSON.stringify(payload) })).json();
|
||||
if (r.success) {
|
||||
bootstrap.Modal.getInstance(document.getElementById('createBackupModal'))?.hide();
|
||||
showToast('{{ t("success") }}', '{{ t("backup_started") }}', 'success');
|
||||
@@ -628,7 +629,7 @@ async function submitRestore() {
|
||||
unique: document.getElementById('restoreUnique').checked,
|
||||
};
|
||||
try {
|
||||
const r = await fetchWithAuth('/proxmox/api/backups/restore', { method: 'POST', body: JSON.stringify(payload) });
|
||||
const r = await (await fetchWithAuth('/proxmox/api/backups/restore', { method: 'POST', body: JSON.stringify(payload) })).json();
|
||||
if (r.success) {
|
||||
bootstrap.Modal.getInstance(document.getElementById('restoreModal'))?.hide();
|
||||
showToast('{{ t("success") }}', '{{ t("backup_restore_started") }}', 'success');
|
||||
@@ -646,7 +647,7 @@ async function openTaskLog(serverId, node, upid) {
|
||||
let done = false;
|
||||
while (!done) {
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/task/${serverId}/${node}/${encodeURIComponent(upid)}`);
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/task/${serverId}/${node}/${encodeURIComponent(upid)}`)).json();
|
||||
const status = r.status || {};
|
||||
const lines = (r.log || []).map(l => l.t || '').join('\n');
|
||||
document.getElementById('taskLogContent').textContent = lines;
|
||||
@@ -670,7 +671,7 @@ async function openTaskLog(serverId, node, upid) {
|
||||
async function loadStorages() {
|
||||
if (!currentServerId) { document.getElementById('storagesTbody').innerHTML = '<tr><td colspan="7" class="text-center py-3 text-muted">{{ t("select_server") }}</td></tr>'; return; }
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`);
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`)).json();
|
||||
const storages = r.storages || [];
|
||||
const tbody = document.getElementById('storagesTbody');
|
||||
if (!storages.length) { tbody.innerHTML = '<tr><td colspan="7" class="text-center py-3 text-muted">{{ t("backup_no_storages") }}</td></tr>'; return; }
|
||||
@@ -697,7 +698,7 @@ async function loadStorages() {
|
||||
async function deleteStorage(storageId) {
|
||||
if (!confirm('{{ t("backup_storage_delete_confirm") }}')) return;
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}/${storageId}`, { method: 'DELETE' });
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}/${storageId}`, { method: 'DELETE' })).json();
|
||||
if (r.success) { showToast('{{ t("success") }}', '{{ t("backup_storage_deleted") }}', 'success'); loadStorages(); }
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
@@ -731,7 +732,7 @@ async function submitAddStorage() {
|
||||
if (type === 'cifs') { payload.server = document.getElementById('asCifsServer').value; payload.share = document.getElementById('asCifsShare').value; payload.username = document.getElementById('asCifsUser').value; payload.password = document.getElementById('asCifsPass').value; }
|
||||
if (type === 'pbs') { payload.server = document.getElementById('asPbsServer').value; payload.datastore = document.getElementById('asPbsDatastore').value; payload.username = document.getElementById('asPbsUser').value; payload.password = document.getElementById('asPbsPass').value; if (document.getElementById('asPbsFingerprint').value) payload.fingerprint = document.getElementById('asPbsFingerprint').value; }
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`, { method: 'POST', body: JSON.stringify(payload) });
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/storages/${currentServerId}`, { method: 'POST', body: JSON.stringify(payload) })).json();
|
||||
if (r.success) { bootstrap.Modal.getInstance(document.getElementById('addStorageModal'))?.hide(); showToast('{{ t("success") }}', '{{ t("backup_storage_added") }}', 'success'); loadStorages(); }
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
@@ -739,7 +740,7 @@ async function submitAddStorage() {
|
||||
// ===== JOBS Tab =====
|
||||
async function loadJobs() {
|
||||
try {
|
||||
const r = await fetchWithAuth('/proxmox/api/backups/jobs');
|
||||
const r = await (await fetchWithAuth('/proxmox/api/backups/jobs')).json();
|
||||
const jobs = r.jobs || [];
|
||||
const tbody = document.getElementById('jobsTbody');
|
||||
if (!jobs.length) { tbody.innerHTML = '<tr><td colspan="8" class="text-center py-3 text-muted">{{ t("backup_no_jobs") }}</td></tr>'; return; }
|
||||
@@ -784,7 +785,7 @@ async function onJobServerChange(serverId) {
|
||||
|
||||
async function populateJobStorages(serverId) {
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/storages/${serverId}`);
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/storages/${serverId}`)).json();
|
||||
const backupStorages = (r.storages || []).filter(s => (s.content || '').includes('backup'));
|
||||
const sel = document.getElementById('ajStorage');
|
||||
sel.innerHTML = '';
|
||||
@@ -854,7 +855,7 @@ async function submitSaveJob() {
|
||||
try {
|
||||
const url = jobId ? `/proxmox/api/backups/jobs/${jobId}` : '/proxmox/api/backups/jobs';
|
||||
const method = jobId ? 'PUT' : 'POST';
|
||||
const r = await fetchWithAuth(url, { method, body: JSON.stringify(payload) });
|
||||
const r = await (await fetchWithAuth(url, { method, body: JSON.stringify(payload) })).json();
|
||||
if (r.success) {
|
||||
bootstrap.Modal.getInstance(document.getElementById('addJobModal'))?.hide();
|
||||
showToast('{{ t("success") }}', '{{ t("saved") }}', 'success');
|
||||
@@ -865,14 +866,14 @@ async function submitSaveJob() {
|
||||
|
||||
async function toggleJob(jobId) {
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}/toggle`, { method: 'PATCH' });
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}/toggle`, { method: 'PATCH' })).json();
|
||||
if (r.success) loadJobs();
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
|
||||
async function runJobNow(jobId) {
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}/run-now`, { method: 'POST' });
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}/run-now`, { method: 'POST' })).json();
|
||||
if (r.success) { showToast('{{ t("success") }}', '{{ t("backup_job_triggered") }}', 'success'); setTimeout(loadJobs, 2000); }
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
@@ -880,7 +881,7 @@ async function runJobNow(jobId) {
|
||||
async function deleteJob(jobId) {
|
||||
if (!confirm('{{ t("backup_job_delete_confirm") }}')) return;
|
||||
try {
|
||||
const r = await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}`, { method: 'DELETE' });
|
||||
const r = await (await fetchWithAuth(`/proxmox/api/backups/jobs/${jobId}`, { method: 'DELETE' })).json();
|
||||
if (r.success) { showToast('{{ t("success") }}', '{{ t("deleted") }}', 'success'); loadJobs(); }
|
||||
} catch(e) { showToast('{{ t("error") }}', e.message, 'danger'); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user