feat(catalog): promote buckets to top-level Data Package cards (#301)

Each catalog_data bucket renders as its own top-level Data Package card instead of nested accordions under a single Core Business Data wrapper. Tables flat-listed per package, mirroring the Agnes Internal card. Pluralization fix (1 table / N tables).

Includes the 0.54.11 release-cut.

Co-authored-by: pcernik-grpn <pcernik-grpn@users.noreply.github.com>
This commit is contained in:
pcernik-grpn 2026-05-14 15:18:35 +02:00 committed by GitHub
parent 1b0329e8c5
commit 840c68ff1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 57 additions and 48 deletions

View file

@ -10,6 +10,24 @@ CalVer image tags (`stable-YYYY.MM.N`, `dev-YYYY.MM.N`) are produced for every C
## [Unreleased]
## [0.54.11] — 2026-05-14
### Changed
- Catalog page: each `catalog_data` bucket now renders as its own
top-level Data Package card instead of being nested as a collapsible
accordion under a single "Core Business Data" wrapper. The page hero
title ("Data Packages") now describes the actual visual structure, and
the card grain matches the `bucket` column on `table_registry`. Tables
inside each package are flat-listed (no per-bucket accordion),
mirroring the existing `Agnes Internal` card; the `Agnes Internal` and
`Business Metrics` cards themselves are unchanged. Per-table sync info
("Synced …" / "Queried directly from BigQuery") on each row is
preserved. The aggregate meta line ("N tables · ~M rows total ·
Synced X") on the old wrapper is dropped with no replacement — the
global sync timestamp is no longer shown on this page. An instance
with zero registered tables now renders no Data Package cards at all,
where the old wrapper always rendered (showing "0 tables").
## [0.54.10] — 2026-05-14
### Changed

View file

@ -1332,7 +1332,13 @@
<!-- ═══════════════ SOURCE CARDS ═══════════════ -->
<div class="source-cards">
<!-- ── Card 1: Core Business Data ── -->
{# ── Data Packages: one source-card per bucket ─────────────────────
Previously all buckets were nested as accordions under a single
"Core Business Data" wrapper card. Each bucket is now its own
top-level Data Package card, matching the page hero title and
the bucket grain of the table_registry. The Internal and
Business Metrics cards below follow the same flat-list pattern. #}
{% for category in catalog_data %}
<div class="source-card">
<div class="source-card-header">
<div class="source-card-left">
@ -1346,63 +1352,48 @@
</svg>
</div>
<div class="source-card-info">
<div class="source-card-name">Core Business Data</div>
<div class="source-card-desc">Core business data from internal systems</div>
<div class="source-card-meta">
{{ data_stats.total_tables or data_stats.tables }} tables &middot; ~{{ data_stats.rows_display }} rows total
{% if data_stats.last_updated %}
&middot; Synced {{ data_stats.last_updated }}
{% endif %}
</div>
<div class="source-card-name">{{ category.name }}</div>
<div class="source-card-meta">{{ category.count }} table{{ 's' if category.count != 1 else '' }}</div>
</div>
</div>
</div>
{% for category in catalog_data %}
<div class="accordion-category">
<button class="accordion-trigger" onclick="toggleAccordion(this)">
<svg class="accordion-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
{{ category.name }}
<span class="accordion-count">{{ category.count }} tables</span>
</button>
<div class="accordion-content">
{% for table in category.tables %}
<div class="table-row" {% if table.query_mode != 'remote' %}onclick="openProfiler('{{ table.name }}')"{% endif %}>
<div class="table-row-left">
<div class="table-row-name">
{{ table.name }}
{% if table.query_mode == 'remote' %}
<span class="query-mode-badge live">Live</span>
{% else %}
<span class="query-mode-badge local">Local</span>
{% endif %}
</div>
<div class="table-row-desc">{{ table.description }}</div>
<div class="table-sync-info">
{% if table.query_mode == 'remote' %}
<span class="live-dot"></span> Queried directly from BigQuery
{% elif table.last_sync %}
Synced {{ table.last_sync }}
{% endif %}
</div>
{# Plain list — tables shown directly; no accordion since the card IS the package. #}
<div class="accordion-content expanded" style="display: block;">
{% for table in category.tables %}
<div class="table-row" {% if table.query_mode != 'remote' %}onclick="openProfiler('{{ table.name }}')"{% endif %}>
<div class="table-row-left">
<div class="table-row-name">
{{ table.name }}
{% if table.query_mode == 'remote' %}
<span class="query-mode-badge live">Live</span>
{% else %}
<span class="query-mode-badge local">Local</span>
{% endif %}
</div>
<div class="table-row-right">
<span class="rows-badge{{ ' large' if table.rows_large }}">{{ table.rows_display }}</span>
{% if table.query_mode != 'remote' %}
<span class="profile-link">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
Profile
</span>
<div class="table-row-desc">{{ table.description }}</div>
<div class="table-sync-info">
{% if table.query_mode == 'remote' %}
<span class="live-dot"></span> Queried directly from BigQuery
{% elif table.last_sync %}
Synced {{ table.last_sync }}
{% endif %}
</div>
</div>
{% endfor %}
<div class="table-row-right">
<span class="rows-badge{{ ' large' if table.rows_large }}">{{ table.rows_display }}</span>
{% if table.query_mode != 'remote' %}
<span class="profile-link">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7z"/><circle cx="12" cy="12" r="3"/></svg>
Profile
</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
{% endfor %}
{# ── Card: Agnes Internal ─────────────────────────────────────────
Renders the three system tables (agnes_sessions / agnes_telemetry /

View file

@ -1,6 +1,6 @@
[project]
name = "agnes-the-ai-analyst"
version = "0.54.10"
version = "0.54.11"
description = "Agnes — AI Data Analyst platform for AI analytical systems"
requires-python = ">=3.11,<3.14"
license = "MIT"