5fe8f228c1
Add a read-only /ecosystem page that consumes the sibling services' JSON APIs (Nexus entities, Praxis attention, Hexis capabilities), fetched concurrently with honest per-panel error states. Siblings stay headless — mavweb is their human surface (arch §16). Wired via mavweb -nexus/-praxis/-hexis flags; mavweb joins the ecosystem compose network. Fix mobile horizontal overflow across all pages: .content is a flex child with default min-width:auto, so it refused to shrink below the tables' intrinsic width. min-width:0 lets wide tables pan inside .scroll instead of dragging the page sideways. Verified via CDP geometry check (scrollWidth === clientWidth at 430px). Also includes in-progress Ethos UI redesign, ecosystem deploy compose, and planning docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
51 lines
1.8 KiB
HTML
51 lines
1.8 KiB
HTML
{{template "shellTop" "dash"}}
|
|
<h1>Dashboard</h1>
|
|
<section class=card>
|
|
<h2 class=card-title>
|
|
<span class="dot dot-ok" style="margin-right:6px"></span>
|
|
presence
|
|
</h2>
|
|
<p>
|
|
<span class="status-{{.Presence.Bucket}}">{{.Presence.Bucket}}</span>
|
|
— score {{printf "%.2f" .Presence.Score}}
|
|
<span class=hint>({{ago .Presence.Updated}})</span>
|
|
</p>
|
|
<div class=hint id=updated>updates every 10s</div>
|
|
</section>
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>nudges</h2>
|
|
</div>
|
|
<div class=scroll><table class=mono id=nudges><tr><th>when<th>rule<th>chan<th>outcome<th>message</tr>
|
|
{{range .Nudges}}<tr><td>{{ago .Ts}}<td>{{.Rule}}<td><span class=badge>{{.Channel}}</span><td class={{.Outcome}}>{{.Outcome}}<td>{{.Message}}</tr>{{end}}
|
|
</table></div>
|
|
</section>
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>facts</h2>
|
|
</div>
|
|
<div class=scroll><table class=mono id=facts><tr><th>when<th>kind<th>key<th>value<th>source<th>conf</tr>
|
|
{{range .Facts}}<tr><td>{{ago .Ts}}<td>{{.Kind}}<td class=key>{{.Key}}<td>{{.Value}}<td>{{.Source}}<td>{{printf "%.2f" .Confidence}}</tr>{{end}}
|
|
</table></div>
|
|
</section>
|
|
<section class=card>
|
|
<div class=section-header>
|
|
<h2>notes</h2>
|
|
</div>
|
|
<div class=scroll><table class=mono id=notes><tr><th>when<th>source<th>text</tr>
|
|
{{range .Notes}}<tr><td>{{ago .Ts}}<td>{{.Source}}<td>{{.Text}}</tr>{{end}}
|
|
</table></div>
|
|
</section>
|
|
{{template "shellBottom"}}
|
|
<script>
|
|
setInterval(() => fetch('/dash').then(r => r.text()).then(html => {
|
|
const p = new DOMParser(), d = p.parseFromString(html, 'text/html');
|
|
for (const id of ['nudges', 'facts', 'notes']) {
|
|
const old = document.getElementById(id), nu = d.getElementById(id);
|
|
if (old && nu) old.replaceWith(nu);
|
|
}
|
|
document.getElementById('updated').textContent = 'updated ' + new Date().toLocaleTimeString();
|
|
}), 10000);
|
|
</script>
|
|
</html>
|