v2.0.6 — oumta-dashboard: hardwire config, drop settings tab
This plugin only targets one specific deployment, so the settings panel was noise that tempted accidental misconfiguration. baseUrl, authToken and pollIntervalSec now live in a top-of-file CONFIG constant; the hyprcrd-settings tab, the localStorage persistence, and the panel CSS are gone. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1e51bdec7c
commit
0553960a57
5 files changed
+27
-106
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
define('APP_NAME', 'hyprcrd');
|
||||
define('APP_VERSION', '2.0.5');
|
||||
define('APP_VERSION', '2.0.6');
|
||||
|
||||
// APP_DEBUG: gates verbose error responses (curl traces, upstream bodies).
|
||||
// Off by default; enable via env for local troubleshooting only.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hyprcrd",
|
||||
"version": "2.0.5",
|
||||
"version": "2.0.6",
|
||||
"description": "hyprcrd — self-hosted card manager",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -19,13 +19,15 @@ Close with **ESC** or the × button.
|
||||
|
||||
Tab row at the top. Currently two mocks (`oumta-dev`, `oumta-beta`). Real list comes from the backend once `/api/namespaces` exists.
|
||||
|
||||
## Settings
|
||||
## Configuration
|
||||
|
||||
Open the hyprcrd settings overlay and choose the **oumta** tab:
|
||||
Hardwired at the top of `oumta-dashboard.js` in the `CONFIG` block:
|
||||
|
||||
- **API Base URL** — e.g. `http://localhost:8080` for local dev, or the cluster-internal URL
|
||||
- **Auth token** — optional, sent as `Authorization: Bearer …`. Will eventually be filled automatically once Keycloak is wired up.
|
||||
- **Poll interval** — polling fallback cadence when SSE is unavailable. Default 15 s.
|
||||
- **baseUrl** — where the Oumta Go backend is reachable (default `http://localhost:8085`).
|
||||
- **authToken** — optional, sent as `Authorization: Bearer …` when non-empty.
|
||||
- **pollIntervalSec** — polling fallback cadence when SSE is unavailable. Default 15 s.
|
||||
|
||||
No UI settings panel: the dashboard only runs against one specific deployment, so exposing these as editable fields would be noise.
|
||||
|
||||
## State today
|
||||
|
||||
|
||||
@@ -234,24 +234,3 @@
|
||||
#oumta-live-indicator[data-state="live"] .oumta-dot { background: #4ade80; box-shadow: 0 0 6px #4ade80; }
|
||||
#oumta-live-indicator[data-state="polling"] .oumta-dot { background: #fb923c; }
|
||||
#oumta-live-indicator[data-state="error"] .oumta-dot { background: var(--t-danger); }
|
||||
|
||||
/* ── Settings tab ── */
|
||||
.oumta-settings-field {
|
||||
display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px;
|
||||
}
|
||||
.oumta-settings-field label {
|
||||
font-family: var(--font-pixel, 'Silkscreen', cursive);
|
||||
font-size: 9px; color: var(--t-dim); text-transform: uppercase;
|
||||
}
|
||||
.oumta-settings-field input {
|
||||
background: var(--t-bg);
|
||||
border: 1px solid var(--t-border);
|
||||
color: var(--t-bright);
|
||||
padding: 8px 10px;
|
||||
border-radius: var(--ui-radius-input);
|
||||
font-family: var(--font-content, monospace);
|
||||
font-size: 12px;
|
||||
outline: none;
|
||||
}
|
||||
.oumta-settings-field input:focus { border-color: var(--t-accent); }
|
||||
.oumta-settings-help { font-size: 10px; color: var(--t-dim); line-height: 1.5; }
|
||||
@@ -1,24 +1,21 @@
|
||||
// ── Oumta Dashboard plugin ──
|
||||
//
|
||||
// Fullscreen view that consumes the Oumta Go backend (`oumta-dashboard`).
|
||||
// All reads go through `api()` below; configure the backend URL in the
|
||||
// hyprcrd settings overlay (oumta tab) or accept the localhost default.
|
||||
// Backend location + poll interval are hardwired below — change them here
|
||||
// if the deployment topology shifts. No UI settings panel on purpose:
|
||||
// this plugin only makes sense in one specific deployment, so a settings
|
||||
// tab would just be noise and tempt accidental misconfiguration.
|
||||
|
||||
const h = window.hyprcrd;
|
||||
const $ = id => document.getElementById(id);
|
||||
|
||||
// ── Settings / persisted state ──
|
||||
//
|
||||
// We use localStorage for now. Later we might persist via a hyprcrd setting
|
||||
// or a plugin-level table — see TODO.md.
|
||||
|
||||
const LS_KEY = 'oumta-dashboard-settings';
|
||||
const state = {
|
||||
settings: {
|
||||
baseUrl: 'http://localhost:8080', // e.g. https://dashboard.oumta.internal; default fits local dev
|
||||
const CONFIG = {
|
||||
baseUrl: 'http://localhost:8085',
|
||||
authToken: '', // Keycloak bearer; empty = no auth yet
|
||||
pollIntervalSec: 15,
|
||||
},
|
||||
};
|
||||
|
||||
const state = {
|
||||
namespaces: [], // [{ id, label, namespace }]
|
||||
activeNamespace: null,
|
||||
activeView: 'overview',
|
||||
@@ -28,31 +25,21 @@ const state = {
|
||||
data: { overview: null, workloads: [], timeline: [], scopeWorkload: null },
|
||||
};
|
||||
|
||||
function loadSettings() {
|
||||
try {
|
||||
const raw = localStorage.getItem(LS_KEY);
|
||||
if (raw) Object.assign(state.settings, JSON.parse(raw));
|
||||
} catch {}
|
||||
}
|
||||
function saveSettings() {
|
||||
localStorage.setItem(LS_KEY, JSON.stringify(state.settings));
|
||||
}
|
||||
|
||||
// ── Central API surface ─────────────────────────────────────────
|
||||
//
|
||||
// Every backend call routes through `api()`. Requests go against
|
||||
// `state.settings.baseUrl`; the active namespace (if any) is attached
|
||||
// as a `namespace` query parameter, and the configured auth token is
|
||||
// sent as a bearer header. Response shapes are defined by the Go
|
||||
// backend in `internal/httpapi/contracts.go`.
|
||||
// Every backend call routes through `api()`. Requests go against the
|
||||
// hardwired baseUrl; the active namespace (if any) is attached as a
|
||||
// `namespace` query parameter, and the bearer token (if any) is sent as
|
||||
// Authorization. Response shapes are defined by the Go backend in
|
||||
// `internal/httpapi/contracts.go`.
|
||||
|
||||
async function api(path, opts = {}) {
|
||||
const url = new URL(path, state.settings.baseUrl);
|
||||
const url = new URL(path, CONFIG.baseUrl);
|
||||
if (!url.searchParams.has('namespace') && state.activeNamespace) {
|
||||
url.searchParams.set('namespace', state.activeNamespace.namespace);
|
||||
}
|
||||
const headers = state.settings.authToken
|
||||
? { Authorization: 'Bearer ' + state.settings.authToken }
|
||||
const headers = CONFIG.authToken
|
||||
? { Authorization: 'Bearer ' + CONFIG.authToken }
|
||||
: {};
|
||||
const res = await fetch(url, { ...opts, headers });
|
||||
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
|
||||
@@ -337,7 +324,7 @@ function stopLive() {
|
||||
setLive('off');
|
||||
}
|
||||
function startPolling() {
|
||||
const ms = (state.settings.pollIntervalSec || 15) * 1000;
|
||||
const ms = (CONFIG.pollIntervalSec || 15) * 1000;
|
||||
state.pollHandle = setInterval(refresh, ms);
|
||||
setLive('polling');
|
||||
}
|
||||
@@ -394,46 +381,6 @@ if (document.readyState === 'loading') {
|
||||
injectHeaderButton();
|
||||
}
|
||||
|
||||
// ── Settings tab in hyprcrd settings ─────────────────────────
|
||||
|
||||
function renderSettingsPanel(panelEl) {
|
||||
panelEl.innerHTML = `
|
||||
<div class="oumta-settings-field">
|
||||
<label for="oumta-set-baseurl">API Base URL</label>
|
||||
<input type="text" id="oumta-set-baseurl" placeholder="http://localhost:8080">
|
||||
<div class="oumta-settings-help">Where the Oumta Go backend is reachable from this browser. No trailing slash.</div>
|
||||
</div>
|
||||
<div class="oumta-settings-field">
|
||||
<label for="oumta-set-token">Auth token (optional)</label>
|
||||
<input type="text" id="oumta-set-token" placeholder="Bearer token from Keycloak">
|
||||
<div class="oumta-settings-help">Will be sent as <code>Authorization: Bearer <token></code>. Leave empty if the API is unauthenticated.</div>
|
||||
</div>
|
||||
<div class="oumta-settings-field">
|
||||
<label for="oumta-set-poll">Poll interval (seconds)</label>
|
||||
<input type="number" id="oumta-set-poll" min="5" max="300">
|
||||
<div class="oumta-settings-help">Used as a fallback when SSE is unavailable.</div>
|
||||
</div>
|
||||
<button id="oumta-set-save" class="flex items-center gap-1.5 px-3 py-1.5 text-xs border border-t-accent text-t-accent hover:bg-t-accent hover:text-t-bg transition-colors">
|
||||
<i class="ph ph-floppy-disk text-sm"></i><span class="font-pixel text-[10px]">Save</span>
|
||||
</button>
|
||||
<span id="oumta-set-status" class="font-pixel text-[10px] text-t-dim ml-3"></span>
|
||||
`;
|
||||
$('oumta-set-baseurl').value = state.settings.baseUrl || '';
|
||||
$('oumta-set-token').value = state.settings.authToken || '';
|
||||
$('oumta-set-poll').value = state.settings.pollIntervalSec || 15;
|
||||
$('oumta-set-save').addEventListener('click', () => {
|
||||
state.settings.baseUrl = $('oumta-set-baseurl').value.trim();
|
||||
state.settings.authToken = $('oumta-set-token').value.trim();
|
||||
state.settings.pollIntervalSec = Math.max(5, parseInt($('oumta-set-poll').value) || 15);
|
||||
saveSettings();
|
||||
const s = $('oumta-set-status');
|
||||
s.textContent = 'saved';
|
||||
setTimeout(() => { s.textContent = ''; }, 1500);
|
||||
// If the overlay is open, restart polling with new interval.
|
||||
if (isOpen()) { stopLive(); startLive(); }
|
||||
});
|
||||
}
|
||||
|
||||
// ── Helpers ─────────────────────────────────────────────────
|
||||
|
||||
function escapeHtml(s) {
|
||||
@@ -449,11 +396,4 @@ function formatTime(iso) {
|
||||
|
||||
// ── Boot ────────────────────────────────────────────────────
|
||||
|
||||
loadSettings();
|
||||
h?.settings?.registerTab?.({
|
||||
id: 'oumta-dashboard',
|
||||
label: 'oumta',
|
||||
icon: 'ph-gauge',
|
||||
onShow: renderSettingsPanel,
|
||||
});
|
||||
h?.registerPlugin?.({ name: 'oumta-dashboard', version: '0.1.0' });
|
||||
Reference in new issue
Block a user