mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-23 19:46:39 +00:00
fix(frontend): suppress ?q= storage restore when ?qs= is present
When `/knowledges` is opened via a `?qs=…` link, `useTableState`'s
mount-time restore was injecting the previous session's `?q=` from
storage on top of it — so a clean semantic-search URL silently became
`?qs=foo&q=python` and the user got a narrowed result set they didn't
ask for.
Added `skipRestore` to `useTableState` (defaults to `false`, captured
via a ref at mount so a later toggle doesn't replay a restore the user
has worked past). `knowledges.tsx` passes `searchParams.has('qs')` so
the restore is skipped exactly when the parameter is part of the
landing URL.
Mirror-to-storage on subsequent filter changes is unaffected — a
client filter the user actually types still persists to storage for
the next session.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
2a4417505a
commit
4430cfc329
@@ -36,6 +36,18 @@ interface UseTableStateOptions {
|
||||
filterParamName?: string;
|
||||
/** Query string param for the 1-based page number. Default `URL_PARAMS.PAGE` (`'page'`). */
|
||||
pageParamName?: string;
|
||||
/**
|
||||
* Suppresses the one-time storage → URL restore on mount. Use on pages
|
||||
* that route the `?q=` filter alongside a sibling URL parameter with
|
||||
* its own filter semantics — e.g. `/knowledges` combines `?q=` (client
|
||||
* text filter) with `?qs=` (server semantic search). Restoring a
|
||||
* previously-typed `?q=` on top of a freshly-opened `?qs=` link would
|
||||
* silently narrow the search result the user navigated to. The caller
|
||||
* decides per-mount whether restore should fire; the value is captured
|
||||
* via a ref at mount time so a later toggle doesn't replay a restore
|
||||
* the user has since worked past.
|
||||
*/
|
||||
skipRestore?: boolean;
|
||||
/**
|
||||
* Stable storage key for persisting the filter value (a fresh tab without
|
||||
* `?<filterParamName>=` resumes from here). Defaults to
|
||||
@@ -86,6 +98,7 @@ export function useTableState(options: UseTableStateOptions = {}): UseTableState
|
||||
debounceMs = 200,
|
||||
filterParamName = URL_PARAMS.QUERY,
|
||||
pageParamName = URL_PARAMS.PAGE,
|
||||
skipRestore = false,
|
||||
storageKey: explicitStorageKey,
|
||||
} = options;
|
||||
|
||||
@@ -154,6 +167,11 @@ export function useTableState(options: UseTableStateOptions = {}): UseTableState
|
||||
// exactly once per storageKey rotation — `restoredForKeyReference`
|
||||
// guards against repeating the replay on every render.
|
||||
const restoredForKeyReference = useRef<null | string>(null);
|
||||
// Snapshot the `skipRestore` decision at mount via a ref so a later
|
||||
// toggle (e.g. the user clearing `?qs=`) doesn't fire the restore
|
||||
// mid-session — by then they've already engaged with the page and a
|
||||
// surprise URL mutation would be jarring.
|
||||
const skipRestoreRef = useRef(skipRestore);
|
||||
|
||||
useEffect(() => {
|
||||
if (restoredForKeyReference.current === storageKey) {
|
||||
@@ -162,6 +180,10 @@ export function useTableState(options: UseTableStateOptions = {}): UseTableState
|
||||
|
||||
restoredForKeyReference.current = storageKey;
|
||||
|
||||
if (skipRestoreRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (filter.length > 0) {
|
||||
// URL already has a value — that beats storage. Mirror it back
|
||||
// into storage so a fresh tab without `?q=` resumes from this
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ColumnDef } from '@tanstack/react-table';
|
||||
|
||||
import { Ellipsis, LibraryBig, Loader2, Pencil, PencilLine, Plus, Trash } from 'lucide-react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { useLocation, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
import type { BadgeVariant } from '@/components/ui/badge';
|
||||
@@ -27,7 +27,7 @@ import { SidebarTrigger } from '@/components/ui/sidebar';
|
||||
import { StatusCard } from '@/components/ui/status-card';
|
||||
import { KnowledgeDocType } from '@/graphql/types';
|
||||
import { useTableState } from '@/hooks/use-table-state';
|
||||
import { mergeHrefWithSearchParams } from '@/lib/url-params';
|
||||
import { mergeHrefWithSearchParams, URL_PARAMS } from '@/lib/url-params';
|
||||
import { type Knowledge, useKnowledges } from '@/providers/knowledges-provider';
|
||||
|
||||
const docTypeBadgeVariant: Record<KnowledgeDocType, BadgeVariant> = {
|
||||
@@ -63,7 +63,16 @@ function Knowledges() {
|
||||
const [isRenameLoading, setIsRenameLoading] = useState(false);
|
||||
const editingInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const { filter, setFilter } = useTableState();
|
||||
// When the user lands on a `?qs=` link (server semantic search) we
|
||||
// must suppress the storage→URL `?q=` restore. Re-injecting a previous
|
||||
// session's client filter on top of a fresh semantic-search URL would
|
||||
// silently narrow the result set behind the user's back.
|
||||
// `useTableState` reads `skipRestore` once at mount via a ref, so a
|
||||
// later toggle (user clears `?qs=`) won't replay the restore.
|
||||
const [initialParams] = useSearchParams();
|
||||
const { filter, setFilter } = useTableState({
|
||||
skipRestore: initialParams.has(URL_PARAMS.SEARCH),
|
||||
});
|
||||
|
||||
const handleOpen = useCallback(
|
||||
(id: string) => {
|
||||
|
||||
Reference in New Issue
Block a user