generated from coulomb/repo-seed
repository-scoped dependency graph view profile persistence and interactive exploration features
This commit is contained in:
@@ -44,6 +44,11 @@ from repo_registry.web_api.schemas import (
|
||||
CapabilitySummaryResponse,
|
||||
CapabilityUpdate,
|
||||
ContentChunkResponse,
|
||||
DependencyGraphAdHocFilters,
|
||||
DependencyGraphProfileCreate,
|
||||
DependencyGraphProfileDuplicate,
|
||||
DependencyGraphProfileResponse,
|
||||
DependencyGraphProfileUpdate,
|
||||
EvidenceCreate,
|
||||
EvidenceUpdate,
|
||||
ErrorResponse,
|
||||
@@ -125,6 +130,7 @@ OPENAPI_TAGS = [
|
||||
{"name": "review", "description": "Candidate graph approval and correction workflow."},
|
||||
{"name": "registry", "description": "Approved ability maps and manual registry CRUD."},
|
||||
{"name": "scope", "description": "SCOPE.md generation, diffing, and writing."},
|
||||
{"name": "visualization", "description": "Dependency graph exploration and view profiles."},
|
||||
{"name": "search", "description": "Agent-facing discovery endpoints."},
|
||||
{"name": "discovery", "description": "Comparison, gap analysis, and export helpers."},
|
||||
]
|
||||
@@ -1141,12 +1147,13 @@ def get_ability_map(
|
||||
|
||||
@app.get(
|
||||
"/repos/{repository_id}/dependency-graph",
|
||||
tags=["registry"],
|
||||
tags=["visualization"],
|
||||
)
|
||||
def get_dependency_graph(
|
||||
repository_id: int,
|
||||
base_analysis_run_id: int | None = Query(default=None),
|
||||
target_analysis_run_id: int | None = Query(default=None),
|
||||
profile_id: int | None = Query(default=None),
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
@@ -1154,6 +1161,7 @@ def get_dependency_graph(
|
||||
repository_id,
|
||||
base_analysis_run_id=base_analysis_run_id,
|
||||
target_analysis_run_id=target_analysis_run_id,
|
||||
profile_id=profile_id,
|
||||
)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
@@ -1161,6 +1169,158 @@ def get_dependency_graph(
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/dependency-graph/filter",
|
||||
tags=["visualization"],
|
||||
)
|
||||
def filter_dependency_graph(
|
||||
repository_id: int,
|
||||
payload: DependencyGraphAdHocFilters,
|
||||
base_analysis_run_id: int | None = Query(default=None),
|
||||
target_analysis_run_id: int | None = Query(default=None),
|
||||
profile_id: int | None = Query(default=None),
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return service.dependency_graph_elements(
|
||||
repository_id,
|
||||
base_analysis_run_id=base_analysis_run_id,
|
||||
target_analysis_run_id=target_analysis_run_id,
|
||||
profile_id=profile_id,
|
||||
rules=payload.rules,
|
||||
manual_overrides=payload.manual_overrides,
|
||||
)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get(
|
||||
"/repos/{repository_id}/dependency-graph/profiles",
|
||||
tags=["visualization"],
|
||||
response_model=list[DependencyGraphProfileResponse],
|
||||
)
|
||||
def list_dependency_graph_profiles(
|
||||
repository_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> list[dict[str, object]]:
|
||||
try:
|
||||
return [
|
||||
asdict(profile)
|
||||
for profile in service.list_dependency_graph_profiles(repository_id)
|
||||
]
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/dependency-graph/profiles",
|
||||
tags=["visualization"],
|
||||
status_code=201,
|
||||
response_model=DependencyGraphProfileResponse,
|
||||
)
|
||||
def create_dependency_graph_profile(
|
||||
repository_id: int,
|
||||
payload: DependencyGraphProfileCreate,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return asdict(
|
||||
service.create_dependency_graph_profile(
|
||||
repository_id,
|
||||
**payload.model_dump(),
|
||||
)
|
||||
)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get(
|
||||
"/repos/{repository_id}/dependency-graph/profiles/{profile_id}",
|
||||
tags=["visualization"],
|
||||
response_model=DependencyGraphProfileResponse,
|
||||
)
|
||||
def get_dependency_graph_profile(
|
||||
repository_id: int,
|
||||
profile_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return asdict(service.get_dependency_graph_profile(repository_id, profile_id))
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.patch(
|
||||
"/repos/{repository_id}/dependency-graph/profiles/{profile_id}",
|
||||
tags=["visualization"],
|
||||
response_model=DependencyGraphProfileResponse,
|
||||
)
|
||||
def update_dependency_graph_profile(
|
||||
repository_id: int,
|
||||
profile_id: int,
|
||||
payload: DependencyGraphProfileUpdate,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return asdict(
|
||||
service.update_dependency_graph_profile(
|
||||
repository_id,
|
||||
profile_id,
|
||||
**payload.model_dump(exclude_unset=True),
|
||||
)
|
||||
)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.post(
|
||||
"/repos/{repository_id}/dependency-graph/profiles/{profile_id}/duplicate",
|
||||
tags=["visualization"],
|
||||
status_code=201,
|
||||
response_model=DependencyGraphProfileResponse,
|
||||
)
|
||||
def duplicate_dependency_graph_profile(
|
||||
repository_id: int,
|
||||
profile_id: int,
|
||||
payload: DependencyGraphProfileDuplicate,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> dict[str, object]:
|
||||
try:
|
||||
return asdict(
|
||||
service.duplicate_dependency_graph_profile(
|
||||
repository_id,
|
||||
profile_id,
|
||||
name=payload.name,
|
||||
)
|
||||
)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.delete(
|
||||
"/repos/{repository_id}/dependency-graph/profiles/{profile_id}",
|
||||
tags=["visualization"],
|
||||
status_code=204,
|
||||
)
|
||||
def delete_dependency_graph_profile(
|
||||
repository_id: int,
|
||||
profile_id: int,
|
||||
service: RegistryService = Depends(get_service),
|
||||
) -> None:
|
||||
try:
|
||||
service.delete_dependency_graph_profile(repository_id, profile_id)
|
||||
except NotFoundError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@app.get(
|
||||
"/repos/{repository_id}/export",
|
||||
tags=["discovery"],
|
||||
|
||||
@@ -308,6 +308,49 @@ class CharacteristicRebuildResponse(BaseModel):
|
||||
candidate_counts: dict[str, int]
|
||||
|
||||
|
||||
class DependencyGraphRule(BaseModel):
|
||||
action: str
|
||||
name: str | None = None
|
||||
match: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class DependencyGraphAdHocFilters(BaseModel):
|
||||
rules: list[dict[str, Any]] = Field(default_factory=list)
|
||||
manual_overrides: dict[str, str] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class DependencyGraphProfileCreate(BaseModel):
|
||||
name: str
|
||||
description: str = ""
|
||||
default_mode: str = "full"
|
||||
filter_rules: list[dict[str, Any]] = Field(default_factory=list)
|
||||
manual_overrides: dict[str, str] = Field(default_factory=dict)
|
||||
|
||||
|
||||
class DependencyGraphProfileUpdate(BaseModel):
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
default_mode: str | None = None
|
||||
filter_rules: list[dict[str, Any]] | None = None
|
||||
manual_overrides: dict[str, str] | None = None
|
||||
|
||||
|
||||
class DependencyGraphProfileDuplicate(BaseModel):
|
||||
name: str | None = None
|
||||
|
||||
|
||||
class DependencyGraphProfileResponse(BaseModel):
|
||||
id: int
|
||||
repository_id: int
|
||||
name: str
|
||||
description: str
|
||||
default_mode: str
|
||||
filter_rules: list[dict[str, Any]]
|
||||
manual_overrides: dict[str, str]
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
class CandidateRejection(BaseModel):
|
||||
notes: str = ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user