v2.0.1 — collab-attachments size cap + oumta overview tiles
- relay: raise /api/collab-attachments + /api/attachments/upload POST size limit from 256KB to 15MB, matching /api/attachments. Previous limit silently dropped any collab image >~100KB as 413 (envelope overhead pushes even modest JPEGs past the cap), leaving puller clients with broken <img src="uploads/..."> references. - oumta-dashboard: centre overview tiles, bump value font to 56px, introduce .oumta-fail alarm state that paints the full tile red with white text. Toggled from JS for cluster state=down, workloads down >0, and open incidents >0. Fail colour uses --t-danger so it stays in sync with the "unavailable" workload labels. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1dfffa5d6d
commit
72a7c7c7cc
6 files changed
+43
-9
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
define('APP_NAME', 'hyprcrd');
|
||||
define('APP_VERSION', '2.0.0');
|
||||
define('APP_VERSION', '2.0.1');
|
||||
|
||||
// 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.0",
|
||||
"version": "2.0.1",
|
||||
"description": "hyprcrd — self-hosted card manager",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
border-radius: var(--ui-radius-card);
|
||||
padding: 14px 16px;
|
||||
display: flex; flex-direction: column; gap: 4px;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
transition: background-color 0.2s, border-color 0.2s, color 0.2s;
|
||||
}
|
||||
.oumta-card-wide { grid-column: span 4; }
|
||||
.oumta-card-label {
|
||||
@@ -57,18 +60,36 @@
|
||||
}
|
||||
.oumta-card-value {
|
||||
font-family: var(--font-content, monospace);
|
||||
font-size: 28px;
|
||||
font-size: 56px;
|
||||
color: var(--t-bright);
|
||||
font-weight: bold;
|
||||
line-height: 1.05;
|
||||
}
|
||||
.oumta-card-value-sm { font-size: 14px; font-weight: normal; }
|
||||
.oumta-card-value-sm { font-size: 18px; font-weight: normal; line-height: 1.3; }
|
||||
.oumta-card-sub { font-size: 10px; color: var(--t-dim); }
|
||||
.oumta-danger { color: var(--t-danger); }
|
||||
|
||||
/* Fail state: whole card goes red; label, value, sub all flip to white
|
||||
* so the box reads as a single alarm tile rather than a coloured number
|
||||
* on dark chrome. Triggered from JS via the oumta-fail class. Uses the
|
||||
* theme's --t-danger to stay consistent with the "unavailable" state
|
||||
* labels and workload state colours elsewhere in the dashboard. */
|
||||
.oumta-card.oumta-fail {
|
||||
background: var(--t-danger);
|
||||
border-color: var(--t-danger);
|
||||
color: #fff;
|
||||
}
|
||||
.oumta-card.oumta-fail .oumta-card-label,
|
||||
.oumta-card.oumta-fail .oumta-card-value,
|
||||
.oumta-card.oumta-fail .oumta-card-sub {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.oumta-cluster-status[data-state="healthy"] .oumta-card-value { color: #4ade80; }
|
||||
.oumta-cluster-status[data-state="degraded"] .oumta-card-value { color: #fb923c; }
|
||||
.oumta-cluster-status[data-state="down"] .oumta-card-value { color: var(--t-danger); }
|
||||
.oumta-cluster-status[data-state="unknown"] .oumta-card-value { color: var(--t-dim); }
|
||||
/* data-state="down" is handled by .oumta-fail (toggled from JS) so the
|
||||
* cluster tile goes fully red + white like the other alarms. */
|
||||
|
||||
/* ── Attention list ── */
|
||||
.oumta-section { margin-top: 8px; }
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
</div>
|
||||
<div class="oumta-card">
|
||||
<div class="oumta-card-label">Workloads down</div>
|
||||
<div class="oumta-card-value oumta-danger" id="oumta-workloads-down">—</div>
|
||||
<div class="oumta-card-value" id="oumta-workloads-down">—</div>
|
||||
</div>
|
||||
<div class="oumta-card">
|
||||
<div class="oumta-card-label">Open incidents</div>
|
||||
|
||||
@@ -269,19 +269,28 @@ function renderOverview() {
|
||||
if (!o) return;
|
||||
|
||||
// Values that come directly from the Go overview endpoint [REAL].
|
||||
$('oumta-cluster-card').dataset.state = o.clusterState || 'unknown';
|
||||
$('oumta-cluster-state').textContent = o.clusterState || 'unknown';
|
||||
const clusterCard = $('oumta-cluster-card');
|
||||
const clusterState = o.clusterState || 'unknown';
|
||||
clusterCard.dataset.state = clusterState;
|
||||
clusterCard.classList.toggle('oumta-fail', clusterState === 'down');
|
||||
$('oumta-cluster-state').textContent = clusterState;
|
||||
$('oumta-cluster-updated').textContent = o.updatedAtUtc ? 'as of ' + formatTime(o.updatedAtUtc) : 'no data';
|
||||
$('oumta-workloads-up').textContent = o.workloadsUp ?? '—';
|
||||
$('oumta-workloads-down').textContent = o.workloadsDown ?? '—';
|
||||
$('oumta-last-import').textContent = o.updatedAtUtc ? formatTime(o.updatedAtUtc) : '—';
|
||||
|
||||
// Any workload down → the "workloads down" tile becomes an alarm tile.
|
||||
const downCard = $('oumta-workloads-down').closest('.oumta-card');
|
||||
if (downCard) downCard.classList.toggle('oumta-fail', (o.workloadsDown ?? 0) > 0);
|
||||
|
||||
// Values derived client-side from the workloads list — the overview
|
||||
// endpoint doesn't carry these today. If the backend later adds
|
||||
// `incidents` / `attention` fields, prefer those over the derivation.
|
||||
const attention = wl.filter(w => w.state !== 'healthy')
|
||||
.sort((a, b) => rankState(a.state) - rankState(b.state));
|
||||
$('oumta-incidents').textContent = attention.length || '—';
|
||||
const incCard = $('oumta-incidents').closest('.oumta-card');
|
||||
if (incCard) incCard.classList.toggle('oumta-fail', attention.length > 0);
|
||||
|
||||
const list = $('oumta-attention-list');
|
||||
if (!attention.length) {
|
||||
|
||||
+5
-1
@@ -66,7 +66,11 @@ if (str_starts_with($route, '/api/')) {
|
||||
if ($method === 'OPTIONS') exit;
|
||||
|
||||
$contentLength = (int)($_SERVER['CONTENT_LENGTH'] ?? 0);
|
||||
$sizeLimit = ($route === '/api/attachments') ? 15728640 : 262144;
|
||||
// Attachment routes handle binary blobs; everything else is JSON metadata.
|
||||
// A ~150KB image becomes a ~275KB envelope after base64 + GCM framing,
|
||||
// so 256KB would silently drop any non-trivial image on collab pushes.
|
||||
$isAttachmentRoute = in_array($route, ['/api/attachments', '/api/attachments/upload', '/api/collab-attachments'], true);
|
||||
$sizeLimit = $isAttachmentRoute ? 15728640 : 262144;
|
||||
if ($contentLength > $sizeLimit) jsonResponse(['error' => 'payload too large'], 413);
|
||||
|
||||
// Each route file contains its handlers as if-blocks that exit on
|
||||
|
||||
Reference in new issue
Block a user