fix(dashboard): ralph.html URL prefix /echo/api/ralph (was /api/ralph → 502)

Tailscale Serve mapează /echo/* → 127.0.0.1:8088 (dashboard) și / →
:18789 (alt backend). Browser-ul calling /api/ralph/status (relative cu
absolute path la root domain) ajungea la 18789 care nu are endpoint Ralph
→ 502 Bad Gateway.

Fix: toate cele 6 URL-uri (5x fetch + 1x EventSource) folosesc acum prefix
/echo/api/ralph/* pentru a respecta routing-ul tailscale. Pattern consistent
cu workspace.html și index.html (verificat manual).

Endpoints atinse: /status, /<slug>/log, /<slug>/prd, /<slug>/stop,
/<slug>/rollback, /stream (SSE).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-27 05:18:01 +00:00
parent 44c9bb4e61
commit 2830bf48f2

View File

@@ -569,7 +569,7 @@
async function fetchStatus() { async function fetchStatus() {
try { try {
const res = await fetch('/api/ralph/status', { cache: 'no-store' }); const res = await fetch('/echo/api/ralph/status', { cache: 'no-store' });
if (!res.ok) throw new Error('HTTP ' + res.status); if (!res.ok) throw new Error('HTTP ' + res.status);
const data = await res.json(); const data = await res.json();
renderSnapshot(data); renderSnapshot(data);
@@ -585,7 +585,7 @@
drawerBody.textContent = 'Se încarcă...'; drawerBody.textContent = 'Se încarcă...';
drawer.dataset.open = 'true'; drawer.dataset.open = 'true';
try { try {
const res = await fetch(`/api/ralph/${encodeURIComponent(slug)}/log?lines=200`); const res = await fetch(`/echo/api/ralph/${encodeURIComponent(slug)}/log?lines=200`);
const data = await res.json(); const data = await res.json();
drawerBody.textContent = (data.lines || []).join('\n'); drawerBody.textContent = (data.lines || []).join('\n');
} catch (err) { } catch (err) {
@@ -598,7 +598,7 @@
drawerBody.textContent = 'Se încarcă...'; drawerBody.textContent = 'Se încarcă...';
drawer.dataset.open = 'true'; drawer.dataset.open = 'true';
try { try {
const res = await fetch(`/api/ralph/${encodeURIComponent(slug)}/prd`); const res = await fetch(`/echo/api/ralph/${encodeURIComponent(slug)}/prd`);
const data = await res.json(); const data = await res.json();
drawerBody.textContent = JSON.stringify(data, null, 2); drawerBody.textContent = JSON.stringify(data, null, 2);
} catch (err) { } catch (err) {
@@ -609,7 +609,7 @@
async function stopRalph(slug) { async function stopRalph(slug) {
if (!confirm(`Oprești Ralph pe ${slug}?`)) return; if (!confirm(`Oprești Ralph pe ${slug}?`)) return;
try { try {
const res = await fetch(`/api/ralph/${encodeURIComponent(slug)}/stop`, { method: 'POST' }); const res = await fetch(`/echo/api/ralph/${encodeURIComponent(slug)}/stop`, { method: 'POST' });
const data = await res.json(); const data = await res.json();
if (!data.success) { if (!data.success) {
alert('Eșec: ' + (data.error || 'unknown')); alert('Eșec: ' + (data.error || 'unknown'));
@@ -624,7 +624,7 @@
async function rollbackRalph(slug) { async function rollbackRalph(slug) {
if (!confirm(`Asta va da git revert HEAD pe ${slug} și va decrementa ultima story trecută. Continui?`)) return; if (!confirm(`Asta va da git revert HEAD pe ${slug} și va decrementa ultima story trecută. Continui?`)) return;
try { try {
const res = await fetch(`/api/ralph/${encodeURIComponent(slug)}/rollback`, { method: 'POST' }); const res = await fetch(`/echo/api/ralph/${encodeURIComponent(slug)}/rollback`, { method: 'POST' });
const data = await res.json(); const data = await res.json();
if (!data.success) { if (!data.success) {
alert('Rollback eşuat: ' + (data.message || 'unknown')); alert('Rollback eşuat: ' + (data.message || 'unknown'));
@@ -686,7 +686,7 @@
return; return;
} }
try { try {
eventSource = new EventSource('/api/ralph/stream'); eventSource = new EventSource('/echo/api/ralph/stream');
} catch (err) { } catch (err) {
startPolling(); startPolling();
return; return;