diff --git a/packages/app/cypress/e2e/quick-range-chips.cy.ts b/packages/app/cypress/e2e/quick-range-chips.cy.ts
new file mode 100644
index 00000000..dba5e247
--- /dev/null
+++ b/packages/app/cypress/e2e/quick-range-chips.cy.ts
@@ -0,0 +1,46 @@
+/**
+ * Tests for the inline QuickRangeChips that sit under the date-range picker
+ * in the Inference tab. Verifies the chips render only when a GPU is selected
+ * (and therefore a date range is needed), that clicking applies a range, and
+ * that the URL-restored range round-trips back to an active chip.
+ */
+describe('QuickRangeChips — inline below date-range trigger', () => {
+ beforeEach(() => {
+ cy.window().then((win) => {
+ win.localStorage.setItem('inferencex-star-modal-dismissed', String(Date.now()));
+ });
+ });
+
+ it('does not render the chips when no GPU is selected', () => {
+ cy.visit('/inference');
+ cy.get('[data-testid="inference-chart-display"]').should('exist');
+ cy.get('[data-testid="quick-range-chips"]').should('not.exist');
+ });
+
+ it('renders the inline chips when a GPU is selected via URL', () => {
+ cy.visit('/inference?i_gpus=b200_sglang');
+ cy.get('[data-testid="inference-chart-display"]').should('exist');
+ cy.get('[data-testid="quick-range-chips"]', { timeout: 15000 }).should('be.visible');
+ cy.get('[data-testid="quick-range-chip-all"]').should('exist');
+ cy.get('[data-testid="quick-range-chip-ytd"]').should('exist');
+ cy.get('[data-testid="quick-range-chip-90d"]').should('exist');
+ cy.get('[data-testid="quick-range-chip-30d"]').should('exist');
+ cy.get('[data-testid="quick-range-chip-7d"]').should('exist');
+ });
+
+ it('lights up the matching chip when the URL range equals the "All" extent', () => {
+ cy.visit('/inference?i_gpus=b200_sglang');
+ cy.get('[data-testid="quick-range-chips"]', { timeout: 15000 }).should('be.visible');
+ cy.get('[data-testid="quick-range-chip-all"]').click();
+ cy.get('[data-testid="quick-range-chip-all"]').should('have.attr', 'data-active', 'true');
+ cy.get('[data-testid="quick-range-chip-all"]').should('have.attr', 'aria-pressed', 'true');
+ });
+
+ it('clicking a chip updates the date-range trigger label', () => {
+ cy.visit('/inference?i_gpus=b200_sglang');
+ cy.get('[data-testid="quick-range-chips"]', { timeout: 15000 }).should('be.visible');
+ cy.get('[data-testid="quick-range-chip-all"]').click();
+ // Trigger label should now show the start - end date pair, not the placeholder
+ cy.contains('button', 'Select date range').should('not.exist');
+ });
+});
diff --git a/packages/app/src/components/inference/ui/ChartControls.tsx b/packages/app/src/components/inference/ui/ChartControls.tsx
index 0b1705b0..3a4e0c71 100644
--- a/packages/app/src/components/inference/ui/ChartControls.tsx
+++ b/packages/app/src/components/inference/ui/ChartControls.tsx
@@ -13,6 +13,7 @@ import {
import { DateRangePicker } from '@/components/ui/date-range-picker';
import { LabelWithTooltip } from '@/components/ui/label-with-tooltip';
import { MultiSelect } from '@/components/ui/multi-select';
+import { QuickRangeChips } from '@/components/ui/quick-range-chips';
import {
Select,
SelectContent,
@@ -343,6 +344,14 @@ export default function ChartControls({ hideGpuComparison = false }: ChartContro
: ''
}
/>
+ {dateRangeAvailableDates && dateRangeAvailableDates.length >= 2 && (
+
+ )}
)}
diff --git a/packages/app/src/components/ui/date-range-picker.tsx b/packages/app/src/components/ui/date-range-picker.tsx
index 24cbc8b3..11715fc9 100644
--- a/packages/app/src/components/ui/date-range-picker.tsx
+++ b/packages/app/src/components/ui/date-range-picker.tsx
@@ -25,6 +25,7 @@ import {
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog';
+import { QuickRangeChips } from '@/components/ui/quick-range-chips';
import { cn } from '@/lib/utils';
export interface DateRange {
@@ -180,6 +181,19 @@ export function DateRangePicker({
)}
+ {availableDates && availableDates.length >= 2 && (
+
+
+ Quick range:
+
+ setTempRange(range)}
+ source="dialog"
+ />
+
+ )}
{error && {error}
}
-
- {availableDates && availableDates.length >= 2 ? (
-
- {[
- {
- label: 'Max Range',
- getRange: () => ({
- startDate: availableDates[0],
- endDate: availableDates.at(-1)!,
- }),
- },
- {
- label: 'Last 90 Days',
- getRange: () => {
- const cutoff = new Date();
- cutoff.setDate(cutoff.getDate() - 90);
- const cutoffStr = cutoff.toISOString().slice(0, 10);
- const filtered = availableDates.filter((d) => d >= cutoffStr);
- if (filtered.length < 2) return null;
- return { startDate: filtered[0], endDate: filtered.at(-1)! };
- },
- },
- {
- label: 'Last 30 Days',
- getRange: () => {
- const cutoff = new Date();
- cutoff.setDate(cutoff.getDate() - 30);
- const cutoffStr = cutoff.toISOString().slice(0, 10);
- const filtered = availableDates.filter((d) => d >= cutoffStr);
- if (filtered.length < 2) return null;
- return { startDate: filtered[0], endDate: filtered.at(-1)! };
- },
- },
- ].map(({ label, getRange }) => {
- const range = getRange();
- if (!range) return null;
- return (
-
- );
- })}
-
- ) : (
-
- )}
+