Update coolify.html
This commit is contained in:
@@ -87,7 +87,7 @@
|
||||
</div>
|
||||
<span :class="statusClass(app.status)"
|
||||
class="text-xs px-2 py-0.5 rounded-full font-medium shrink-0"
|
||||
x-text="statusLabel(app.status)">
|
||||
x-text="actionStatusText(app.uuid, app.status)">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
<!-- Spinner de acción individual -->
|
||||
<div x-show="actionLoading[app.uuid]" class="text-xs text-indigo-500 flex items-center gap-1">
|
||||
<svg class="animate-spin h-3 w-3" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
|
||||
Procesando...
|
||||
<span x-text="actionSpinnerText(app.uuid)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -230,7 +230,7 @@
|
||||
</div>
|
||||
<span :class="statusClass(svc.status)"
|
||||
class="text-xs px-2 py-0.5 rounded-full font-medium shrink-0"
|
||||
x-text="statusLabel(svc.status)">
|
||||
x-text="actionStatusText(svc.uuid, svc.status)">
|
||||
</span>
|
||||
</div>
|
||||
<div x-show="svc.description" class="text-xs text-gray-500" x-text="svc.description"></div>
|
||||
@@ -249,7 +249,7 @@
|
||||
</div>
|
||||
<div x-show="actionLoading[svc.uuid]" class="text-xs text-indigo-500 flex items-center gap-1">
|
||||
<svg class="animate-spin h-3 w-3" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
|
||||
Procesando...
|
||||
<span x-text="actionSpinnerText(svc.uuid)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -269,7 +269,7 @@
|
||||
</div>
|
||||
<span :class="statusClass(db.status)"
|
||||
class="text-xs px-2 py-0.5 rounded-full font-medium shrink-0"
|
||||
x-text="statusLabel(db.status)">
|
||||
x-text="actionStatusText(db.uuid, db.status)">
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-500 space-y-0.5">
|
||||
@@ -289,7 +289,7 @@
|
||||
</div>
|
||||
<div x-show="actionLoading[db.uuid]" class="text-xs text-indigo-500 flex items-center gap-1">
|
||||
<svg class="animate-spin h-3 w-3" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/></svg>
|
||||
Procesando...
|
||||
<span x-text="actionSpinnerText(db.uuid)"></span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -489,10 +489,10 @@
|
||||
<div class="flex-1 overflow-auto p-5 space-y-2">
|
||||
<div x-show="envsLoading" class="text-sm text-gray-400 text-center py-4">Cargando variables...</div>
|
||||
<div x-show="!envsLoading && envsList.length === 0" class="text-sm text-gray-400 text-center py-4">Sin variables de entorno.</div>
|
||||
<template x-for="env in envsList" :key="env.id">
|
||||
<template x-for="env in envsList" :key="env.id || env.uuid || env.key || env.name || env">
|
||||
<div class="flex items-center gap-3 bg-gray-50 rounded-lg px-3 py-2 text-sm">
|
||||
<span class="font-mono font-semibold text-gray-700 w-40 shrink-0 truncate" x-text="env.key"></span>
|
||||
<span class="font-mono text-gray-500 flex-1 truncate" x-text="env.is_shown_once ? '••••••••' : (env.value || '')"></span>
|
||||
<span class="font-mono font-semibold text-gray-700 w-40 shrink-0 truncate" x-text="env.key || env.name || '—'"></span>
|
||||
<span class="font-mono text-gray-500 flex-1 truncate" x-text="(env.is_shown_once || env.is_masked) ? '••••••••' : (env.value || '')"></span>
|
||||
<span x-show="env.is_preview" class="text-xs px-1.5 py-0.5 bg-blue-100 text-blue-600 rounded">Preview</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -677,6 +677,7 @@ document.addEventListener('alpine:init', () => {
|
||||
|
||||
// Action loading by uuid
|
||||
actionLoading: {},
|
||||
actionPhase: {},
|
||||
|
||||
// ─── Config modal ─────────────────────────────
|
||||
configModal: false,
|
||||
@@ -744,6 +745,34 @@ document.addEventListener('alpine:init', () => {
|
||||
return env.description || env.branch || env.fqdn || env.url || '';
|
||||
},
|
||||
|
||||
actionTextFor(action) {
|
||||
const map = {
|
||||
start: 'iniciando',
|
||||
stop: 'deteniendo',
|
||||
restart: 'reiniciando',
|
||||
deploy: 'desplegando',
|
||||
};
|
||||
return map[action] || 'procesando';
|
||||
},
|
||||
|
||||
actionStatusText(uuid, status) {
|
||||
return this.actionPhase[uuid] || this.statusLabel(status);
|
||||
},
|
||||
|
||||
actionSpinnerText(uuid) {
|
||||
return this.actionPhase[uuid] || 'procesando';
|
||||
},
|
||||
|
||||
clearActionState(uuid) {
|
||||
const nextLoading = { ...this.actionLoading };
|
||||
delete nextLoading[uuid];
|
||||
this.actionLoading = nextLoading;
|
||||
|
||||
const nextPhase = { ...this.actionPhase };
|
||||
delete nextPhase[uuid];
|
||||
this.actionPhase = nextPhase;
|
||||
},
|
||||
|
||||
flash(msg, ok = true) {
|
||||
this.flashMsg = msg;
|
||||
this.flashOk = ok;
|
||||
@@ -967,7 +996,8 @@ document.addEventListener('alpine:init', () => {
|
||||
try {
|
||||
const r = await fetch('/app/coolify/deployments');
|
||||
const j = await r.json();
|
||||
this.deployments = Array.isArray(j) ? j : (j.data || []);
|
||||
this.deployments = Array.isArray(j) ? j
|
||||
: (j.deployments || j.items || j.data || j.result || j.deployments_list || []);
|
||||
this.lastFetch = this.fmtDate(new Date().toISOString());
|
||||
} catch(e) { this.flash('Error cargando despliegues: ' + e.message, false); }
|
||||
finally { this.loading = false; }
|
||||
@@ -994,20 +1024,25 @@ document.addEventListener('alpine:init', () => {
|
||||
const prev = { ...this.actionLoading };
|
||||
prev[uuid] = true;
|
||||
this.actionLoading = prev;
|
||||
const phase = this.actionTextFor(action);
|
||||
this.actionPhase = { ...this.actionPhase, [uuid]: phase };
|
||||
let clearNow = true;
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/apps/${uuid}/${action}`);
|
||||
const j = await r.json();
|
||||
if (r.ok) {
|
||||
this.flash(`App ${action} iniciado correctamente.`);
|
||||
setTimeout(() => this.loadApps(), 2000);
|
||||
clearNow = false;
|
||||
this.flash(`App ${phase} correctamente.`);
|
||||
setTimeout(async () => {
|
||||
await this.loadApps();
|
||||
this.clearActionState(uuid);
|
||||
}, 2000);
|
||||
} else {
|
||||
this.flash((j.message || j.error || `Error en ${action}`), false);
|
||||
}
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally {
|
||||
const next = { ...this.actionLoading };
|
||||
next[uuid] = false;
|
||||
this.actionLoading = next;
|
||||
if (clearNow) this.clearActionState(uuid);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1015,19 +1050,21 @@ document.addEventListener('alpine:init', () => {
|
||||
const prev = { ...this.actionLoading };
|
||||
prev[uuid] = true;
|
||||
this.actionLoading = prev;
|
||||
this.actionPhase = { ...this.actionPhase, [uuid]: this.actionTextFor('deploy') };
|
||||
let clearNow = true;
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/apps/${uuid}/deploy`, { method: 'POST' });
|
||||
const j = await r.json();
|
||||
if (r.ok) {
|
||||
clearNow = false;
|
||||
this.flash('Deploy disparado correctamente.');
|
||||
setTimeout(() => this.clearActionState(uuid), 3000);
|
||||
} else {
|
||||
this.flash((j.message || j.error || 'Error al hacer deploy'), false);
|
||||
}
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally {
|
||||
const next = { ...this.actionLoading };
|
||||
next[uuid] = false;
|
||||
this.actionLoading = next;
|
||||
if (clearNow) this.clearActionState(uuid);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1070,7 +1107,7 @@ document.addEventListener('alpine:init', () => {
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/apps/${app.uuid}/envs`);
|
||||
const j = await r.json();
|
||||
this.envsList = Array.isArray(j) ? j : (j.data || []);
|
||||
this.envsList = Array.isArray(j) ? j : (j.data || j.variables || j.envs || j.items || j.environment_variables || []);
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally { this.envsLoading = false; }
|
||||
},
|
||||
@@ -1085,7 +1122,7 @@ document.addEventListener('alpine:init', () => {
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/services/${svc.uuid}/envs`);
|
||||
const j = await r.json();
|
||||
this.envsList = Array.isArray(j) ? j : (j.data || []);
|
||||
this.envsList = Array.isArray(j) ? j : (j.data || j.variables || j.envs || j.items || j.environment_variables || []);
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally { this.envsLoading = false; }
|
||||
},
|
||||
@@ -1110,7 +1147,7 @@ document.addEventListener('alpine:init', () => {
|
||||
// Recargar lista
|
||||
const r2 = await fetch(endpoint.replace(/\/envs$/, '/envs'));
|
||||
const j2 = await r2.json();
|
||||
this.envsList = Array.isArray(j2) ? j2 : (j2.data || []);
|
||||
this.envsList = Array.isArray(j2) ? j2 : (j2.data || j2.variables || j2.envs || j2.items || j2.environment_variables || []);
|
||||
} else {
|
||||
this.flash(j.message || j.error || 'Error al crear variable.', false);
|
||||
}
|
||||
@@ -1127,10 +1164,16 @@ document.addEventListener('alpine:init', () => {
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/apps/${app.uuid}/deployments`);
|
||||
const j = await r.json();
|
||||
this.appDeploymentsList = Array.isArray(j) ? j : (j.data || []);
|
||||
let list = Array.isArray(j) ? j
|
||||
: (j.deployments || j.items || j.data || j.result || j.deployments_list || []);
|
||||
// Si la respuesta es vacía pero tiene data a nivel superior, prueba parsear como objeto wrapper
|
||||
if (!Array.isArray(list) && typeof list === 'object' && list !== null) {
|
||||
list = Object.values(list).filter(v => Array.isArray(v))[0] || [];
|
||||
}
|
||||
this.appDeploymentsList = Array.isArray(list) ? list : [];
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally { this.appDeploymentsLoading = false; }
|
||||
},
|
||||
}
|
||||
|
||||
// ─── Deployment log ──────────────────────────────
|
||||
openDeploymentLog(dep) {
|
||||
@@ -1143,20 +1186,25 @@ document.addEventListener('alpine:init', () => {
|
||||
const prev = { ...this.actionLoading };
|
||||
prev[uuid] = true;
|
||||
this.actionLoading = prev;
|
||||
const phase = this.actionTextFor(action);
|
||||
this.actionPhase = { ...this.actionPhase, [uuid]: phase };
|
||||
let clearNow = true;
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/services/${uuid}/${action}`);
|
||||
const j = await r.json();
|
||||
if (r.ok) {
|
||||
this.flash(`Servicio ${action} iniciado.`);
|
||||
setTimeout(() => this.loadServices(), 2000);
|
||||
clearNow = false;
|
||||
this.flash(`Servicio ${phase} correctamente.`);
|
||||
setTimeout(async () => {
|
||||
await this.loadServices();
|
||||
this.clearActionState(uuid);
|
||||
}, 2000);
|
||||
} else {
|
||||
this.flash(j.message || j.error || `Error en ${action}`, false);
|
||||
}
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally {
|
||||
const next = { ...this.actionLoading };
|
||||
next[uuid] = false;
|
||||
this.actionLoading = next;
|
||||
if (clearNow) this.clearActionState(uuid);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1165,20 +1213,25 @@ document.addEventListener('alpine:init', () => {
|
||||
const prev = { ...this.actionLoading };
|
||||
prev[uuid] = true;
|
||||
this.actionLoading = prev;
|
||||
const phase = this.actionTextFor(action);
|
||||
this.actionPhase = { ...this.actionPhase, [uuid]: phase };
|
||||
let clearNow = true;
|
||||
try {
|
||||
const r = await fetch(`/app/coolify/databases/${uuid}/${action}`);
|
||||
const j = await r.json();
|
||||
if (r.ok) {
|
||||
this.flash(`Base de datos ${action} iniciado.`);
|
||||
setTimeout(() => this.loadDatabases(), 2000);
|
||||
clearNow = false;
|
||||
this.flash(`Base de datos ${phase} correctamente.`);
|
||||
setTimeout(async () => {
|
||||
await this.loadDatabases();
|
||||
this.clearActionState(uuid);
|
||||
}, 2000);
|
||||
} else {
|
||||
this.flash(j.message || j.error || `Error en ${action}`, false);
|
||||
}
|
||||
} catch(e) { this.flash('Error: ' + e.message, false); }
|
||||
finally {
|
||||
const next = { ...this.actionLoading };
|
||||
next[uuid] = false;
|
||||
this.actionLoading = next;
|
||||
if (clearNow) this.clearActionState(uuid);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user