feat: фильтры таблиц заявок запоминаются, видно какие включены
Tests / frontend-test (push) Failing after 2m11s
Tests / frontend-test (push) Failing after 2m11s
Пользователи жаловались, что фильтры постоянно сбрасываются. Тип, статус, период и сортировка теперь хранятся в localStorage — отдельно на каждого пользователя и таблицу, с проверкой значений при чтении. Чтобы забытый фильтр не выглядел как «пропали заявки», над таблицей строка «Включены фильтры» с чипами, «Сбросить все» (чистит и хранилище) и «Показано X из Y». Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,8 @@ import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
||||
import { IPage, pageKey, pageSignature, readPage, writePage } from './pageCache';
|
||||
import { Pager } from './Pager';
|
||||
import { RequestsFilterBar } from './RequestsFilterBar';
|
||||
import { ActiveFiltersBar } from './ActiveFiltersBar';
|
||||
import { effectiveUserEmail } from '../../shared/impersonation';
|
||||
import { RequestHistoryDialog } from './RequestHistoryDialog';
|
||||
import { SortableHeader } from './SortableHeader';
|
||||
import { filterRows, hasActiveFilters, ISortState, SortKey, sortRows } from './requestsTableFilters';
|
||||
@@ -441,6 +443,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
// нет — всё как раньше.
|
||||
const refinement = useTableRefinement({
|
||||
tableKey: `${view}|${allRequestsType?.id ?? ''}`,
|
||||
storageScope: effectiveUserEmail(context),
|
||||
statusFromRoute: view === 'own:created',
|
||||
routeStatus: statusFilter,
|
||||
onRouteStatusChange: onStatusFilterChange,
|
||||
@@ -454,6 +457,10 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
// Листание страниц и смена фильтра его переиспользуют (заново по сети не
|
||||
// идём), а автообновление и rp-requests-changed перечитывают.
|
||||
const fullListRef = React.useRef<{ key: string; rows: IMyRequest[] } | undefined>(undefined);
|
||||
// Сколько заявок в разделе БЕЗ фильтров — для «Показано 3 из 10» в строке
|
||||
// включённых фильтров. undefined — неизвестно (постраничная загрузка или
|
||||
// статус из маршрута уже сузил список на сервере): тогда пишем просто «Показано 3».
|
||||
const [unfilteredTotal, setUnfilteredTotal] = React.useState<number | undefined>(undefined);
|
||||
|
||||
// Какой ИМЕННО таблице принадлежат лежащие в состоянии rows/totalRows.
|
||||
// Компонент один на все разделы (см. LIST_VIEWS в RequestPortal), поэтому при
|
||||
@@ -654,6 +661,11 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
setRows(fresh.rows);
|
||||
setTotalRows(fresh.totalRows);
|
||||
}
|
||||
const full = fullListRef.current;
|
||||
const narrowedByRouteStatus = view === 'own:created' && !!statusFilter;
|
||||
setUnfilteredTotal(
|
||||
isRefined && !narrowedByRouteStatus && full && full.key === fullKey ? full.rows.length : undefined
|
||||
);
|
||||
// Данные точно от текущей таблицы — теперь по ним можно судить о
|
||||
// количестве страниц (см. сброс страницы ниже).
|
||||
setLoadedKey(dataKey);
|
||||
@@ -720,6 +732,18 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
if (rows && page > totalPages) onPageChange(totalPages);
|
||||
}, [loadedKey, dataKey, rows, page, totalPages, onPageChange]);
|
||||
|
||||
// Запомненный тип заявки, которого больше нет среди доступных пользователю
|
||||
// (тип убрали или доступ к нему отозвали), — снимаем: иначе таблица навсегда
|
||||
// осталась бы пустой по фильтру, который в выпадающем списке даже не выбрать.
|
||||
const storedTypeId = refinement.barFilters.typeId;
|
||||
React.useEffect(() => {
|
||||
if (view === 'all' || !types || storedTypeId === undefined) return;
|
||||
if (types.some((t) => t.id === storedTypeId)) return;
|
||||
refinement.onFiltersChange({ ...refinement.barFilters, typeId: undefined });
|
||||
// refinement пересобирается на каждый рендер — реагируем только на сам тип и справочник.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [view, types, storedTypeId]);
|
||||
|
||||
return (
|
||||
<section className={styles.view}>
|
||||
<div className={styles.head}>
|
||||
@@ -743,10 +767,21 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
types={view === 'all' ? undefined : types}
|
||||
// Статус — там же, где его колонка: в остальных разделах он у всех строк один.
|
||||
showStatus={columnsFor(view, '').status}
|
||||
canReset={refinement.canReset}
|
||||
// При включённых фильтрах сброс — в строке ActiveFiltersBar («Сбросить все»);
|
||||
// здесь кнопка остаётся только для случая «изменена одна сортировка».
|
||||
canReset={refinement.canReset && !hasActiveFilters(refinement.barFilters)}
|
||||
onReset={refinement.onReset}
|
||||
/>
|
||||
|
||||
<ActiveFiltersBar
|
||||
filters={refinement.barFilters}
|
||||
types={types}
|
||||
onChange={refinement.onFiltersChange}
|
||||
onReset={refinement.onReset}
|
||||
shown={loaded ? total : undefined}
|
||||
total={unfilteredTotal}
|
||||
/>
|
||||
|
||||
{error && <div className={styles.error}>Не удалось загрузить заявки: {error}</div>}
|
||||
{deleteError && <div className={styles.error}>{deleteError}</div>}
|
||||
{!error && !loaded && <div className={styles.empty}>Загрузка…</div>}
|
||||
|
||||
Reference in New Issue
Block a user