diff --git a/CHANGELOG.md b/CHANGELOG.md index c5549a2..af10555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Cache entry detail page — `GET /cache/entries/:id` shows the full key, byte size, and created-at for a single entry; value body is gated behind `SolidStackWeb.allow_value_preview` (default `false`); when enabled, displays up to 4 KB of the raw serialized value with a truncation notice; entry key in the browser table is now a link to the detail page; **Delete** button on the detail page redirects back to the entry list +- Cache stats dashboard card — adds **Oldest** entry age (via `time_ago_in_words` with exact timestamp on hover) to the Solid Cache overview card; stat is hidden when the cache is empty; **Entries** count is now a link to the entry browser; `oldest_entry` added to the `/metrics` JSON payload as ISO 8601 (or `null`) +- Cache entry detail page — `GET /cache/entries/:id` shows the full key, byte size, and created-at for a single entry; value body is gated behind `SolidStackWeb.allow_value_preview` (default `false`); when enabled, displays up to 4 KB with JSON pretty-printing and a format badge (JSON / Text); entry key in the browser table is now a link to the detail page; **Delete** button on the detail page redirects back to the entry list - Solid Cache entry browser — `GET /cache/entries` lists all `SolidCache::Entry` records in a paginated, sortable table (key, byte size, created-at); sortable by any column; key-substring search filters the list; per-row **Delete** removes a single entry; **Flush All** header button deletes every entry with a confirmation prompt; Cache subnav (Overview / Entries) added to the layout ## [0.4.0] - 2026-05-26 diff --git a/README.md b/README.md index 317ce8f..826c615 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Filters are preserved when switching between status tabs (Ready / Scheduled / Ru ### Features -- **Overview dashboard card** — live entry count and total byte size +- **Overview dashboard card** — live entry count (linked to the entry browser), total byte size, and oldest-entry age (`time_ago_in_words` with exact timestamp on hover; hidden when cache is empty) - **Entry browser** — `GET /cache/entries` lists all `SolidCache::Entry` records in a paginated, sortable table; columns: key, byte size, created-at; sortable by any column; key auto-submits search after 4 characters - **Key search** — filter entries by key substring; results update automatically after 4 characters - **Entry detail page** — `GET /cache/entries/:id` shows the full key, byte size, and created-at; optionally displays the raw serialized value (see `allow_value_preview` below) @@ -133,7 +133,7 @@ _Channel monitoring coming in v0.6.0. Currently shows active message count and d "processes_stale": 0, "slow_jobs": 7 }, - "cache": { "entries": 1024, "byte_size": 2097152 }, + "cache": { "entries": 1024, "byte_size": 2097152, "oldest_entry": "2026-05-20T10:00:00Z" }, "cable": { "messages": 50, "channels": 3 }, "generated_at": "2026-05-26T10:00:00Z" } diff --git a/ROADMAP.md b/ROADMAP.md index f00ad79..73a5325 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -13,7 +13,6 @@ The path to v1.0.0 is staged: first achieve feature parity with `solid_queue_das ### Added - **Size distribution stats** — top-N entries by byte size; histogram bucketed by size range - **Cache timeline** — 24-hour chart of entry count and total byte size growth -- **Stats dashboard card** — expand the overview card to include hit/miss rates if `SolidCache` exposes them, plus oldest-entry age --- diff --git a/app/assets/stylesheets/solid_stack_web/_07_dashboard.css b/app/assets/stylesheets/solid_stack_web/_07_dashboard.css index 2b0a6e0..d561608 100644 --- a/app/assets/stylesheets/solid_stack_web/_07_dashboard.css +++ b/app/assets/stylesheets/solid_stack_web/_07_dashboard.css @@ -69,6 +69,7 @@ a.sqw-inline-stat:hover { opacity: 0.7; text-decoration: none; } } .sqw-inline-stat__value { font-size: 28px; font-weight: 700; line-height: 1; } +.sqw-inline-stat__value--sm { font-size: 16px; } .sqw-inline-stat--ready .sqw-inline-stat__value { color: var(--success); } .sqw-inline-stat--scheduled .sqw-inline-stat__value { color: var(--info); } diff --git a/app/models/solid_stack_web/cache_stats.rb b/app/models/solid_stack_web/cache_stats.rb index adf697a..226a49c 100644 --- a/app/models/solid_stack_web/cache_stats.rb +++ b/app/models/solid_stack_web/cache_stats.rb @@ -2,8 +2,9 @@ module SolidStackWeb class CacheStats def to_h { - entries: ::SolidCache::Entry.count, - byte_size: ::SolidCache::Entry.sum(:byte_size) + entries: ::SolidCache::Entry.count, + byte_size: ::SolidCache::Entry.sum(:byte_size), + oldest_entry: ::SolidCache::Entry.minimum(:created_at) } end end diff --git a/app/views/solid_stack_web/cache/index.html.erb b/app/views/solid_stack_web/cache/index.html.erb index 91c93d6..cb4f83f 100644 --- a/app/views/solid_stack_web/cache/index.html.erb +++ b/app/views/solid_stack_web/cache/index.html.erb @@ -3,10 +3,10 @@