Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ export const AutoSelectQuickTab: Story = {
}
};

export const QuickRangeCustomEditing: Story = {
args: {
value: '[now-90d TO now]'
},
parameters: {
docs: {
description: {
story: 'A persisted quick range should populate the Custom range fields when the section is opened after the picker mounts.'
}
}
}
};

export const CommandSearchFiltering: Story = {
args: {
value: '[now-5m TO now]'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script lang="ts">
import type { CustomDateRange } from '$features/shared/models';

import DateTime from '$comp/formatters/date-time.svelte';
import { Button } from '$comp/ui/button';
import { Input } from '$comp/ui/input';
Expand Down Expand Up @@ -32,16 +30,21 @@
let startValue = $state('');
let endValue = $state('');

// Initialize custom fields from current value if it's not a common range
// Keep custom fields synchronized with the persisted range. Common ranges stay collapsed,
// but their values must still be available when Custom range is opened after a remount.
$effect(() => {
const isCommon = commonRanges.some((r) => r.value === value);
if (!isCommon && value && typeof value === 'string') {
const range = extractRangeExpressions(value) as CustomDateRange | null;
if (range) {
startValue = range.start ?? '';
endValue = range.end ?? '';
const range = typeof value === 'string' ? extractRangeExpressions(value) : null;
if (range) {
startValue = range.start ?? '';
endValue = range.end ?? '';

if (!commonRanges.some((r) => r.value === value)) {
showCustom = true;
}
} else if (!value) {
startValue = '';
endValue = '';
showCustom = false;
}
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/svelte';
import { describe, expect, it, vi } from 'vitest';

import DateRangePicker from './date-range-picker.svelte';

describe('DateRangePicker', () => {
it('allows applying a custom range after selecting the last 90 days', async () => {
const onselect = vi.fn();
render(DateRangePicker, {
onselect,
value: '[now-30d TO now]'
});

await fireEvent.click(screen.getByRole('button', { name: 'Last 90 days' }));
await fireEvent.click(screen.getByRole('button', { name: 'Custom range' }));

const startInput = screen.getByPlaceholderText('Start: now-1h, 2024-01-01');
const endInput = screen.getByPlaceholderText('End: now, 2024-12-31');
await fireEvent.input(startInput, { target: { value: 'now-1y' } });
await fireEvent.input(endInput, { target: { value: 'now' } });

const applyButton = screen.getByRole('button', { name: 'Apply' });
await waitFor(() => expect((applyButton as HTMLButtonElement).disabled).toBe(false));
await fireEvent.click(applyButton);

expect(onselect).toHaveBeenLastCalledWith('[now-1y TO now]');
});

it('initializes a persisted common range after the picker is remounted', async () => {
const onselect = vi.fn();
const initialRender = render(DateRangePicker, { onselect, value: '[now-30d TO now]' });

await fireEvent.click(screen.getByRole('button', { name: 'Last 90 days' }));
expect(onselect).toHaveBeenLastCalledWith('[now-90d TO now]');
initialRender.unmount();

render(DateRangePicker, { onselect, value: '[now-90d TO now]' });
await fireEvent.click(screen.getByRole('button', { name: 'Custom range' }));

const startInput = screen.getByPlaceholderText('Start: now-1h, 2024-01-01');
const endInput = screen.getByPlaceholderText('End: now, 2024-12-31');
expect((startInput as HTMLInputElement).value).toBe('now-90d');
expect((endInput as HTMLInputElement).value).toBe('now');
await fireEvent.input(startInput, { target: { value: 'now-1y' } });

const applyButton = screen.getByRole('button', { name: 'Apply' });
await waitFor(() => expect((applyButton as HTMLButtonElement).disabled).toBe(false));
await fireEvent.click(applyButton);

expect(onselect).toHaveBeenLastCalledWith('[now-1y TO now]');
});
});