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
22 changes: 22 additions & 0 deletions client/src/components/models/ModelComparison.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import {
import Modal from '../ui/Modal';
import ComparisonResearch from './ComparisonResearch';
import { EFFORT_LADDER, withEstimatedCosts } from '../../lib/effortCostEstimate';
import { safeReadStorage, safeWriteStorage } from '../../lib/safeStorage';

const SETTINGS_STORAGE_KEY = 'portos-model-comparison-settings';

const COLORS = [
'#2563eb', // blue (GPT-5.6 Sol)
Expand Down Expand Up @@ -99,6 +102,25 @@ export default function ModelComparison() {
const [syncError, setSyncError] = useState('');
const [syncing, setSyncing] = useState(false);

// Restore the last-viewed settings from localStorage when the page is opened
// with no query string (a bookmark-free visit), so filters/zoom/scale persist
// across sessions instead of resetting every time. An explicit URL (a shared
// link, browser back/forward) always wins over the stored snapshot.
useEffect(() => {
if (params.toString() !== '') return;
const stored = safeReadStorage(SETTINGS_STORAGE_KEY);
if (!stored) return;
setParams(new URLSearchParams(stored), { replace: true });
// Restore once, on mount only — subsequent param changes are the user
// driving the page, not something to overwrite from storage again.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
const query = params.toString();
if (query) safeWriteStorage(SETTINGS_STORAGE_KEY, query);
}, [params]);

const xMinParam = params.get('xMin');
const xMaxParam = params.get('xMax');
const yMinParam = params.get('yMin');
Expand Down
24 changes: 24 additions & 0 deletions client/src/components/models/ModelComparison.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,27 @@ it('respects initial zoom and stretch URL search parameters', async () => {
expect(screen.getByTestId('yaxis')).toHaveAttribute('data-domain', JSON.stringify([40, 60]));
});

it('persists settings to localStorage and restores them on a fresh visit', async () => {
localStorage.clear();
const { unmount } = render(
<MemoryRouter initialEntries={['/']}>
<ModelComparison />
</MemoryRouter>
);
await act(async () => {});
await screen.findByText(/1 plotted/);

fireEvent.click(screen.getByRole('button', { name: '1.5×' }));
await waitFor(() => expect(localStorage.getItem('portos-model-comparison-settings')).toContain('stretch=1.5'));
unmount();

render(
<MemoryRouter initialEntries={['/']}>
<ModelComparison />
</MemoryRouter>
);
await act(async () => {});
await screen.findByText(/1 plotted/);
expect(screen.getByRole('button', { name: '1.5×' })).toHaveAttribute('aria-pressed', 'true');
});