Skip to content

ui: the generated dashboard takes the shape of what each tile holds (#7412) - #7413

Merged
delchev merged 1 commit into
masterfrom
harmonia3-dashboard
Sep 17, 2026
Merged

delchev merged 1 commit into
masterfrom
harmonia3-dashboard

Conversation

@himchev

@himchev himchev commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Cause

The dashboard's tiles were assembled inside the card rather than from it - the label a hbox of
uppercase utility classes, the value a bare <p class="text-3xl font-bold">, the hint a second
paragraph - leaving the card's own description / title / action / footer slots unused. From there
every tile was framed the same way, though a number, a top-N table, an embedded chart and an
embedded page are four different things.

Change

Two card shapes, because the reference has two. A NUMBER tile uses the slots it was ignoring.
Everything carrying content of its own takes the reference's table-card shape - plain title over its
description, a border-b header, x-h-card-content.flush - except a chart preview, which takes the
padded, borderless chart-card shape.

A report preview now takes the shape of what the embedded page actually draws. The .report has
carried a chart: type all along and the reports store never read it. The chart tile also gets a
taller frame, which is not cosmetic: the report page sizes that surface in vh, and inside an
iframe vh resolves against the FRAME, so a short frame squashed a chart that fills the window on
the report page itself.

The rows inside a preview are framed by the tile's card, so the embedded page drops its own gutter,
box and grid lines when previewed. This is why a ui/perspective/report-file file appears in a
dashboard PR
- it is gated on the preview flag, and preview mode has exactly two callers, this
dashboard and the platform application shell's, so it cannot reach a report page a user opens. The
container's data-border is read ONCE as the directive initializes, where it only adds
border rounded-md, so the preview branch sets those classes directly rather than binding the
attribute and racing Alpine's directive order; data-borders is a pure CSS hook and does bind.

Navigation moves off the title onto a labelled "View all" button - a @click on a <div> is
reachable by neither keyboard nor screen reader. The blocks lose their headings, every tile naming
itself. KPI widgets group by the shape they render as. The dashboard names itself in the breadcrumb
like every other page.

Verified

  • ModelGenerationIT, HarmoniaContractIT, HarmoniaDateFormatIT and IntentEmissionCoverageIT
    green, re-run against the installed jar after each change.
  • Every directive, class and attribute checked against the pinned Harmonia 3.1.2 webjar, including
    how it consumes data-border and data-borders; the two card shapes read from the reference's
    own dashboard source rather than from a screenshot of it.
  • In a browser against a live instance: the whole dashboard at desktop width - number tiles carrying
    their values, the table card's flush borderless rows under a bordered header, both chart cards
    padded and borderless, no block headings, breadcrumb reading Dashboard. The report page opened
    directly still shows its inset, boxed, grid-lined table, which is the path where the mechanism
    changed rather than only the gating.

Not verified

Narrow widths, and the platform application shell's own dashboard, which embeds the same preview and
therefore inherits the table format change.

Out of scope

The status badges and record links the reference shows in its table cells. A .report column
carries table, alias, name, type, aggregate, select, grouping, tId, label, align
and pattern - no status marker, and no row identity, a report row being a GROUP BY aggregate.
Rendering either would mean guessing from a column name; saying it in the model belongs in
engine-intent.

Fixes #7412

🤖 Generated with Claude Code

…7412)

The dashboard's tiles were assembled by hand inside the card rather than from
it: the label a hbox of uppercase utility classes in the header, the value a
bare <p class="text-3xl font-bold"> in the content, the hint a second paragraph
under it. The card's own description, title, action and footer slots went
unused, and each block was headed by a hand-rolled uppercase eyebrow row.

There are two card shapes, because the reference has two. A NUMBER tile uses the
slots it was ignoring - description for the label, title for the value, an icon
avatar in the action, the hint in the footer. Everything carrying content of its
own - a top-N table, an embedded report preview, a custom page - takes the
reference's table-card shape instead: a plain title over its description, a
border-b header, and x-h-card-content.flush, since Harmonia 3 moved padding off
the card surface onto the slots, so a table meant to span the card edge to edge
is the flush modifier now, not a cancelled padding. Navigation moves off the
title and onto a labelled "View all" button: a @click on a <div> is reachable by
neither keyboard nor screen reader.

Key Indicators is grouped by the shape a widget renders as. A scalar is a
compact number tile and a list is a top-N table; sharing one grid, the wide list
tiles left holes around the narrow ones, so each kind gets a row - summaryKpis
and listKpis on dashboardPage.

A report preview tile takes the shape of what the embedded page actually draws.
The .report has carried a chart type all along and the reports store simply did
not read it, so every preview was framed as a table; a report declaring chart:
renders its chart surface and wants the reference's padded, borderless chart
card, while a report without one renders rows and wants the bordered full-bleed
table card. The chart tile is also given a taller frame, which is not cosmetic:
the report page sizes that surface in vh, and inside an iframe vh resolves
against the FRAME, so a short frame squashed a chart that fills the window on
the report page itself.

The rows inside a preview are framed by the tile's card, so the embedded page
drops its own gutter, box and grid lines when it is previewed - gated on the
preview flag, leaving the report a user opens byte-identical. The container's
data-border is read ONCE as the directive initializes, where it only adds
`border rounded-md`, so the preview branch sets those classes directly instead
of binding the attribute and racing Alpine's directive order; data-borders is a
pure CSS hook and does bind. Preview mode has exactly two callers, this
dashboard and the platform application shell's, so the change cannot reach a
report page.

The blocks lose their headings. Every tile names itself, so a heading above them
only repeated what the cards already said, and the reference's dashboard is
likewise bare grids separated by the page's own gap. The page's own
<h3>Dashboard</h3> goes too, and breadcrumbTrail returns a Dashboard crumb
instead of an empty trail - the dashboard now names itself where every other
page does, rather than being the one route whose breadcrumb was a bare home
icon.

A tile's hint rides x-if rather than x-show, and so does the spacer above it.
The header pads its own bottom only while nothing but a <template> follows it -
last-rendered:pb-6 compiles to :not(:has(~:not(template))) - so a hidden-but-
present footer or spacer left a tile with no hint sitting on its bottom edge,
which is the common case: a widget need not declare a description at all.

Deliberately not done: the status badges and record links the reference's table
card shows in its cells. A .report column carries table, alias, name, type,
aggregate, select, grouping, tId, label, align and pattern - no status marker,
and no row identity, a report row being a GROUP BY aggregate. Rendering either
would mean guessing from a column name. Saying it in the model is the fix, and
it belongs in engine-intent rather than here.

Verified: ModelGenerationIT, HarmoniaContractIT, HarmoniaDateFormatIT and
IntentEmissionCoverageIT green, re-run against the installed jar after each
change; every directive, class and attribute checked against the pinned 3.1.2
webjar, including how it consumes data-border and data-borders; and the two card
shapes read from the reference's own dashboard source rather than from its
rendered screenshot.

Also verified in a browser against a live instance, the whole dashboard at
desktop width: the four number tiles carrying their values, the table card's
flush borderless rows under a bordered header, both chart cards padded and
borderless, no block headings, and the breadcrumb reading Dashboard. The report
page opened directly still shows its inset, boxed, grid-lined table - the path
where the mechanism changed rather than only the gating, so the one a regression
would hide in.

Not verified: narrow widths, and the dashboard of the platform application
shell, which embeds the same preview and therefore inherits the table format
change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@delchev
delchev merged commit f8b606f into master Sep 17, 2026
10 checks passed
@delchev
delchev deleted the harmonia3-dashboard branch September 17, 2026 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui: the generated dashboard frames every tile the same way

2 participants