Combined approved and candidate view with actions

This commit is contained in:
2026-04-29 13:19:58 +02:00
parent 8bd22dab1b
commit 142812e7f2
5 changed files with 942 additions and 43 deletions

View File

@@ -1194,6 +1194,17 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
assert "Use OpenRouter Models" in run_detail.text
assert "Expected from provider docs." in run_detail.text
pending_candidate_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={
"scope": "candidate",
"analysis_run_id": first_run_id,
"type": "features",
},
)
assert pending_candidate_listing.status_code == 200
assert "Accept" in pending_candidate_listing.text
approve_response = client.post(
f"{run_path}/candidate-graph/approve",
follow_redirects=False,
@@ -1215,14 +1226,14 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
assert "Search Profile" in approved_detail.text
assert "Discovery" in approved_detail.text
assert "Export" in approved_detail.text
assert "Approved Elements" in approved_detail.text
assert "Elements" in approved_detail.text
assert "q=Report+Service+Status" in approved_detail.text
assert (
f"/ui/repos/{repository_id}/elements?scope=approved&type=abilities"
f"/ui/repos/{repository_id}/elements?scope=all&entry_filter=approved&type=abilities"
in approved_detail.text
)
assert (
f"/ui/repos/{repository_id}/elements?scope=candidate&analysis_run_id={first_run_id}&type=features"
f"/ui/repos/{repository_id}/elements?scope=all&entry_filter=candidate&analysis_run_id={first_run_id}&type=features"
in approved_detail.text
)
assert (
@@ -1237,11 +1248,49 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
approved_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={"scope": "approved", "type": "capabilities"},
params={"scope": "all", "entry_filter": "approved", "type": "capabilities"},
)
assert approved_listing.status_code == 200
assert "Approved Capabilities" in approved_listing.text
assert "Registry Capabilities" in approved_listing.text
assert "Entry" in approved_listing.text
assert "Approved only" in approved_listing.text
assert "Expose Repository Interface" in approved_listing.text
assert "Save" in approved_listing.text
assert "Delete" in approved_listing.text
combined_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={
"scope": "all",
"analysis_run_id": first_run_id,
"type": "features",
},
)
assert combined_listing.status_code == 200
assert "Registry Features" in combined_listing.text
assert "Approved and candidate" in combined_listing.text
assert ">approved<" in combined_listing.text
assert ">candidate: approved<" in combined_listing.text
approved_map = client.get(f"/repos/{repository_id}/ability-map").json()
approved_capability = approved_map["abilities"][0]["capabilities"][0]
tune_response = client.post(
f"/ui/repos/{repository_id}/capabilities/{approved_capability['id']}/edit",
data={
"name": "Expose Tuned Repository Interface",
"description": approved_capability["description"],
"inputs": ", ".join(approved_capability["inputs"]),
"outputs": ", ".join(approved_capability["outputs"]),
"confidence": str(approved_capability["confidence"]),
},
follow_redirects=False,
)
assert tune_response.status_code == 303
tuned_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={"scope": "all", "entry_filter": "approved", "type": "capabilities"},
)
assert "Expose Tuned Repository Interface" in tuned_listing.text
candidate_listing = client.get(
f"/ui/repos/{repository_id}/elements",
@@ -1359,6 +1408,95 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
)
assert filtered_search_response.status_code == 200
assert "UI Repo" in filtered_search_response.text
final_map = client.get(f"/repos/{repository_id}/ability-map").json()
feature_id = final_map["abilities"][0]["capabilities"][0]["features"][0]["id"]
delete_feature_response = client.post(
f"/ui/repos/{repository_id}/features/{feature_id}/delete",
follow_redirects=False,
)
assert delete_feature_response.status_code == 303
deleted_feature_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={"scope": "approved", "type": "features"},
)
assert f"/ui/repos/{repository_id}/features/{feature_id}/delete" not in (
deleted_feature_listing.text
)
finally:
app.dependency_overrides.clear()
def test_ui_element_listing_hides_rejected_candidates_by_default(tmp_path):
source = tmp_path / "repo"
source.mkdir()
(source / "requirements.txt").write_text("fastapi\n", encoding="utf-8")
(source / "app.py").write_text(
"from fastapi import FastAPI\n"
"app = FastAPI()\n"
'@app.get("/status")\n'
"def status():\n"
" return {}\n",
encoding="utf-8",
)
def override_settings():
return Settings(
database_path=str(tmp_path / "ui-rejected.sqlite3"),
checkout_root=str(tmp_path / "ui-rejected-checkouts"),
)
app.dependency_overrides[get_settings] = override_settings
client = TestClient(app)
try:
repository_response = client.post(
"/repos",
json={"name": "Rejected UI", "url": str(source)},
)
repository_id = repository_response.json()["id"]
run_response = client.post(f"/repos/{repository_id}/analysis-runs", json={})
run_id = run_response.json()["analysis_run"]["id"]
candidate_graph = client.get(
f"/repos/{repository_id}/analysis-runs/{run_id}/candidate-graph"
).json()
candidate_feature = candidate_graph["abilities"][0]["capabilities"][0][
"features"
][0]
candidate_feature_id = candidate_feature["id"]
candidate_feature_name = candidate_feature["name"]
reject_response = client.post(
f"/ui/repos/{repository_id}/analysis-runs/{run_id}"
f"/candidate-features/{candidate_feature_id}/reject",
follow_redirects=False,
)
assert reject_response.status_code == 303
default_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={
"scope": "all",
"analysis_run_id": run_id,
"type": "features",
},
)
assert default_listing.status_code == 200
assert "Hide rejected" in default_listing.text
assert candidate_feature_name not in default_listing.text
rejected_listing = client.get(
f"/ui/repos/{repository_id}/elements",
params={
"scope": "all",
"analysis_run_id": run_id,
"type": "features",
"candidate_status_filter": "all",
},
)
assert rejected_listing.status_code == 200
assert candidate_feature_name in rejected_listing.text
assert "candidate: rejected" in rejected_listing.text
assert "Accept" in rejected_listing.text
finally:
app.dependency_overrides.clear()