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