From eacfccdffdaf51e59b1720fc28ac6248f8cfff46 Mon Sep 17 00:00:00 2001 From: tegwick Date: Fri, 19 Jun 2026 16:05:04 +0200 Subject: [PATCH] Add Service DoM dashboard policy page Mirror the repo-doi/workstream-dod Observable policy pages for service-dom: read/edit view backed by GET/PUT /policy/service-dom. Add it to the Policies nav section and the State Hub reference doc. Builds clean (62 pages). Co-Authored-By: Claude Opus 4.8 --- dashboard/observablehq.config.js | 1 + dashboard/src/docs/state-hub.md | 1 + dashboard/src/policy/service-dom.md | 90 +++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 dashboard/src/policy/service-dom.md diff --git a/dashboard/observablehq.config.js b/dashboard/observablehq.config.js index e72fdba..c467f7b 100644 --- a/dashboard/observablehq.config.js +++ b/dashboard/observablehq.config.js @@ -44,6 +44,7 @@ export default { open: false, pages: [ { name: "Repository DoI", path: "/policy/repo-doi" }, + { name: "Service DoM", path: "/policy/service-dom" }, { name: "Workstream DoD", path: "/policy/workstream-dod" }, ], }, diff --git a/dashboard/src/docs/state-hub.md b/dashboard/src/docs/state-hub.md index e38b58e..29c49dc 100644 --- a/dashboard/src/docs/state-hub.md +++ b/dashboard/src/docs/state-hub.md @@ -265,5 +265,6 @@ why, even years later. - [Connecting to the Hub](/docs/connecting) - [Repo Integration](/docs/repo-integration) - [Repository DoI](/policy/repo-doi) — Definition of Integrated +- [Service DoM](/policy/service-dom) — Definition of Mature - [TPSC](/docs/tpsc) — Third-Party Services Catalog - [SBOM](/docs/sbom) diff --git a/dashboard/src/policy/service-dom.md b/dashboard/src/policy/service-dom.md new file mode 100644 index 0000000..e16f7a2 --- /dev/null +++ b/dashboard/src/policy/service-dom.md @@ -0,0 +1,90 @@ +--- +title: Service Definition of Mature (DoM) +--- + +```js +import {API} from "../components/config.js"; +``` + +```js +import {marked} from "npm:marked"; + +const _resp = await fetch(`${API}/policy/service-dom`); +if (!_resp.ok) throw new Error(`Failed to load policy: ${_resp.status}`); +const _policy = await _resp.json(); +``` + +```js +let _content = _policy.content; +let _editing = false; + +const _root = display(html`
`); + +async function _save(text) { + const r = await fetch(`${API}/policy/service-dom`, { + method: "PUT", + headers: {"Content-Type": "application/json"}, + body: JSON.stringify({content: text}), + }); + if (!r.ok) throw new Error(`Save failed: ${r.status}`); + _content = text; +} + +function _toolbar(...nodes) { + return html`
${nodes}
`; +} + +function _btn(label, primary = false) { + return html``; +} + +function _render() { + _root.innerHTML = ""; + + if (_editing) { + const area = html``; + + const saveBtn = _btn("Save", true); + const cancelBtn = _btn("Cancel"); + + saveBtn.onclick = async () => { + saveBtn.disabled = true; + saveBtn.textContent = "Saving…"; + try { + await _save(area.value); + _editing = false; + _render(); + } catch (e) { + saveBtn.disabled = false; + saveBtn.textContent = "Save"; + alert(e.message); + } + }; + + cancelBtn.onclick = () => { _editing = false; _render(); }; + + _root.append(_toolbar(saveBtn, cancelBtn), area); + + } else { + const editBtn = _btn("Edit"); + editBtn.onclick = () => { _editing = true; _render(); }; + + const body = html`
`; + body.innerHTML = marked.parse(_content); + + _root.append(_toolbar(editBtn), body); + } +} + +_render(); +```