Keep users instance filter and icon search in the URL (#1185)

The instance picker on the users page and the search box on the icon
reference page held their value in component state, so leaving the page
and coming back with the browser history reset them. Both now go through
useTableQueryState like the table filters do, as user.instance and
icon.search.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BastiaanandClaude Opus 5.5 authored and GitHub committed 2026-11-04 15:22:02 +00:00
1 parent b0fb43d678
commit c6867de13d
2 files changed
+21 -4

No files matched your search

@@ -9,6 +9,7 @@ import { useParams } from "react-router-dom";
import { useModPack } from "../model/mod_pack";
import { PrototypeMetadataEntry } from "../store/export_prototype_metadata_store";
import useResourceState from "../util/useResourceState";
import useTableQueryState from "../util/useTableQueryState";
import ResourceState from "./ResourceState";
const { Text } = Typography;
@@ -39,7 +40,9 @@ export default function IconReferencePage() {
let params = useParams();
let modPackId = Number(params.id);
const [filter, setFilter] = useState("");
// Filters live as you type, written to the URL on blur, enter or clear
const queryState = useTableQueryState({ namespace: "icon" });
const filter = queryState.filteredValue("search")?.[0] ?? "";
const [expandedGroups, setExpandedGroups] = useState<Set<string>>(new Set());
const [modPack, synced, error] = useModPack(modPackId);
const state = useResourceState(modPack, synced, error, modPackId);
@@ -137,7 +140,15 @@ export default function IconReferencePage() {
<Input
placeholder="Filter by type or name…"
value={filter}
onChange={e => setFilter(e.target.value)}
onChange={e => {
const values = e.target.value ? [e.target.value] : null;
queryState.setFilter("search", values);
if (!values) {
queryState.commitFilter("search", null);
}
}}
onBlur={() => queryState.commitFilter("search")}
onPressEnter={() => queryState.commitFilter("search")}
allowClear
style={{ width: 320 }}
/>
+8 -2
View File
@@ -20,6 +20,7 @@ import PageLayout from "./PageLayout";
import PluginExtra from "./PluginExtra";
import UsersTable from "./UsersTable";
import { InputInstanceWithAll } from "./InputInstance";
import useTableQueryState from "../util/useTableQueryState";
function CreateUserButton() {
let control = useContext(ControlContext);
@@ -368,7 +369,10 @@ function BulkUserActionButton() {
export default function UsersPage() {
const account = useAccount();
const [instanceId, setInstanceId] = useState<number | null>(null);
// Kept in the URL with the users table state so back/forward restores it
const tableState = useTableQueryState<lib.UserDetails>({ namespace: "user" });
const instanceParam = Number(tableState.filteredValue("instance")?.[0]);
const instanceId = Number.isInteger(instanceParam) ? instanceParam : null;
return <PageLayout nav={[{ name: "Users" }]}>
<PageHeader
@@ -377,7 +381,9 @@ export default function UsersPage() {
{account.hasAllPermission("core.instance.list", "core.instance.subscribe")
&& <InputInstanceWithAll
value={instanceId}
onChange={value => setInstanceId(value as number)}
onChange={value => tableState.commitFilter(
"instance", value === null ? null : [String(value)]
)}
fieldDefinition={{ optional: true } as any}
disabled={false}
/>}