diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui/app.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ui/app.py | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py index 18764e8..3dc320b 100644 --- a/packages/meshbay-node/src/meshbay_node/ui/app.py +++ b/packages/meshbay-node/src/meshbay_node/ui/app.py @@ -169,6 +169,14 @@ def create_ui_app(state: dict) -> FastAPI: async def api_denylist_clear(subject: str = ""): return await _op(lambda: ops.clear_denylist(state, subject=subject)) + @app.get("/api/index-cache") + async def api_index_cache_stats(): + return await _op(lambda: ops.index_cache_stats(state)) + + @app.post("/api/index-cache/prune") + async def api_index_cache_prune(): + return await _op(lambda: ops.prune_index_cache(state)) + @app.get("/api/groups/{group_id}/files") async def api_group_files(group_id: str): groups_ctx = state.get("groups_ctx", {}) @@ -458,7 +466,9 @@ def create_ui_app(state: dict) -> FastAPI: "members": await roster.list_members(), "invites": await roster.list_invites(), } - return _render_page(state, roster_view) + index_cache = state.get("index_cache") + cache_count = await index_cache.count() if index_cache else None + return _render_page(state, roster_view, cache_count) @app.get("/audit", response_class=HTMLResponse) async def audit_page(): @@ -540,7 +550,8 @@ def _render_roster(roster_view: dict | None) -> str: </p>""" -def _render_page(state: dict, roster_view: dict | None = None) -> str: +def _render_page(state: dict, roster_view: dict | None = None, + index_cache_count: int | None = None) -> str: token_js = json.dumps(state.get("ui_token", "")) status = state.get("status", "starting") indexes = state.get("indexes", {}) @@ -723,6 +734,26 @@ def _render_page(state: dict, roster_view: dict | None = None) -> str: <p><b>Node ID:</b> <code>{state.get("endpoint_hint") or "—"}</code></p> </div> + <h2>Maintenance</h2> + <div class="card"> + <p><b>Index cache:</b> <span id="cacheCount">{ + index_cache_count if index_cache_count is not None else "—" + }</span> path(s) remembered (size/mtime → hash, shared by every group)</p> + <p class="muted">Removes rows whose path no longer belongs to any group's + root, or whose file is genuinely gone from a root that is currently + reachable. Never touches a root that is temporarily unavailable + (unplugged drive) — that one still needs its full cache back the + moment it returns.</p> + <div style="margin:10px 0"> + <button onclick="pruneIndexCache()" id="prune-cache-btn" + style="padding:8px 16px;background:#3b82f6;color:#fff;border:none; + border-radius:6px;cursor:pointer;font-size:0.85em"> + Prune stale entries + </button> + <span id="prune-cache-status" class="muted" style="margin-left:8px"></span> + </div> + </div> + <h2>Link Node to Hub Account</h2> <div class="card"> <p>To connect to your group from a browser, link this node to your hub account. @@ -774,6 +805,30 @@ async function initGEK(groupId) {{ if (btn) btn.disabled = false; }} }} +async function pruneIndexCache() {{ + const btn = document.getElementById('prune-cache-btn'); + const status = document.getElementById('prune-cache-status'); + if (btn) btn.disabled = true; + if (status) {{ status.textContent = 'Pruning...'; status.style.color = ''; }} + try {{ + const resp = await fetch('/api/index-cache/prune?t=' + TOKEN, {{ method: 'POST' }}); + const data = await resp.json(); + if (resp.ok) {{ + if (status) status.textContent = 'Removed ' + data.removed + ', kept ' + data.kept; + if (status) status.style.color = '#22c55e'; + const count = document.getElementById('cacheCount'); + if (count) count.textContent = data.kept; + }} else {{ + if (status) status.textContent = data.error || 'Failed'; + if (status) status.style.color = '#ef4444'; + }} + }} catch (e) {{ + if (status) status.textContent = 'Error: ' + e.message; + if (status) status.style.color = '#ef4444'; + }} finally {{ + if (btn) btn.disabled = false; + }} +}} setTimeout(()=>location.reload(), 10000); </script> </body> |