Skip to content

Commit 986c8ef

Browse files
committed
render logo as file instead of bas64 and show uptime
1 parent eab9aa1 commit 986c8ef

File tree

3 files changed

+40
-45
lines changed

3 files changed

+40
-45
lines changed

pkg/api/logs_handler.go

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
package api
33

44
import (
5-
"encoding/base64"
65
"encoding/json"
76
"net/http"
87
"strconv"
@@ -206,26 +205,19 @@ func (h *LogsHandler) HandleGetAllLogs(w http.ResponseWriter, r *http.Request) {
206205
}
207206
}
208207

209-
// HandleGetLogo returns the logo as base64-encoded PNG
210-
// GET /api/logo
208+
// HandleGetLogo returns the logo PNG file
209+
// GET /static/logo.png
211210
func (h *LogsHandler) HandleGetLogo(w http.ResponseWriter, r *http.Request) {
212-
if r.Method != http.MethodGet {
211+
if r.Method != http.MethodGet && r.Method != http.MethodHead {
213212
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
214213
return
215214
}
216215

217-
logoBase64 := base64.StdEncoding.EncodeToString(ui.LogoPNG)
218-
219-
response := map[string]interface{}{
220-
"logo": logoBase64,
221-
"type": "image/png",
222-
}
223-
224-
w.Header().Set("Content-Type", "application/json")
225-
if err := json.NewEncoder(w).Encode(response); err != nil {
226-
h.logger.Error("failed to encode logo response", err)
227-
http.Error(w, "Internal server error", http.StatusInternalServerError)
228-
return
216+
w.Header().Set("Content-Type", "image/png")
217+
w.Header().Set("Cache-Control", "public, max-age=3600") // Cache for 1 hour
218+
w.WriteHeader(http.StatusOK)
219+
if r.Method != http.MethodHead {
220+
w.Write(ui.LogoPNG)
229221
}
230222
}
231223

@@ -268,7 +260,6 @@ func (h *LogsHandler) RegisterRoutes(mux *http.ServeMux) {
268260
mux.HandleFunc("/api/logs/since", h.HandleGetLogsSince)
269261
mux.HandleFunc("/api/logs/stats", h.HandleGetStats)
270262
mux.HandleFunc("/api/logs/clear", h.HandleClearLogs)
271-
mux.HandleFunc("/api/logo", h.HandleGetLogo)
272263

273264
h.logger.Info("log API routes registered",
274265
"endpoints", []string{
@@ -277,7 +268,6 @@ func (h *LogsHandler) RegisterRoutes(mux *http.ServeMux) {
277268
"GET /api/logs/since",
278269
"GET /api/logs/stats",
279270
"DELETE /api/logs/clear",
280-
"GET /api/logo",
281271
})
282272
}
283273

@@ -290,7 +280,6 @@ func (h *LogsHandler) RegisterRoutesWithPrefix(mux *http.ServeMux, prefix string
290280
mux.HandleFunc(prefix+"/api/logs/since", h.HandleGetLogsSince)
291281
mux.HandleFunc(prefix+"/api/logs/stats", h.HandleGetStats)
292282
mux.HandleFunc(prefix+"/api/logs/clear", h.HandleClearLogs)
293-
mux.HandleFunc(prefix+"/api/logo", h.HandleGetLogo)
294283

295284
h.logger.Info("log API routes registered with prefix",
296285
"prefix", prefix,
@@ -300,7 +289,6 @@ func (h *LogsHandler) RegisterRoutesWithPrefix(mux *http.ServeMux, prefix string
300289
"GET " + prefix + "/api/logs/since",
301290
"GET " + prefix + "/api/logs/stats",
302291
"DELETE " + prefix + "/api/logs/clear",
303-
"GET " + prefix + "/api/logo",
304292
})
305293
}
306294

@@ -324,7 +312,7 @@ func (h *LogsHandler) RegisterInterimRoutes(mux *http.ServeMux, basePath string)
324312
mux.HandleFunc(basePath+"/api/logs/since", h.HandleGetLogsSince)
325313
mux.HandleFunc(basePath+"/api/logs/stats", h.HandleGetStats)
326314
mux.HandleFunc(basePath+"/api/logs/clear", h.HandleClearLogs)
327-
mux.HandleFunc(basePath+"/api/logo", h.HandleGetLogo)
315+
mux.HandleFunc(basePath+"/static/logo.png", h.HandleGetLogo)
328316
mux.HandleFunc(basePath+"/static/logs.css", h.HandleGetCSS)
329317
mux.HandleFunc(basePath+"/static/logs.js", h.HandleGetJS)
330318

@@ -336,7 +324,7 @@ func (h *LogsHandler) RegisterInterimRoutes(mux *http.ServeMux, basePath string)
336324
"GET " + basePath + "/api/logs/since",
337325
"GET " + basePath + "/api/logs/stats",
338326
"DELETE " + basePath + "/api/logs/clear",
339-
"GET " + basePath + "/api/logo",
327+
"GET " + basePath + "/static/logo.png",
340328
"GET " + basePath + "/static/logs.css",
341329
"GET " + basePath + "/static/logs.js",
342330
})
@@ -358,9 +346,9 @@ func (h *LogsHandler) RegisterInterimRoutesWithAuth(mux *http.ServeMux, basePath
358346
mux.Handle(basePath+"/api/logs/since", oauthMW.Wrap(http.HandlerFunc(h.HandleGetLogsSince)))
359347
mux.Handle(basePath+"/api/logs/stats", oauthMW.Wrap(http.HandlerFunc(h.HandleGetStats)))
360348
mux.Handle(basePath+"/api/logs/clear", oauthMW.Wrap(http.HandlerFunc(h.HandleClearLogs)))
361-
mux.Handle(basePath+"/api/logo", oauthMW.Wrap(http.HandlerFunc(h.HandleGetLogo)))
362349

363-
// Static assets are not protected - they're just CSS/JS files
350+
// Static assets are not protected - they're just CSS/JS/image files
351+
mux.HandleFunc(basePath+"/static/logo.png", h.HandleGetLogo)
364352
mux.HandleFunc(basePath+"/static/logs.css", h.HandleGetCSS)
365353
mux.HandleFunc(basePath+"/static/logs.js", h.HandleGetJS)
366354

@@ -372,7 +360,7 @@ func (h *LogsHandler) RegisterInterimRoutesWithAuth(mux *http.ServeMux, basePath
372360
"GET " + basePath + "/api/logs/since",
373361
"GET " + basePath + "/api/logs/stats",
374362
"DELETE " + basePath + "/api/logs/clear",
375-
"GET " + basePath + "/api/logo",
363+
"GET " + basePath + "/static/logo.png",
376364
"GET " + basePath + "/static/logs.css",
377365
"GET " + basePath + "/static/logs.js",
378366
})

pkg/ui/logs.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ <h1 class="title" id="title">Deploying your application</h1>
6666
<line x1="12" y1="19" x2="20" y2="19"></line>
6767
</svg>
6868
Logs
69+
<span id="elapsedTime" style="margin-left: 1rem; color: #718096; font-size: 0.875rem;"></span>
6970
</div>
7071
<div style="display: flex; align-items: center; gap: 1.5rem;">
7172
<div class="auto-redirect-toggle">

pkg/ui/logs.js

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const commandText = document.getElementById('commandText');
55
const versionText = document.getElementById('versionText');
66
const logo = document.getElementById('logo');
77
const autoScrollToggle = document.getElementById('autoScrollToggle');
8+
const elapsedTime = document.getElementById('elapsedTime');
89

910
let isReady = false;
1011
let lastLogCount = 0;
@@ -36,26 +37,10 @@ autoScrollToggle.addEventListener('click', function() {
3637
// Load logo
3738
async function loadLogo() {
3839
try {
39-
const response = await fetch(apiBase + '/logo');
40-
41-
// Silently fail if authentication fails
42-
if (response.status === 403 || response.status === 401 || !response.ok) {
43-
return false;
44-
}
45-
46-
// Check if response is JSON (OAuth redirect returns HTML with 200 OK)
47-
const contentType = response.headers.get('content-type');
48-
if (!contentType || !contentType.includes('application/json')) {
49-
return false;
50-
}
51-
52-
const data = await response.json();
53-
if (data.logo) {
54-
logo.src = 'data:' + data.type + ';base64,' + data.logo;
55-
logo.style.display = 'block'; // Show logo only after successful load
56-
logoLoaded = true;
57-
return true;
58-
}
40+
logo.src = basePath + '/static/logo.png';
41+
logo.style.display = 'block'; // Show logo
42+
logoLoaded = true;
43+
return true;
5944
} catch (err) {
6045
console.error('Failed to load logo:', err);
6146
}
@@ -68,6 +53,22 @@ function scrollToBottom() {
6853
}
6954
}
7055

56+
function formatElapsedTime(seconds) {
57+
if (!seconds || seconds < 0) {
58+
return '(0:00)';
59+
}
60+
61+
const hours = Math.floor(seconds / 3600);
62+
const minutes = Math.floor((seconds % 3600) / 60);
63+
const secs = Math.floor(seconds % 60);
64+
65+
if (hours > 0) {
66+
return `(${hours}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')})`;
67+
} else {
68+
return `(${minutes}:${String(secs).padStart(2, '0')})`;
69+
}
70+
}
71+
7172
function addLog(stream, line) {
7273
const firstPlaceholder = logsContainer.querySelector('.log-placeholder');
7374
if (firstPlaceholder) {
@@ -146,6 +147,11 @@ async function checkAppStatus() {
146147
if (data.process_state) {
147148
const state = data.process_state.state;
148149

150+
// Update elapsed time (show even if uptime is 0)
151+
if (data.process_state.uptime !== undefined) {
152+
elapsedTime.textContent = formatElapsedTime(data.process_state.uptime);
153+
}
154+
149155
if (state === 'running' && !isReady) {
150156
isReady = true;
151157
progressContainer.classList.add('hidden');

0 commit comments

Comments
 (0)