FleetHealth PR 3: 'Projects' panel — which repos live where
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 34s
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 34s
Backend:
* New DashboardProject { repo, cache_bytes, fingerprint_count,
refs, first_seen_unix, last_seen_unix, tier }.
* Handler build_projects() joins ref-tracking with the ref-store
and blob-store: for each recorded fp, resolve fp → blob-id via
RefStore::{get_stamped, get} then sum blob sizes per repo.
* Tier is a wall-clock function of last_seen_unix:
active < 24h, recent < 7d, else idle.
* DashboardStorageReply gains `projects: Vec<DashboardProject>`
(serde-default so older clients still parse).
Aggregator:
* New /api/v2/projects endpoint. Fans out DashboardStorage to
every peer, tags each project row with its originating node,
returns hottest-first.
Frontend:
* New ProjectsPanel component appended to the FleetHealth
landing. Groups by repo, one row per project with tier badge
(active/recent/idle), per-node pill badges, cache-size sum,
ref list, last-activity age.
* Empty state explains how to populate: claw-cargo build with
--repo + --git-ref (or CLAWSTOR_REPO/CLAWSTOR_GIT_REF env
vars in CI).
Data populates automatically as each cache-put runs. Existing
demo entry on tank (clawverse/clawstor · main · c384a4...) will
surface after redeploy.
This commit is contained in:
@@ -23,10 +23,9 @@ async function get(path) {
|
||||
}
|
||||
return resp.json();
|
||||
}
|
||||
// All paths are relative to API_BASE. E.g. '/v2/fleet' becomes
|
||||
// '/api/v2/fleet' locally or '/clawstor/api/v2/fleet' via Tailscale.
|
||||
export const api = {
|
||||
fleet: () => get('/v2/fleet'),
|
||||
projects: () => get('/v2/projects'),
|
||||
nodeStatus: (name) => get(`/v2/node/${name}/status`),
|
||||
blobs: (limit = 200, offset = 0) => get(`/v2/storage/blobs?limit=${limit}&offset=${offset}`),
|
||||
tags: (prefix = '') => get(`/v2/storage/tags?prefix=${encodeURIComponent(prefix)}`),
|
||||
|
||||
@@ -121,8 +121,20 @@ async function get<T>(path: string): Promise<T> {
|
||||
|
||||
// All paths are relative to API_BASE. E.g. '/v2/fleet' becomes
|
||||
// '/api/v2/fleet' locally or '/clawstor/api/v2/fleet' via Tailscale.
|
||||
export interface ProjectRow {
|
||||
node: string;
|
||||
repo: string;
|
||||
cache_bytes: number;
|
||||
fingerprint_count: number;
|
||||
refs: string[];
|
||||
first_seen_unix: number;
|
||||
last_seen_unix: number;
|
||||
tier: 'active' | 'recent' | 'idle' | string;
|
||||
}
|
||||
|
||||
export const api = {
|
||||
fleet: () => get<FleetSnapshot>('/v2/fleet'),
|
||||
projects: () => get<ProjectRow[]>('/v2/projects'),
|
||||
nodeStatus: (name: string) => get<NodeStatusV2>(`/v2/node/${name}/status`),
|
||||
blobs: (limit = 200, offset = 0) =>
|
||||
get<BlobSummary[]>(`/v2/storage/blobs?limit=${limit}&offset=${offset}`),
|
||||
|
||||
Reference in New Issue
Block a user