UI can now build an approved profile by hand

This commit is contained in:
2026-04-26 02:26:34 +02:00
parent 6da0e8966b
commit 6b7c6443ae
7 changed files with 794 additions and 1 deletions

View File

@@ -308,6 +308,45 @@ def repository_detail(
{render_ability_map(asdict(ability_map))}
</section>
</div>
<section class="panel" style="margin-top:18px">
<h2>Manual Registry Entry</h2>
<div class="grid">
<form class="stack" method="post" action="/ui/repos/{repository_id}/abilities">
<h3>Add Ability</h3>
<label>Name <input name="name" required></label>
<label>Description <textarea name="description" rows="2"></textarea></label>
<label>Confidence <input name="confidence" type="number" min="0" max="1" step="0.01" value="1.0" required></label>
<button type="submit">Add Ability</button>
</form>
<form class="stack" method="post" action="/ui/repos/{repository_id}/capabilities">
<h3>Add Capability</h3>
<label>Ability ID <input name="ability_id" type="number" min="1" required></label>
<label>Name <input name="name" required></label>
<label>Description <textarea name="description" rows="2"></textarea></label>
<label>Inputs <input name="inputs" placeholder="Comma-separated"></label>
<label>Outputs <input name="outputs" placeholder="Comma-separated"></label>
<label>Confidence <input name="confidence" type="number" min="0" max="1" step="0.01" value="1.0" required></label>
<button type="submit">Add Capability</button>
</form>
<form class="stack" method="post" action="/ui/repos/{repository_id}/features">
<h3>Add Feature</h3>
<label>Capability ID <input name="capability_id" type="number" min="1" required></label>
<label>Name <input name="name" required></label>
<label>Type <input name="type" required></label>
<label>Location <input name="location"></label>
<label>Confidence <input name="confidence" type="number" min="0" max="1" step="0.01" value="1.0" required></label>
<button type="submit">Add Feature</button>
</form>
<form class="stack" method="post" action="/ui/repos/{repository_id}/evidence">
<h3>Add Evidence</h3>
<label>Capability ID <input name="capability_id" type="number" min="1" required></label>
<label>Type <input name="type" required></label>
<label>Reference <input name="reference" required></label>
<label>Strength <input name="strength" value="medium" required></label>
<button type="submit">Add Evidence</button>
</form>
</div>
</section>
<section class="panel" style="margin-top:18px">
<h2>Review Decisions</h2>
{render_review_decisions(decisions)}
@@ -316,6 +355,86 @@ def repository_detail(
return page(repository.name, body)
@router.post("/ui/repos/{repository_id}/abilities")
def create_ability_from_form(
repository_id: int,
name: str = Form(...),
description: str = Form(""),
confidence: float = Form(1.0),
service: RegistryService = Depends(get_service),
) -> RedirectResponse:
service.add_ability(
repository_id,
name=name,
description=description,
confidence=confidence,
)
return RedirectResponse(f"/ui/repos/{repository_id}", status_code=303)
@router.post("/ui/repos/{repository_id}/capabilities")
def create_capability_from_form(
repository_id: int,
ability_id: int = Form(...),
name: str = Form(...),
description: str = Form(""),
inputs: str = Form(""),
outputs: str = Form(""),
confidence: float = Form(1.0),
service: RegistryService = Depends(get_service),
) -> RedirectResponse:
service.add_capability(
repository_id,
ability_id,
name=name,
description=description,
inputs=split_csv(inputs),
outputs=split_csv(outputs),
confidence=confidence,
)
return RedirectResponse(f"/ui/repos/{repository_id}", status_code=303)
@router.post("/ui/repos/{repository_id}/features")
def create_feature_from_form(
repository_id: int,
capability_id: int = Form(...),
name: str = Form(...),
type: str = Form(...),
location: str = Form(""),
confidence: float = Form(1.0),
service: RegistryService = Depends(get_service),
) -> RedirectResponse:
service.add_feature(
repository_id,
capability_id,
name=name,
type=type,
location=location,
confidence=confidence,
)
return RedirectResponse(f"/ui/repos/{repository_id}", status_code=303)
@router.post("/ui/repos/{repository_id}/evidence")
def create_evidence_from_form(
repository_id: int,
capability_id: int = Form(...),
type: str = Form(...),
reference: str = Form(...),
strength: str = Form("medium"),
service: RegistryService = Depends(get_service),
) -> RedirectResponse:
service.add_evidence(
repository_id,
capability_id,
type=type,
reference=reference,
strength=strength,
)
return RedirectResponse(f"/ui/repos/{repository_id}", status_code=303)
@router.post("/ui/repos/{repository_id}/analysis-runs")
def create_analysis_run_from_form(
repository_id: int,
@@ -751,6 +870,10 @@ def render_repository_facts(languages: list[str], frameworks: list[str]) -> str:
return f'<p class="actions">{language_pills}{framework_pills}</p>'
def split_csv(value: str) -> list[str]:
return [item.strip() for item in value.split(",") if item.strip()]
def render_review_decisions(decisions: list) -> str:
if not decisions:
return '<p class="muted">No review decisions yet.</p>'
@@ -967,6 +1090,7 @@ def render_ability_map(ability_map: dict) -> str:
f"""
<li id="capability-{capability['id']}">
<strong>{escape(capability['name'])}</strong>
<span class="pill">ID {capability['id']}</span>
<p class="muted">{escape(capability['description'])}</p>
<ul>{features}{evidence}</ul>
</li>
@@ -976,6 +1100,7 @@ def render_ability_map(ability_map: dict) -> str:
f"""
<li id="ability-{ability['id']}">
<strong>{escape(ability['name'])}</strong>
<span class="pill">ID {ability['id']}</span>
<p class="muted">{escape(ability['description'])}</p>
<ul>{''.join(capabilities)}</ul>
</li>