generated from coulomb/repo-seed
STATE-WP-0062 T3: Services nav section + First/Self Hosted pages
Replace the single "Services (TPSC)" nav entry with a Services section: Third Party (existing /tpsc cloud-third-party view), First Party (/services/first-party — Service Maturity Level + dev-repo columns, development_type=first_party), and Self Hosted (/services/self-hosted — self_hosted third-party OSS with upstream/host/runbook). New pages are filtered views over /services/catalog and degrade to an empty-state if the API is offline. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,16 @@ export default {
|
|||||||
{ name: "Inbox", path: "/inbox" },
|
{ name: "Inbox", path: "/inbox" },
|
||||||
{ name: "Progress", path: "/progress" },
|
{ name: "Progress", path: "/progress" },
|
||||||
{ name: "Token Cost", path: "/token-cost" },
|
{ name: "Token Cost", path: "/token-cost" },
|
||||||
{ name: "Services (TPSC)", path: "/tpsc" },
|
{
|
||||||
|
name: "Services",
|
||||||
|
collapsible: true,
|
||||||
|
open: false,
|
||||||
|
pages: [
|
||||||
|
{ name: "Third Party", path: "/tpsc" },
|
||||||
|
{ name: "First Party", path: "/services/first-party" },
|
||||||
|
{ name: "Self Hosted", path: "/services/self-hosted" },
|
||||||
|
],
|
||||||
|
},
|
||||||
{ name: "Todo", path: "/todo" },
|
{ name: "Todo", path: "/todo" },
|
||||||
{ name: "Tools & Apps", path: "/tools" },
|
{ name: "Tools & Apps", path: "/tools" },
|
||||||
// ── Sections (alphabetical) ───────────────────────────────────────────────
|
// ── Sections (alphabetical) ───────────────────────────────────────────────
|
||||||
|
|||||||
49
dashboard/src/services/first-party.md
Normal file
49
dashboard/src/services/first-party.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
---
|
||||||
|
title: First Party Services
|
||||||
|
---
|
||||||
|
|
||||||
|
# First Party Services Catalog
|
||||||
|
|
||||||
|
Services **coulomb is development-responsible for** (`development_type = first_party`),
|
||||||
|
whether deployed to a cloud or self-hosted on coulomb infrastructure. The
|
||||||
|
**Service Maturity Level** column tracks each service against the
|
||||||
|
[Service DoM](/policy/service-dom) (1 · Core → 2 · Standard → 3 · Mature).
|
||||||
|
|
||||||
|
```js
|
||||||
|
import {API} from "../components/config.js";
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const services = await fetch(`${API}/services/catalog?development_type=first_party`)
|
||||||
|
.then(r => r.ok ? r.json() : [])
|
||||||
|
.catch(() => []);
|
||||||
|
const repos = await fetch(`${API}/repos/`)
|
||||||
|
.then(r => r.ok ? r.json() : [])
|
||||||
|
.catch(() => []);
|
||||||
|
const repoById = new Map(repos.map(r => [r.id, r.slug]));
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const LEVEL = {1: "1 · Core", 2: "2 · Standard", 3: "3 · Mature"};
|
||||||
|
|
||||||
|
const rows = services.map(s => ({
|
||||||
|
Service: s.name,
|
||||||
|
Slug: s.slug,
|
||||||
|
Hosting: s.hosting_type === "self_hosted" ? "self-hosted" : "cloud-hosted",
|
||||||
|
"Maturity Level": s.maturity_level ? LEVEL[s.maturity_level] : "—",
|
||||||
|
"Dev Repo": s.first_party?.repo_id ? (repoById.get(s.first_party.repo_id) ?? "(unlinked)") : "—",
|
||||||
|
Domain: s.first_party?.owning_domain ?? "—",
|
||||||
|
Status: s.status,
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
display(services.length === 0
|
||||||
|
? html`<div style="color:#64748b;padding:1rem;">No first-party services registered yet. Add one with
|
||||||
|
<code>POST /services/catalog</code> (<code>development_type: "first_party"</code>).</div>`
|
||||||
|
: Inputs.table(rows, {
|
||||||
|
columns: ["Service", "Hosting", "Maturity Level", "Dev Repo", "Domain", "Status"],
|
||||||
|
sort: "Service",
|
||||||
|
rows: 30,
|
||||||
|
}));
|
||||||
|
```
|
||||||
48
dashboard/src/services/self-hosted.md
Normal file
48
dashboard/src/services/self-hosted.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: Self Hosted Services
|
||||||
|
---
|
||||||
|
|
||||||
|
# Self Hosted Services Catalog
|
||||||
|
|
||||||
|
Services and webapps built on **third-party / open-source software** that coulomb
|
||||||
|
**hosts and operates** as part of the three-helix infrastructure
|
||||||
|
(`hosting_type = self_hosted`, `development_type = third_party`). coulomb runs
|
||||||
|
these but is not development-responsible for them.
|
||||||
|
|
||||||
|
> First-party services that coulomb also self-hosts (e.g. the State Hub itself)
|
||||||
|
> are listed under [First Party](/services/first-party), classified by who develops
|
||||||
|
> them.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import {API} from "../components/config.js";
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const services = await fetch(`${API}/services/catalog?hosting_type=self_hosted&development_type=third_party`)
|
||||||
|
.then(r => r.ok ? r.json() : [])
|
||||||
|
.catch(() => []);
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
const rows = services.map(s => ({
|
||||||
|
Service: s.name,
|
||||||
|
Slug: s.slug,
|
||||||
|
"Upstream OSS": s.self_hosted?.upstream_oss_project ?? s.owner_or_provider ?? "—",
|
||||||
|
"Helix Instance": s.self_hosted?.helix_instance ?? "—",
|
||||||
|
Host: s.self_hosted?.host_node ?? "—",
|
||||||
|
Runbook: s.self_hosted?.runbook_ref ?? "—",
|
||||||
|
Status: s.status,
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
display(services.length === 0
|
||||||
|
? html`<div style="color:#64748b;padding:1rem;">No self-hosted third-party services registered yet. Add one with
|
||||||
|
<code>POST /services/catalog</code> (<code>hosting_type: "self_hosted"</code>,
|
||||||
|
<code>development_type: "third_party"</code>).</div>`
|
||||||
|
: Inputs.table(rows, {
|
||||||
|
columns: ["Service", "Upstream OSS", "Helix Instance", "Host", "Runbook", "Status"],
|
||||||
|
sort: "Service",
|
||||||
|
rows: 30,
|
||||||
|
}));
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user