diff --git a/web/src/views/DashboardView.vue b/web/src/views/DashboardView.vue index 8b8b02f..edc7627 100644 --- a/web/src/views/DashboardView.vue +++ b/web/src/views/DashboardView.vue @@ -161,9 +161,14 @@ function finishSetup() {
- +
+ +
+ +
@@ -173,7 +178,6 @@ function finishSetup() { -
@@ -196,6 +200,10 @@ function finishSetup() { border-right: 1px solid var(--border-soft); } +.db-tail { + padding: 8px 16px 40px; +} + .db-aside { min-width: 0; padding: 32px 8px 40px; @@ -208,6 +216,7 @@ function finishSetup() { @media (max-width: 768px) { .db-body { grid-template-columns: 1fr; } .db-main { border-right: none; } + .db-tail { padding: 0 0 28px; } /* On phones the health summary follows the briefing. */ .db-aside { padding: 8px 0 28px; border-top: 1px solid var(--border-soft); } } diff --git a/web/src/views/__tests__/DashboardView.test.ts b/web/src/views/__tests__/DashboardView.test.ts index aa70af8..ff65825 100644 --- a/web/src/views/__tests__/DashboardView.test.ts +++ b/web/src/views/__tests__/DashboardView.test.ts @@ -405,14 +405,17 @@ describe('DashboardView', () => { }) describe('widget layout', () => { - it('lets the briefing end the main column and keeps health, then performance, beside it', () => { + it('follows the briefing with the week\'s traffic and keeps health, then performance, beside it', () => { const wrapper = makeWrapper({ projects: [{ id: 'p1', name: 'A', slug: 'a' }, { id: 'p2', name: 'B', slug: 'b' }], }) const titles = (column: string) => wrapper.findAll(`${column} .db-sec__title`).map(t => t.text()) - expect(wrapper.find('.db-main > .brief').exists()).toBe(true) - expect(wrapper.findAll('.db-main > *')).toHaveLength(1) - expect(titles('.db-aside')).toEqual(['Vitals · 24h', 'Release health', 'Projects', 'Recent alerts', 'Slowest transactions', 'Traffic · last 7 days']) + const main = wrapper.findAll('.db-main > *') + expect(main).toHaveLength(2) + expect(main[0].classes()).toContain('brief') + expect(main[1].classes()).toContain('db-tail') + expect(titles('.db-tail')).toEqual(['Traffic · last 7 days']) + expect(titles('.db-aside')).toEqual(['Vitals · 24h', 'Release health', 'Projects', 'Recent alerts', 'Slowest transactions']) }) it('fetches widget data only once the dashboard itself is shown', () => { diff --git a/web/src/views/dashboard/TransactionDensityWidget.vue b/web/src/views/dashboard/TransactionDensityWidget.vue index 00a44fd..c64aff8 100644 --- a/web/src/views/dashboard/TransactionDensityWidget.vue +++ b/web/src/views/dashboard/TransactionDensityWidget.vue @@ -100,6 +100,10 @@ function cellColor(v: number): string { :style="cellColor(cell) ? { background: cellColor(cell) } : undefined" /> + +
low
@@ -125,7 +129,7 @@ function cellColor(v: number): string { .db-heatmap__row { display: flex; align-items: center; - gap: 1px; + gap: 2px; margin-bottom: 2px; } @@ -142,7 +146,7 @@ function cellColor(v: number): string { .db-heatmap__cell { position: relative; flex: 1; - height: 9px; + height: 16px; border-radius: 2px; background: var(--surface-2); min-width: 0; @@ -170,6 +174,29 @@ function cellColor(v: number): string { .db-heatmap__cell--legend { flex: none; width: 11px; + height: 11px; +} + +/* Ticks sit over the cell area: the day labels take the first 28px. */ +.db-heatmap__axis { + position: relative; + height: 14px; + margin: 4px 0 0 28px; +} + +.db-heatmap__tick { + position: absolute; + top: 0; + font-size: 10px; + color: var(--text-3); + opacity: 0.5; + font-variant-numeric: tabular-nums; +} + +@media (max-width: 768px) { + .db-heatmap { padding: 8px 0 10px; } + .db-heatmap__row { gap: 1px; } + .db-heatmap__cell { height: 12px; } } .db-heatmap__foot { diff --git a/web/src/views/dashboard/__tests__/widgets.test.ts b/web/src/views/dashboard/__tests__/widgets.test.ts index 2ce873a..628648f 100644 --- a/web/src/views/dashboard/__tests__/widgets.test.ts +++ b/web/src/views/dashboard/__tests__/widgets.test.ts @@ -416,5 +416,6 @@ describe('TransactionDensityWidget', () => { expect(wrapper.findAll('.db-heatmap__row')).toHaveLength(7) expect(wrapper.findAll('.db-heatmap__row .db-heatmap__cell')).toHaveLength(7 * 24) expect(wrapper.find('.db-heatmap__row .db-heatmap__cell').attributes('data-tip')).toMatch(/00:00–01:00 · no events$/) + expect(wrapper.findAll('.db-heatmap__tick').map(t => t.text())).toEqual(['00:00', '06:00', '12:00', '18:00']) }) })