Files
hermes-skills/skills/software-development/portal-ui-mockups/references/network-ops-page.md
T

4.1 KiB

Ops Portal — Network Page Pattern

Created: 2026-07-08 Session: Built /var/www/ops/network.html — network infrastructure page for the ops portal Domain: ops.itpropartner.com Root: /var/www/ops/

Page structure

Section Content
Nav Shared via fetch('/nav.html') — nav partial already had the /network.html link
Header Title "Network", status summary, last-updated timestamp, refresh button
Network Health Overview 5-card grid: DNS Zones tracked, API Checks (ok/total), Routers tracked, Domains active, Overall health score
MikroTik Routers Amber placeholder card + conditional backup history row from S3 data
Ubiquiti / UISP Teal placeholder card
DNS & Domains Live table from data.cloudflare_zones or data.domains with soft-coded fallback
Network Health — Port & Service Checks Grid of API/port check cards

Reusable patterns

1. Fallback data for when collector is offline

When a page depends on data from a live collector that may be offline, provide a hardcoded fallback so the page is useful from day one:

var KNOWN_ZONES = [
  { name: 'itpropartner.com', zone: '' },
  { name: 'nousresearch.com', zone: '' },
  // ...
];

Render logic: prefer live data → fall back to known list → show "Pending" badges → the page always has content even if the data source is down.

2. Placeholder card pattern

Sections that aren't yet connected to a live data source use a placeholder-card with status badges:

<div class="placeholder-card">
  <div class="p-icon">🔄</div>
  <div class="p-body">
    <div class="p-title">Title of feature</div>
    <div class="p-desc">Description of what will show when configured</div>
    <div class="p-meta">
      <span>Status: Not configured</span>
      <span>Requires: API Key</span>
    </div>
  </div>
</div>

Three color variants are defined:

  • .placeholder-card (amber) — not yet configured
  • .placeholder-card.placeholder-teal — setup required (teal accent)
  • .placeholder-card.placeholder-purple — reserved for future use

3. Data-source-agnostic health grid

The health overview at the top fetches from multiple possible data paths:

Metric Data path priority
DNS Zones data.cloudflare_zonesdata.domainsKNOWN_ZONES.length
API Checks data.api_healthdata.api_checks → 0
Routers data.routers → 0
Overall health Weighted combination of zone status + API status

This means the grid always renders something, even if only partial data is available.

4. S3 backup cross-section

When an S3 backup bucket name matches a section (e.g., "mikrotik-backups"), the section shows backup history inline:

var s3Backups = getNested(data, 's3_backups', []);
for (var i = 0; i < s3Backups.length; i++) {
  var bName = (b.name || b.bucket_name || b.bucket || '').toLowerCase();
  if (bName.indexOf('mikrotik') !== -1) {
    // Show backup row with last_upload, age color, status dot
  }
}

5. Plain CSS (no Tailwind CDN)

This page uses plain CSS with CSS custom properties — same dark theme variables as the rest of the portal but no Tailwind CDN dependency. This is an alternative approach to the Tailwind-heavy mockups listed elsewhere in this skill. Useful when:

  • The page is deployed in production (not a mockup)
  • Caching and no-external-dep is preferred
  • The shared ops.css stylesheet pattern is in play

Data flow

Fetches /data/ops-status.json on load + auto-refresh every 30s. Expects these fields:

{
  "cloudflare_zones": [{ "name": "...", "status": "active" }],
  "api_health": [{ "name": "...", "status": "ok" }],
  "network_checks": { "hostname": { "status": "reachable", "latency_ms": 42 } },
  "routers": [{ "name": "...", "status": "..." }],
  "domains": [{ "name": "...", "status": "...", "last_checked": "..." }],
  "s3_backups": [{ "name|bucket_name|bucket": "...", "status": "ok", "last_upload": "..." }]
}

File

  • /var/www/ops/network.html — 920 lines, 30 KB, plain HTML+CSS+JS, no external dependencies