From f00614c10f152e6baaa0d0eecd381fec03a7c07d Mon Sep 17 00:00:00 2001 From: Gamosoft Date: Fri, 27 Mar 2026 17:02:36 +0100 Subject: [PATCH] added stats endpoint for dashboards --- backend/main.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ documentation/API.md | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/backend/main.py b/backend/main.py index a1915f9..70e13af 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1499,6 +1499,67 @@ async def toggle_plugin(request: Request, plugin_name: str, enabled: dict): raise HTTPException(status_code=500, detail=safe_error_message(e, "Failed to toggle plugin")) +# ============================================================================ +# Stats Endpoint (for dashboards) +# ============================================================================ + +@api_router.get("/stats", tags=["Stats"]) +@limiter.limit("30/minute") +async def get_stats(request: Request): + """ + Get application statistics at a glance. + + Designed for dashboard widgets (e.g., Homepage) - lightweight and cached. + Returns counts of notes, folders, tags, templates, media, and other metadata. + """ + try: + notes_dir = config['storage']['notes_dir'] + + # Get notes and folders (cached) + notes, folders = scan_notes_fast_walk(notes_dir, include_media=True) + + # Separate notes from media + note_items = [n for n in notes if n.get('type') == 'note'] + media_items = [n for n in notes if n.get('type') != 'note'] + + # Count unique tags + all_tags = set() + for note in note_items: + all_tags.update(note.get('tags', [])) + + # Get templates count + templates = get_templates(notes_dir) + + # Calculate total size + total_size = sum(n.get('size', 0) for n in notes) + + # Get last modified (notes are already sorted by modified desc) + last_modified = note_items[0].get('modified') if note_items else None + + # Count enabled plugins + enabled_plugins = sum(1 for p in plugin_manager.plugins.values() if p.enabled) + + # Read version + version = "unknown" + version_file = Path(__file__).parent.parent / "VERSION" + if version_file.exists(): + version = version_file.read_text().strip() + + return { + "notes_count": len(note_items), + "folders_count": len(folders), + "tags_count": len(all_tags), + "templates_count": len(templates), + "media_count": len(media_items), + "total_size_bytes": total_size, + "last_modified": last_modified, + "plugins_enabled": enabled_plugins, + "version": version + } + except Exception as e: + raise HTTPException(status_code=500, detail=safe_error_message(e, "Failed to get stats")) + + # ============================================================================ # Share Token Endpoints (authenticated) # ============================================================================ diff --git a/documentation/API.md b/documentation/API.md index 01aecf8..de9f240 100644 --- a/documentation/API.md +++ b/documentation/API.md @@ -452,6 +452,60 @@ GET /api/config ``` Returns application configuration. +### Get Stats +```http +GET /api/stats +``` +Returns application statistics at a glance. Designed for dashboard widgets (e.g., Homepage) - lightweight and uses cached data. + +**Response:** +```json +{ + "notes_count": 142, + "folders_count": 12, + "tags_count": 37, + "templates_count": 5, + "media_count": 23, + "total_size_bytes": 2458624, + "last_modified": "2026-03-17T14:32:00Z", + "plugins_enabled": 3, + "version": "0.19.1" +} +``` + +| Field | Description | +|-------|-------------| +| `notes_count` | Total number of markdown notes | +| `folders_count` | Total number of folders | +| `tags_count` | Number of unique tags across all notes | +| `templates_count` | Number of templates in `_templates` folder | +| `media_count` | Number of media files (images, etc.) | +| `total_size_bytes` | Total size of all files in bytes | +| `last_modified` | ISO timestamp of most recently modified note | +| `plugins_enabled` | Number of enabled plugins | +| `version` | Application version | + +**Example ([Homepage](https://gethomepage.dev/) dashboard widget):** +```yaml +- NoteDiscovery: + href: https://notediscovery.homelab.local + icon: notediscovery + container: homelab-notediscovery + widget: + type: customapi + url: http://notediscovery:8000/api/stats + refreshInterval: 60000 + mappings: + - field: notes_count + label: Notes + - field: tags_count + label: Tags + - field: folders_count + label: Folders + - field: version + label: Version +``` + ### Health Check ```http GET /health