generated from coulomb/repo-seed
feat(dashboard): add Tools & Apps page with liveness probes
New page at /tools listing all connected applications grouped by category: Local Services (State Hub API, KeePassXC, pgAdmin, ops-bridge), Source Control (Gitea), Identity/Auth (KeyCape, Authelia, privacyIDEA, LLDAP), and Dev Tooling (Claude Code, uv). Local services show live green/red/grey status dots via no-cors fetch probes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ export default {
|
||||
{ name: "Progress", path: "/progress" },
|
||||
{ name: "Services (TPSC)", path: "/tpsc" },
|
||||
{ name: "Todo", path: "/todo" },
|
||||
{ name: "Tools & Apps", path: "/tools" },
|
||||
// ── Sections (alphabetical) ───────────────────────────────────────────────
|
||||
{
|
||||
name: "Policies",
|
||||
|
||||
203
dashboard/src/tools.md
Normal file
203
dashboard/src/tools.md
Normal file
@@ -0,0 +1,203 @@
|
||||
---
|
||||
title: Tools & Apps
|
||||
---
|
||||
|
||||
```js
|
||||
import {API} from "./components/config.js";
|
||||
```
|
||||
|
||||
```js
|
||||
// Probe local services — best-effort, timeout after 2s
|
||||
async function probe(url) {
|
||||
try {
|
||||
const ctrl = new AbortController();
|
||||
const tid = setTimeout(() => ctrl.abort(), 2000);
|
||||
const r = await fetch(url, {signal: ctrl.signal, mode: "no-cors"});
|
||||
clearTimeout(tid);
|
||||
return true; // no-cors = opaque response, but no throw = reachable
|
||||
} catch { return false; }
|
||||
}
|
||||
|
||||
// Only probe local services the browser can actually reach
|
||||
const [apiUp, giteaUp, pgadminUp] = await Promise.all([
|
||||
probe(`${API}/state/health`),
|
||||
probe("http://92.205.130.254:32166"),
|
||||
probe("http://127.0.0.1:5050"),
|
||||
]);
|
||||
|
||||
// Cluster services — mark as "unknown" unless we can check
|
||||
// (browser can't reach coulomb.social without the cluster being up;
|
||||
// just show them as static links without a live probe)
|
||||
```
|
||||
|
||||
```js
|
||||
function dot(up) {
|
||||
if (up === null) return html`<span class="app-dot app-dot-unknown" title="status unknown">●</span>`;
|
||||
return up
|
||||
? html`<span class="app-dot app-dot-up" title="reachable">●</span>`
|
||||
: html`<span class="app-dot app-dot-down" title="unreachable">●</span>`;
|
||||
}
|
||||
|
||||
function appCard({name, desc, url, label, status, icon, note}) {
|
||||
const linkEl = url
|
||||
? html`<a class="app-link" href="${url}" target="_blank" rel="noopener">${label ?? url}</a>`
|
||||
: html`<span class="app-link app-link-local">${label ?? "local app"}</span>`;
|
||||
return html`<div class="app-card">
|
||||
<div class="app-card-header">
|
||||
<span class="app-icon">${icon}</span>
|
||||
<span class="app-name">${name}</span>
|
||||
${dot(status)}
|
||||
</div>
|
||||
<p class="app-desc">${desc}</p>
|
||||
${linkEl}
|
||||
${note ? html`<p class="app-note">${note}</p>` : ""}
|
||||
</div>`;
|
||||
}
|
||||
```
|
||||
|
||||
# Tools & Apps
|
||||
|
||||
Connected applications, services, and local tools used across the Custodian ecosystem.
|
||||
|
||||
## Local Services
|
||||
|
||||
```js
|
||||
display(html`<div class="app-grid">
|
||||
${appCard({
|
||||
icon: "🗄️", name: "State Hub API", status: apiUp,
|
||||
desc: "FastAPI backend — the source of truth for all workstream, task, and decision data.",
|
||||
url: "http://127.0.0.1:8000/docs", label: "127.0.0.1:8000 · Swagger UI",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "🔑", name: "KeePassXC", status: null,
|
||||
desc: "Primary credential store. Holds all service secrets in the FOS group hierarchy. Single root of trust per the Credential Management Standard.",
|
||||
label: "local desktop app",
|
||||
note: "Standard: canon/standards/credential-management_v0.1.md",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "🐘", name: "pgAdmin", status: pgadminUp,
|
||||
desc: "PostgreSQL admin UI for the state-hub database. Start with: make db in state-hub/.",
|
||||
url: "http://127.0.0.1:5050", label: "127.0.0.1:5050",
|
||||
note: pgadminUp ? "" : "Start with: cd ~/the-custodian/state-hub && docker compose --profile pgadmin up -d",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "🌉", name: "ops-bridge", status: null,
|
||||
desc: "SSH reverse tunnel lifecycle manager. Keeps CoulombCore and Railiance nodes connected to the local state hub.",
|
||||
label: "~/ops-bridge · CLI",
|
||||
note: "bridge up / bridge status / bridge logs",
|
||||
})}
|
||||
</div>`);
|
||||
```
|
||||
|
||||
## Source Control
|
||||
|
||||
```js
|
||||
display(html`<div class="app-grid">
|
||||
${appCard({
|
||||
icon: "🦊", name: "Gitea", status: giteaUp,
|
||||
desc: "Self-hosted git server. All domain repos are mirrored here. Coulomb organisation hosts the primary remotes.",
|
||||
url: "http://92.205.130.254:32166", label: "92.205.130.254:32166",
|
||||
note: "Org: coulomb · also accessible as gitea.local on LAN",
|
||||
})}
|
||||
</div>`);
|
||||
```
|
||||
|
||||
## Identity & Auth (NetKingdom)
|
||||
|
||||
Services deployed on the k3s cluster. Require cluster to be running (ThreePhoenix / CoulombCore).
|
||||
|
||||
```js
|
||||
display(html`<div class="app-grid">
|
||||
${appCard({
|
||||
icon: "🪪", name: "KeyCape", status: null,
|
||||
desc: "Lightweight OIDC orchestration layer. Binds LLDAP, Authelia, and privacyIDEA into a single IAM profile.",
|
||||
url: "https://id.coulomb.social", label: "id.coulomb.social",
|
||||
note: "OIDC discovery: /.well-known/openid-configuration",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "🔐", name: "Authelia", status: null,
|
||||
desc: "Authentication and authorisation server. Handles password auth, session management, and OIDC relying-party flows.",
|
||||
url: "https://auth.coulomb.social", label: "auth.coulomb.social",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "📱", name: "privacyIDEA", status: null,
|
||||
desc: "MFA token management. Issues TOTP challenges via trigger-admin API. Backs all second-factor authentication.",
|
||||
url: "https://pink.coulomb.social", label: "pink.coulomb.social",
|
||||
note: "Admin portal — credentials in KeePassXC net-kingdom/privacyidea/pi-admin",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "📂", name: "LLDAP", status: null,
|
||||
desc: "Lightweight LDAP directory. Stores user accounts and group memberships queried by Authelia and KeyCape.",
|
||||
url: "https://ldap.coulomb.social", label: "ldap.coulomb.social",
|
||||
note: "Admin UI at :17170 · credentials in KeePassXC net-kingdom/lldap",
|
||||
})}
|
||||
</div>`);
|
||||
```
|
||||
|
||||
## Dev Tooling
|
||||
|
||||
```js
|
||||
display(html`<div class="app-grid">
|
||||
${appCard({
|
||||
icon: "🤖", name: "Claude Code", status: null,
|
||||
desc: "Primary AI coding assistant. Registered with the state-hub via MCP SSE server on :8001. The tool you're using right now.",
|
||||
label: "local CLI · claude",
|
||||
note: "MCP server: http://127.0.0.1:8001/sse · registered at user scope in ~/.claude.json",
|
||||
})}
|
||||
${appCard({
|
||||
icon: "📦", name: "uv", status: null,
|
||||
desc: "Python package and project manager. Manages all Python environments across custodian, state-hub, ops-bridge, and domain repos.",
|
||||
label: "local CLI · uv",
|
||||
note: "uv sync · uv run · uv add",
|
||||
})}
|
||||
</div>`);
|
||||
```
|
||||
|
||||
<style>
|
||||
.app-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.app-card {
|
||||
background: var(--theme-background-alt);
|
||||
border-radius: 8px;
|
||||
padding: 1rem 1.1rem;
|
||||
border: 1px solid var(--theme-foreground-faint, #e0e0e0);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
.app-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
.app-icon { font-size: 1.2rem; line-height: 1; }
|
||||
.app-name { font-weight: 700; font-size: 0.95rem; flex: 1; }
|
||||
.app-dot { font-size: 0.7rem; }
|
||||
.app-dot-up { color: #22c55e; }
|
||||
.app-dot-down { color: #ef4444; }
|
||||
.app-dot-unknown { color: #94a3b8; }
|
||||
.app-desc {
|
||||
font-size: 0.82rem;
|
||||
color: var(--theme-foreground-muted, #555);
|
||||
line-height: 1.45;
|
||||
margin: 0;
|
||||
}
|
||||
.app-link {
|
||||
font-size: 0.8rem;
|
||||
font-family: monospace;
|
||||
color: steelblue;
|
||||
word-break: break-all;
|
||||
}
|
||||
.app-link-local { color: var(--theme-foreground-muted, #888); }
|
||||
.app-note {
|
||||
font-size: 0.75rem;
|
||||
color: var(--theme-foreground-muted, #888);
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user