Add file deletion endpoint with multi-tag filtering support and redesigned editor UI with icon-only buttons
This commit is contained in:
@@ -231,6 +231,35 @@ async def api_file_save(vault_name: str, path: str = Query(..., description="Rel
|
||||
raise HTTPException(status_code=500, detail=f"Error saving file: {str(e)}")
|
||||
|
||||
|
||||
@app.delete("/api/file/{vault_name}")
|
||||
async def api_file_delete(vault_name: str, path: str = Query(..., description="Relative path to file")):
|
||||
"""Delete a file."""
|
||||
vault_data = get_vault_data(vault_name)
|
||||
if not vault_data:
|
||||
raise HTTPException(status_code=404, detail=f"Vault '{vault_name}' not found")
|
||||
|
||||
vault_root = Path(vault_data["path"])
|
||||
file_path = vault_root / path
|
||||
|
||||
try:
|
||||
file_path.resolve().relative_to(vault_root.resolve())
|
||||
except ValueError:
|
||||
raise HTTPException(status_code=403, detail="Access denied: path outside vault")
|
||||
|
||||
if not file_path.exists() or not file_path.is_file():
|
||||
raise HTTPException(status_code=404, detail=f"File not found: {path}")
|
||||
|
||||
try:
|
||||
file_path.unlink()
|
||||
logger.info(f"File deleted: {vault_name}/{path}")
|
||||
return {"status": "ok", "vault": vault_name, "path": path}
|
||||
except PermissionError:
|
||||
raise HTTPException(status_code=403, detail="Permission denied: vault may be read-only")
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting file {vault_name}/{path}: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"Error deleting file: {str(e)}")
|
||||
|
||||
|
||||
@app.get("/api/file/{vault_name}")
|
||||
async def api_file(vault_name: str, path: str = Query(..., description="Relative path to file")):
|
||||
"""Return rendered HTML + metadata for a file."""
|
||||
|
||||
+9
-2
@@ -8,6 +8,12 @@ from backend.indexer import index, get_vault_data
|
||||
logger = logging.getLogger("obsigate.search")
|
||||
|
||||
|
||||
def _normalize_tag_filter(tag_filter: Optional[str]) -> List[str]:
|
||||
if not tag_filter:
|
||||
return []
|
||||
return [tag.strip().lstrip("#") for tag in tag_filter.split(",") if tag.strip()]
|
||||
|
||||
|
||||
def _read_file_content(vault_name: str, file_path: str) -> str:
|
||||
"""Read raw markdown content of a file from disk."""
|
||||
vault_data = get_vault_data(vault_name)
|
||||
@@ -52,8 +58,9 @@ def search(
|
||||
"""
|
||||
query = query.strip() if query else ""
|
||||
has_query = len(query) > 0
|
||||
selected_tags = _normalize_tag_filter(tag_filter)
|
||||
|
||||
if not has_query and not tag_filter:
|
||||
if not has_query and not selected_tags:
|
||||
return []
|
||||
|
||||
results: List[Dict[str, Any]] = []
|
||||
@@ -63,7 +70,7 @@ def search(
|
||||
continue
|
||||
|
||||
for file_info in vault_data["files"]:
|
||||
if tag_filter and tag_filter not in file_info["tags"]:
|
||||
if selected_tags and not all(tag in file_info["tags"] for tag in selected_tags):
|
||||
continue
|
||||
|
||||
score = 0
|
||||
|
||||
Reference in New Issue
Block a user