generated from coulomb/repo-seed
Milestone 5 polish
This commit is contained in:
@@ -587,10 +587,14 @@ class RegistryService:
|
||||
status: str | None = None,
|
||||
language: str | None = None,
|
||||
framework: str | None = None,
|
||||
ability: str | None = None,
|
||||
capability: str | None = None,
|
||||
) -> list[SearchResult]:
|
||||
return self.store.search(
|
||||
query,
|
||||
status=status,
|
||||
language=language,
|
||||
framework=framework,
|
||||
ability=ability,
|
||||
capability=capability,
|
||||
)
|
||||
|
||||
@@ -1282,6 +1282,8 @@ class RegistryStore:
|
||||
status: str | None = None,
|
||||
language: str | None = None,
|
||||
framework: str | None = None,
|
||||
ability: str | None = None,
|
||||
capability: str | None = None,
|
||||
) -> list[SearchResult]:
|
||||
term = query.strip()
|
||||
needle = f"%{term}%"
|
||||
@@ -1294,6 +1296,8 @@ class RegistryStore:
|
||||
status=status,
|
||||
language=language,
|
||||
framework=framework,
|
||||
ability=ability,
|
||||
capability=capability,
|
||||
)
|
||||
if repository_ids is not None and not repository_ids:
|
||||
return []
|
||||
@@ -1502,6 +1506,8 @@ class RegistryStore:
|
||||
status: str | None,
|
||||
language: str | None,
|
||||
framework: str | None,
|
||||
ability: str | None,
|
||||
capability: str | None,
|
||||
) -> list[int] | None:
|
||||
filters: list[set[int]] = []
|
||||
if status:
|
||||
@@ -1530,6 +1536,26 @@ class RegistryStore:
|
||||
(framework,),
|
||||
).fetchall()
|
||||
filters.append({row["repository_id"] for row in rows})
|
||||
if ability:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT DISTINCT repository_id
|
||||
FROM approved_abilities
|
||||
WHERE name LIKE ? OR description LIKE ?
|
||||
""",
|
||||
(f"%{ability}%", f"%{ability}%"),
|
||||
).fetchall()
|
||||
filters.append({row["repository_id"] for row in rows})
|
||||
if capability:
|
||||
rows = connection.execute(
|
||||
"""
|
||||
SELECT DISTINCT repository_id
|
||||
FROM approved_capabilities
|
||||
WHERE name LIKE ? OR description LIKE ?
|
||||
""",
|
||||
(f"%{capability}%", f"%{capability}%"),
|
||||
).fetchall()
|
||||
filters.append({row["repository_id"] for row in rows})
|
||||
if not filters:
|
||||
return None
|
||||
repository_ids = set.intersection(*filters)
|
||||
|
||||
@@ -771,6 +771,8 @@ def search(
|
||||
status: str | None = None,
|
||||
language: str | None = None,
|
||||
framework: str | None = None,
|
||||
ability: str | None = None,
|
||||
capability: str | None = None,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
return [
|
||||
@@ -780,6 +782,8 @@ def search(
|
||||
status=status,
|
||||
language=language,
|
||||
framework=framework,
|
||||
ability=ability,
|
||||
capability=capability,
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
@@ -179,6 +179,8 @@ def search_page(
|
||||
status: str = "",
|
||||
language: str = "",
|
||||
framework: str = "",
|
||||
ability: str = "",
|
||||
capability: str = "",
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> HTMLResponse:
|
||||
results = (
|
||||
@@ -187,6 +189,8 @@ def search_page(
|
||||
status=status or None,
|
||||
language=language or None,
|
||||
framework=framework or None,
|
||||
ability=ability or None,
|
||||
capability=capability or None,
|
||||
)
|
||||
if q.strip()
|
||||
else []
|
||||
@@ -194,7 +198,7 @@ def search_page(
|
||||
rows = "\n".join(
|
||||
f"""
|
||||
<tr>
|
||||
<td><a href="/ui/repos/{result.repository_id}">{escape(result.repository_name)}</a></td>
|
||||
<td><a href="{search_result_href(asdict(result))}">{escape(result.repository_name)}</a></td>
|
||||
<td><span class="pill">{escape(result.match_type)}</span></td>
|
||||
<td>
|
||||
<strong>{escape(result.match_name)}</strong>
|
||||
@@ -223,6 +227,8 @@ def search_page(
|
||||
<label>Status <input name="status" value="{escape(status)}" placeholder="indexed"></label>
|
||||
<label>Language <input name="language" value="{escape(language)}" placeholder="Python"></label>
|
||||
<label>Framework <input name="framework" value="{escape(framework)}" placeholder="FastAPI"></label>
|
||||
<label>Ability <input name="ability" value="{escape(ability)}" placeholder="Email Routing"></label>
|
||||
<label>Capability <input name="capability" value="{escape(capability)}" placeholder="Classification"></label>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<button type="submit">Search</button>
|
||||
@@ -930,7 +936,7 @@ def render_ability_map(ability_map: dict) -> str:
|
||||
)
|
||||
capabilities.append(
|
||||
f"""
|
||||
<li>
|
||||
<li id="capability-{capability['id']}">
|
||||
<strong>{escape(capability['name'])}</strong>
|
||||
<p class="muted">{escape(capability['description'])}</p>
|
||||
<ul>{features}{evidence}</ul>
|
||||
@@ -939,7 +945,7 @@ def render_ability_map(ability_map: dict) -> str:
|
||||
)
|
||||
items.append(
|
||||
f"""
|
||||
<li>
|
||||
<li id="ability-{ability['id']}">
|
||||
<strong>{escape(ability['name'])}</strong>
|
||||
<p class="muted">{escape(ability['description'])}</p>
|
||||
<ul>{''.join(capabilities)}</ul>
|
||||
@@ -949,6 +955,15 @@ def render_ability_map(ability_map: dict) -> str:
|
||||
return f'<div class="tree"><ul>{"".join(items)}</ul></div>'
|
||||
|
||||
|
||||
def search_result_href(result: dict) -> str:
|
||||
href = f"/ui/repos/{result['repository_id']}"
|
||||
if result.get("capability_id"):
|
||||
return f"{href}#capability-{result['capability_id']}"
|
||||
if result.get("ability_id"):
|
||||
return f"{href}#ability-{result['ability_id']}"
|
||||
return href
|
||||
|
||||
|
||||
def render_sources(source_refs: list[dict]) -> str:
|
||||
if not source_refs:
|
||||
return ""
|
||||
|
||||
@@ -161,6 +161,8 @@ def test_search_filters_by_status_language_and_framework(tmp_path):
|
||||
status="indexed",
|
||||
language="Python",
|
||||
framework="FastAPI",
|
||||
ability="Repository Usefulness",
|
||||
capability="Repository Structure",
|
||||
)
|
||||
wrong_language_results = service.search(
|
||||
"repository",
|
||||
@@ -168,10 +170,18 @@ def test_search_filters_by_status_language_and_framework(tmp_path):
|
||||
language="TypeScript",
|
||||
framework="FastAPI",
|
||||
)
|
||||
wrong_capability_results = service.search(
|
||||
"repository",
|
||||
status="indexed",
|
||||
language="Python",
|
||||
framework="FastAPI",
|
||||
capability="Email Routing",
|
||||
)
|
||||
|
||||
assert results
|
||||
assert {result.repository_name for result in results} == {"Filterable"}
|
||||
assert wrong_language_results == []
|
||||
assert wrong_capability_results == []
|
||||
|
||||
|
||||
def test_register_repository_imports_metadata_when_name_is_omitted(tmp_path):
|
||||
|
||||
@@ -215,7 +215,12 @@ def test_api_analysis_run_loop(tmp_path):
|
||||
|
||||
filtered_search_response = client.get(
|
||||
"/search",
|
||||
params={"q": "frontend", "status": "indexed"},
|
||||
params={
|
||||
"q": "frontend",
|
||||
"status": "indexed",
|
||||
"ability": "Frontend",
|
||||
"capability": "Frontend Stack",
|
||||
},
|
||||
)
|
||||
assert filtered_search_response.status_code == 200
|
||||
assert filtered_search_response.json()
|
||||
@@ -315,10 +320,17 @@ def test_ui_register_analyze_and_approve_loop(tmp_path):
|
||||
assert search_response.status_code == 200
|
||||
assert "UI Repo" in search_response.text
|
||||
assert "Field" in search_response.text
|
||||
assert "#capability-" in search_response.text or "#ability-" in search_response.text
|
||||
|
||||
filtered_search_response = client.get(
|
||||
"/ui/search",
|
||||
params={"q": "repository", "status": "indexed", "language": "Python"},
|
||||
params={
|
||||
"q": "repository",
|
||||
"status": "indexed",
|
||||
"language": "Python",
|
||||
"ability": "Repository Usefulness",
|
||||
"capability": "Repository",
|
||||
},
|
||||
)
|
||||
assert filtered_search_response.status_code == 200
|
||||
assert "UI Repo" in filtered_search_response.text
|
||||
|
||||
Reference in New Issue
Block a user