Jesús Pérez da083fb9ec
Some checks failed
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
.coder/m
2026-03-29 00:19:56 +00:00

151 lines
5.8 KiB
HTML

{% extends "base.html" %}
{% import "macros/ui.html" as m %}
{% block title %}ADRs — {{ slug }} — Ontoref{% endblock title %}
{% block nav_adrs %}active{% endblock nav_adrs %}
{% block nav_group_dev %}active{% endblock nav_group_dev %}
{% block head %}
{% endblock head %}
{% block content %}
<div class="mb-6 flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold">Architecture Decision Records</h1>
<p class="text-base-content/50 text-sm mt-1">Typed NCL records — constraints, rationale, and alternatives for lasting architectural decisions</p>
</div>
<span class="badge badge-lg badge-neutral">{{ adr_count }} ADRs</span>
</div>
<!-- Filter bar -->
<div class="flex flex-wrap gap-2 mb-4">
<input id="filter-input" type="text" placeholder="Filter by ID, title, or context…"
class="input input-sm input-bordered flex-1 min-w-48 font-mono"
oninput="filterAdrs()">
<select id="filter-status" class="select select-sm select-bordered" onchange="filterAdrs()">
<option value="">All statuses</option>
<option value="Accepted">Accepted</option>
<option value="Proposed">Proposed</option>
<option value="Deprecated">Deprecated</option>
<option value="Superseded">Superseded</option>
</select>
</div>
<!-- ADR table -->
<div class="overflow-x-auto" id="adrs-container">
<table class="table table-sm w-full bg-base-200 rounded-lg" id="adrs-table">
<thead>
<tr class="text-base-content/50 text-xs uppercase tracking-wider">
<th class="w-24">ID</th>
<th>Title</th>
<th class="w-24">Status</th>
<th class="w-20">Date</th>
<th class="w-20">Constraints</th>
</tr>
</thead>
<tbody id="adrs-body"></tbody>
</table>
</div>
<!-- ADR detail modal -->
<dialog id="adr-modal" class="modal">
<div class="modal-box w-full max-w-3xl">
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-3 top-3"></button>
</form>
<div class="flex items-baseline gap-3 mb-1 pr-8">
<span id="detail-id" class="font-mono font-bold text-primary"></span>
<span id="detail-status-badge"></span>
<span id="detail-date" class="text-xs text-base-content/40 font-mono"></span>
</div>
<h2 id="detail-title" class="text-lg font-bold mb-3"></h2>
<div class="space-y-4 text-sm">
<div>
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/50 mb-1">Context</h3>
<p id="detail-context" class="text-base-content/80 leading-relaxed"></p>
</div>
<div>
<h3 class="text-xs font-semibold uppercase tracking-wider text-base-content/50 mb-1">Decision</h3>
<p id="detail-decision" class="text-base-content/80 leading-relaxed"></p>
</div>
</div>
<div class="flex gap-4 text-xs text-base-content/40 border-t border-base-content/10 pt-3 mt-4">
<span>Hard constraints: <span id="detail-hard" class="font-mono text-error"></span></span>
<span>Soft constraints: <span id="detail-soft" class="font-mono text-warning"></span></span>
<span class="ml-auto font-mono" id="detail-file"></span>
</div>
</div>
<form method="dialog" class="modal-backdrop">
<button>close</button>
</form>
</dialog>
<script>
const ADRS = {{ adrs_json | safe }};
function statusBadge(s) {
const cls = {
Accepted: 'badge badge-success badge-xs font-mono',
Proposed: 'badge badge-warning badge-xs font-mono',
Deprecated: 'badge badge-ghost badge-xs font-mono',
Superseded: 'badge badge-error badge-xs font-mono',
Error: 'badge badge-error badge-xs font-mono',
}[s] ?? 'badge badge-ghost badge-xs font-mono';
return `<span class="${cls}">${s}</span>`;
}
let visibleAdrs = ADRS;
function renderAdrs(adrs) {
visibleAdrs = adrs;
const tbody = document.getElementById('adrs-body');
tbody.innerHTML = adrs.map((a, i) => `
<tr class="hover cursor-pointer" onclick="showDetail(${i})">
<td class="font-mono text-xs text-primary">${a.id}</td>
<td class="text-sm">${a.title || '<span class="text-base-content/30">—</span>'}</td>
<td>${statusBadge(a.status)}</td>
<td class="font-mono text-xs text-base-content/50">${a.date || ''}</td>
<td class="text-xs">
${a.hard_constraints > 0 ? `<span class="text-error font-mono mr-1">${a.hard_constraints}H</span>` : ''}
${a.soft_constraints > 0 ? `<span class="text-warning font-mono">${a.soft_constraints}S</span>` : ''}
${a.hard_constraints === 0 && a.soft_constraints === 0 ? '<span class="text-base-content/30">—</span>' : ''}
</td>
</tr>
`).join('');
}
function showDetail(index) {
const a = visibleAdrs[index];
if (!a) return;
document.getElementById('detail-id').textContent = a.id;
document.getElementById('detail-status-badge').innerHTML = statusBadge(a.status);
document.getElementById('detail-date').textContent = a.date;
document.getElementById('detail-title').textContent = a.title;
document.getElementById('detail-context').textContent = a.context;
document.getElementById('detail-decision').textContent = a.decision;
document.getElementById('detail-hard').textContent = a.hard_constraints;
document.getElementById('detail-soft').textContent = a.soft_constraints;
document.getElementById('detail-file').textContent = a.file + '.ncl';
document.getElementById('adr-modal').showModal();
}
function filterAdrs() {
const text = document.getElementById('filter-input').value.toLowerCase();
const status = document.getElementById('filter-status').value;
const filtered = ADRS.filter(a => {
const textMatch = !text ||
a.id.toLowerCase().includes(text) ||
a.title.toLowerCase().includes(text) ||
a.context.toLowerCase().includes(text);
const statusMatch = !status || a.status === status;
return textMatch && statusMatch;
});
renderAdrs(filtered);
}
renderAdrs(ADRS);
</script>
{% endblock content %}