feat(timeline): wire the grouping toggle into the Zeitstrahl page
Add the grouping $state beside the #780 layer-filter state, render the GroupingControl stacked above the filter trigger (disabled, but kept in place, when no loose letters remain), make the meta-line grouping label track the active mode, and thread groupingMode into TimelineView — filter-then-group, no refetch. Refs #827 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -265,3 +265,61 @@ describe('/zeitstrahl curator affordances (#842)', () => {
|
||||
expect(document.querySelector('[data-testid="event-edit"]')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('/zeitstrahl grouping toggle (#827)', () => {
|
||||
const historical = () =>
|
||||
makeEntry({
|
||||
kind: 'EVENT',
|
||||
type: 'HISTORICAL',
|
||||
derived: false,
|
||||
eventId: 'h1',
|
||||
documentId: undefined,
|
||||
title: 'Erster Weltkrieg',
|
||||
senderName: '',
|
||||
receiverName: ''
|
||||
});
|
||||
const mixed = () =>
|
||||
makeTimelineDTO({
|
||||
years: [
|
||||
makeYear(1915, [
|
||||
makeEntry({ documentId: 'd1', title: 'Brief Eins', linkedEventId: 'h1' }),
|
||||
historical()
|
||||
])
|
||||
]
|
||||
});
|
||||
const radio = (value: string) => document.querySelector(`[data-value="${value}"]`) as HTMLElement;
|
||||
|
||||
it('updates the meta-line grouping label when a mode is chosen (REQ-016)', async () => {
|
||||
render(Page, { data: pageData(mixed()) });
|
||||
const meta = page.getByTestId('timeline-meta');
|
||||
await expect.element(meta).toHaveTextContent(m.timeline_grouping_date());
|
||||
radio('event').click();
|
||||
await expect.element(meta).toHaveTextContent(m.timeline_grouping_event());
|
||||
radio('thema').click();
|
||||
await expect.element(meta).toHaveTextContent(m.timeline_grouping_thema());
|
||||
});
|
||||
|
||||
it('regroups loose letters under their event client-side, no buckets in Datum (REQ-002/003)', async () => {
|
||||
render(Page, { data: pageData(mixed()) });
|
||||
expect(document.querySelector('[data-testid="letter-bucket"]')).toBeNull();
|
||||
radio('event').click();
|
||||
await expect.element(page.getByTestId('letter-bucket')).toBeVisible();
|
||||
});
|
||||
|
||||
it('disables the grouping control when the Letters layer is off, keeping the mode (REQ-018)', async () => {
|
||||
render(Page, { data: pageData(mixed()) });
|
||||
radio('thema').click();
|
||||
const control = page.getByTestId('grouping-control');
|
||||
await expect.element(control).toHaveAttribute('aria-disabled', 'false');
|
||||
// turn the Letters layer off → nothing to regroup
|
||||
await page.getByTestId('timeline-filter-trigger').click();
|
||||
await page.getByTestId('timeline-filter-letters').click();
|
||||
await expect.element(control).toHaveAttribute('aria-disabled', 'true');
|
||||
// the chosen mode is retained for when letters return
|
||||
expect(radio('thema').getAttribute('aria-checked')).toBe('true');
|
||||
// re-enabling restores the enabled control with the same mode (no reset to Datum)
|
||||
await page.getByTestId('timeline-filter-letters').click();
|
||||
await expect.element(control).toHaveAttribute('aria-disabled', 'false');
|
||||
expect(radio('thema').getAttribute('aria-checked')).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user