Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/DESIGN-SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ Garis progres 3px (`#progress`) saat navigasi boosted >150 ms, hormati reduced-m
### 7.1 Navigasi boosted (S9)
- `<body hx-boost="true" hx-ext="preload,head-support" hx-target="#main" hx-select="#main" hx-swap="outerHTML show:none">`. Setiap halaman kerja membungkus **seluruh** isi (konten, sheet, `<template>`, skrip inline) dalam satu `<div class="container" id="main" data-nav="{{.Nav}}">`; header, tab bar, dan head tetap. `login.html` tidak memuat htmx; form logout `hx-boost="false"`.
- Elemen htmx lain di dalam halaman (stats card, segmented) wajib `hx-target` sendiri dan `hx-select="unset"` agar tidak mewarisi `#main`.
- Skrip halaman **idempoten**: dipanggil pada `DOMContentLoaded` dan `htmx:afterSettle`, dengan guard `data-init` (lihat `list.js`, `formatTimes` di `app.js`). Listener ke `document`/`window` dari skrip inline dilarang (menumpuk setiap swap): pasang ke `#main` atau elemen di dalamnya. Sumber daya hidup (WebSocket, xterm) mendaftar fungsi pembersih ke `window.dockifyCleanups`; `app.js` memanggilnya pada `htmx:beforeSwap` target `#main`.
- Skrip halaman **idempoten**: dipanggil pada `DOMContentLoaded` dan `htmx:afterSettle`, dengan guard `data-init` (lihat `list.js`, `formatTimes` di `app.js`). Listener ke `document`/`window` dari skrip inline dilarang (menumpuk setiap swap): pasang ke `#main` atau elemen di dalamnya. Sumber daya hidup (WebSocket, xterm) mendaftar fungsi pembersih ke `window.dockifyCleanups`; `app.js` memanggilnya pada `htmx:beforeSwap` target `#main`. `charts.js` dan `console.js` dimuat `defer`: skrip inline yang memanggilnya saat parse dibungkus `dockifyReady(fn)` (app.js; menunggu DOMContentLoaded pada load penuh, langsung jalan setelah swap). Pembersih yang dipasang saat aksi user (Console) didaftarkan saat aksi itu, bukan sekali saat skrip dimuat.
- Form dengan `onsubmit` yang bisa membatalkan harus memvalidasi lagi di `htmx:beforeRequest` (htmx tetap mengirim saat `onsubmit` mengembalikan false).
- Respons tanpa `#main` (redirect ke login) jatuh ke load penuh; 4xx/5xx boosted tetap di-swap (halaman error).
- Preload: atribut `preload="mousedown"` (touchstart otomatis) pada nav dan tautan baris; server menjawab permintaan `HX-Preloaded` dengan `Cache-Control: private, max-age=5`.
Expand Down
6 changes: 6 additions & 0 deletions internal/http/static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ document.addEventListener('click', function (e) {
else fallback();
});

// Inline page scripts that need a deferred asset (charts.js, console.js): on a full load they run before it, so wait for DCL.
function dockifyReady(fn) {
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn, { once: true });
else fn();
}

// xterm is only needed for the SSH console: load it on first use.
var xtermLoading = null;
function loadXterm(cb) {
Expand Down
7 changes: 5 additions & 2 deletions internal/http/static/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ function dockifyConsole(cfg) {
function el(id) { return document.getElementById(id); }
function setStatus(text, cls) {
var s = el(cfg.status);
if (!s) return; // socket closed after the page was swapped out
s.textContent = text;
s.className = 'badge ' + cls;
}
Expand Down Expand Up @@ -47,6 +48,7 @@ function dockifyConsole(cfg) {
if (box.hidden) {
box.hidden = false;
if (cfg.openLabel) btn.textContent = cfg.openLabel;
(window.dockifyCleanups = window.dockifyCleanups || []).push(closeConsoles);
loadXterm(connect);
} else {
box.hidden = true;
Expand Down Expand Up @@ -113,7 +115,8 @@ function toggleAppConsole() {
appConsole.toggle();
}
// A boosted navigation replaces #main; close any open console so its socket does not leak.
(window.dockifyCleanups = window.dockifyCleanups || []).push(function () {
// Registered on open: the cleanup list is emptied on every swap.
function closeConsoles() {
if (serverConsole) { serverConsole.disconnect(); serverConsole = null; }
if (appConsole) { appConsole.disconnect(); appConsole = null; }
});
}
4 changes: 2 additions & 2 deletions internal/http/templates/apps_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ <h3>Resource usage <span id="app-live-indicator" class="badge badge-online live-
</div>
</div>
<script>
var appCharts = initLiveCharts({
dockifyReady(function () { initLiveCharts({
wsUrl: 'api/apps/{{.App.ID}}/stats/live',
metrics: ['cpu', 'memory', 'network', 'disk'],
gauges: [
Expand All @@ -115,7 +115,7 @@ <h3>Resource usage <span id="app-live-indicator" class="badge badge-online live-
var e2=document.getElementById('disk-chart-val'); if(e2) e2.textContent=formatBytes(d.disk_usage_bytes);
}
}
});
}); });
</script>
{{end}}

Expand Down
4 changes: 2 additions & 2 deletions internal/http/templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@
<script src="static/htmx-ext-head-support.min.js?v={{.AssetVersion}}"></script>
<script src="static/app.js?v={{.AssetVersion}}"></script>
<script src="static/list.js?v={{.AssetVersion}}"></script>
<script src="static/charts.js?v={{.AssetVersion}}"></script>
<script src="static/console.js?v={{.AssetVersion}}"></script>
<script defer src="static/charts.js?v={{.AssetVersion}}"></script>
<script defer src="static/console.js?v={{.AssetVersion}}"></script>
{{end}}

{{define "nav"}}
Expand Down
4 changes: 2 additions & 2 deletions internal/http/templates/servers_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ <h3>Danger zone</h3>

{{if eq .Server.Status "online"}}
<script>
var serverCharts = initLiveCharts({
dockifyReady(function () { initLiveCharts({
wsUrl: 'api/servers/{{.Server.ID}}/stats/live',
metrics: ['cpu', 'ram', 'disk'],
gauges: [
Expand Down Expand Up @@ -227,7 +227,7 @@ <h3>Danger zone</h3>
}
}
}
});
}); });
</script>
{{end}}
</div>
Expand Down
Loading