Skip to content

Commit 6f19621

Browse files
committed
osint: server-side FieldMask card render (/api/osint/card.html)
The Redmine ERB ViewFilter, rendered server-side in the codebase's own Html<String> idiom (no template engine exists in the workspace; adding askama blind on edition-2024 would risk the whole binary). render_rows is template- agnostic, so this is a drop-in swap for an askama template once a version is pinned — the projection (mask → rows) is identical either way. GET /api/osint/card.html?mask=<bits> renders the 0x0700 card as an HTML table: role (from the predicate prefix) · field · predicate, FieldMask-filtered.
1 parent d5f7633 commit 6f19621

2 files changed

Lines changed: 40 additions & 0 deletions

File tree

crates/cockpit-server/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ async fn main() {
226226
// The canonical OSINT card (classid 0x0700) projected through a FieldMask —
227227
// the Redmine-style ViewFilter, server-side (`?mask=<bits>`, omitted = FULL).
228228
.route("/api/osint/card", get(osint_classview::osint_card_handler))
229+
.route("/api/osint/card.html", get(osint_classview::osint_card_html_handler))
229230
// /body server-side HHTL LOD — POST camera → per-concept HhtlAction byte
230231
// (cascade over 1658 baked BlockBounds; native SIMD; client gates draw by it).
231232
.route("/api/body/lod", post(body_lod::body_lod_handler))

crates/cockpit-server/src/osint_classview.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
2121
use std::sync::LazyLock;
2222

23+
use axum::response::Html;
2324
use axum::{extract::Query, Json};
2425
use lance_graph_contract::class_view::{ClassId, ClassView, FieldMask};
2526
use lance_graph_contract::ontology::{DisplayTemplate, FieldRef};
@@ -99,6 +100,44 @@ pub async fn osint_card_handler(Query(q): Query<CardQuery>) -> Json<serde_json::
99100
}))
100101
}
101102

103+
/// `GET /api/osint/card.html?mask=<bits>` — the same ViewFilter, rendered
104+
/// server-side as HTML (the Redmine ERB view, in this codebase's `Html<String>`
105+
/// idiom). `render_rows` is template-agnostic, so this is a drop-in swap for an
106+
/// askama template once a version is pinned; the *projection* (mask → rows) is
107+
/// identical either way. Each row shows its reasoning role (parsed from the
108+
/// predicate prefix), the field label, and the predicate key.
109+
pub async fn osint_card_html_handler(Query(q): Query<CardQuery>) -> Html<String> {
110+
let mask = q.mask.map(FieldMask).unwrap_or(FieldMask::FULL);
111+
let cv = OsintClassView;
112+
let rows = cv.render_rows(OSINT_CLASS, mask);
113+
let mut body = String::new();
114+
for r in &rows {
115+
// predicate = "aiwar:<role>/<field>" — the reasoning role is the prefix.
116+
let role = r
117+
.predicate
118+
.strip_prefix("aiwar:")
119+
.and_then(|s| s.split('/').next())
120+
.unwrap_or("");
121+
body.push_str(&format!(
122+
"<tr><td class=r>{role}</td><td class=l>{}</td><td class=p>{}</td></tr>",
123+
r.label, r.predicate
124+
));
125+
}
126+
Html(format!(
127+
"<!doctype html><meta charset=utf-8><title>OSINT 0x0700 card</title>\
128+
<style>body{{background:#0a0e17;color:#cfe7ff;font:13px ui-monospace,monospace;padding:18px}}\
129+
h1{{font-size:14px;color:#7fd1ff;font-weight:400}}table{{border-collapse:collapse;margin-top:10px}}\
130+
td{{padding:4px 12px;border-bottom:1px solid #1b2c3e;white-space:nowrap}}\
131+
.r{{color:#7fd1ff}}.l{{color:#eaf4ff}}.p{{color:#5a6b7f}}</style>\
132+
<h1>OSINT · classid 0x0700 · FieldMask 0x{:03x} · {} / {} fields shown</h1>\
133+
<table><tr><td class=r>role</td><td class=l>field</td><td class=p>predicate</td></tr>{}</table>",
134+
mask.0,
135+
rows.len(),
136+
cv.field_count(OSINT_CLASS),
137+
body
138+
))
139+
}
140+
102141
#[cfg(test)]
103142
mod tests {
104143
use super::*;

0 commit comments

Comments
 (0)