feat(web): URL-состояние вкладок/поиска/фильтров на страницах агентов, списков, правил и статистики
This commit is contained in:
@@ -5,6 +5,7 @@ import { createFileRoute, useNavigate } from '@tanstack/react-router'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'sonner'
|
||||
import type { Filter, FilterFieldConfig } from '@/components/reui/filters'
|
||||
import { searchToFilters, searchToFlag, searchToQ } from '@/lib/search-params'
|
||||
import { PageHeader, PageShell, ResourcePage } from '@/components/reui-kit'
|
||||
import { DataGridColumnHeader } from '@/components/reui/data-grid/data-grid-column-header'
|
||||
import { DataGridPrimaryCell } from '@/components/data-grid-cell'
|
||||
@@ -28,11 +29,23 @@ import {
|
||||
} from '@evofw/ui/components/sheet'
|
||||
import type { PolicySet } from '@evofw/shared'
|
||||
|
||||
type RulesSearch = {
|
||||
create?: boolean
|
||||
q?: string
|
||||
f?: Filter[]
|
||||
}
|
||||
|
||||
/** URL-состояние страницы: create/q/f (deep-link и refresh сохраняют вид). */
|
||||
function parseRulesSearch(search: Record<string, unknown>): RulesSearch {
|
||||
return {
|
||||
create: searchToFlag(search.create),
|
||||
q: searchToQ(search.q),
|
||||
f: searchToFilters(search.f),
|
||||
}
|
||||
}
|
||||
|
||||
export const Route = createFileRoute('/_auth/rules/')({
|
||||
validateSearch: (search: Record<string, unknown>) => ({
|
||||
/** Открыть sheet создания (из ⌘K-палитры). */
|
||||
create: search.create === true || undefined,
|
||||
}),
|
||||
validateSearch: parseRulesSearch,
|
||||
component: PolicySetsPage,
|
||||
})
|
||||
|
||||
@@ -43,16 +56,37 @@ export const Route = createFileRoute('/_auth/rules/')({
|
||||
* Create sheet: https://reui.io/preview/base/sheet-8
|
||||
*/
|
||||
function PolicySetsPage() {
|
||||
const navigate = useNavigate()
|
||||
const navigate = useNavigate({ from: Route.fullPath })
|
||||
const qc = useQueryClient()
|
||||
const setsQ = useQuery(policySetsQueryOptions())
|
||||
const createParam = Route.useSearch().create === true
|
||||
const { create: createParam, q: qParam, f: fParam } = Route.useSearch()
|
||||
const searchQuery = qParam ?? ''
|
||||
const filters = fParam ?? []
|
||||
const [sheetOpenState, setSheetOpenState] = useState(false)
|
||||
const sheetOpen = sheetOpenState || createParam
|
||||
const sheetOpen = sheetOpenState || createParam === true
|
||||
|
||||
/** Обновление URL-состояния (q/f) без перезагрузки. */
|
||||
const setRulesSearch = useCallback(
|
||||
(next: { q?: string; f?: Filter[]; create?: boolean }) => {
|
||||
void navigate({
|
||||
search: (prev) => {
|
||||
const base = parseRulesSearch(prev as Record<string, unknown>)
|
||||
return {
|
||||
create:
|
||||
next.create !== undefined
|
||||
? next.create || undefined
|
||||
: base.create,
|
||||
q: next.q !== undefined ? searchToQ(next.q) : base.q,
|
||||
f: next.f !== undefined ? next.f : base.f,
|
||||
}
|
||||
},
|
||||
replace: true,
|
||||
})
|
||||
},
|
||||
[navigate],
|
||||
)
|
||||
const [name, setName] = useState('')
|
||||
const [description, setDescription] = useState('')
|
||||
const [filters, setFilters] = useState<Filter[]>([])
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
const [deleteId, setDeleteId] = useState<string | null>(null)
|
||||
|
||||
const create = useMutation({
|
||||
@@ -231,11 +265,11 @@ function PolicySetsPage() {
|
||||
getRowId={(r) => r.id}
|
||||
filterFields={filterFields}
|
||||
filters={filters}
|
||||
onFiltersChange={setFilters}
|
||||
onClearFilters={() => setFilters([])}
|
||||
onFiltersChange={(f) => setRulesSearch({ f })}
|
||||
onClearFilters={() => setRulesSearch({ f: [], q: '' })}
|
||||
getFilterFieldValue={getFilterFieldValue}
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
onSearchChange={(q) => setRulesSearch({ q })}
|
||||
searchPlaceholder="Поиск наборов…"
|
||||
getSearchText={getSearchText}
|
||||
isLoading={setsQ.isLoading}
|
||||
|
||||
Reference in New Issue
Block a user