Архивация списков (#9)
Tests / frontend-test (push) Successful in 1m12s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/9
This commit was merged in pull request #9.
This commit is contained in:
2026-08-19 09:07:53 +00:00
parent 3a71d0df1f
commit 6f789f8f1c
67 changed files with 2617 additions and 901 deletions
@@ -4,6 +4,7 @@ import { getLinkedTypes, hydratePendingAuthors, searchMyRequests } from './myReq
import { IMyRequest } from './models/IMyRequest';
import { IRequestType, StatusBadge } from '../../shared/approval';
import { onRequestsChanged } from '../../shared/requestEvents';
import { traced } from './perfTrace';
import { useRoutedQuery } from '../../shared/usePersistedQuery';
import { pageKey, pageSignature, readPage, writePage } from './pageCache';
import { Pager } from './Pager';
@@ -66,7 +67,7 @@ const Table: React.FC<{ rows: IMyRequest[]; onOpen: (request: IMyRequest) => voi
<table className={styles.table}>
<thead>
<tr>
<th className={styles.colId}>ID</th>
<th className={styles.colId}>Код</th>
<th className={styles.colType}>Тип</th>
<th className={styles.colTitle}>Название</th>
<th className={styles.colDate}>Дата</th>
@@ -91,9 +92,10 @@ const Table: React.FC<{ rows: IMyRequest[]; onOpen: (request: IMyRequest) => voi
}
}}
>
<td className={styles.colId}>{r.id}</td>
{/* Код заявки, а не Id элемента — см. IMyRequest.code и колонки в RequestsTableView. */}
<td className={styles.colId}>{r.code || `#${r.id}`}</td>
<td className={styles.colType}>{r.requestTypeName}</td>
<td className={styles.colTitle}>{r.title || `#${r.id}`}</td>
<td className={styles.colTitle}>{r.title || r.code || `#${r.id}`}</td>
<td className={styles.colDate}>{formatDate(r.created)}</td>
<td className={styles.colAuthor}>
{[r.authorName, r.authorEmail].filter(Boolean).join(' · ') || '—'}
@@ -182,13 +184,16 @@ export const SearchView: React.FC<ISearchViewProps> = ({
setRows(cached ? cached.rows : undefined);
setTotalRows(cached ? cached.totalRows : 0);
const load = async (): Promise<void> => {
const load = async (forceRender = false): Promise<void> => {
try {
const fresh = await searchMyRequests(context, types, debouncedQuery);
const fresh = await traced('ИТОГО поиск', () => searchMyRequests(context, types, debouncedQuery));
if (cancelled) return;
applyKnownAuthors(fresh.rows, authors.current);
const prev = readPage(cacheKey);
if (!prev || pageSignature(prev) !== pageSignature(fresh)) {
// forceRender — строки уже спрятаны (см. force ниже) и обязаны
// вернуться, даже если свежий ответ совпал с прежним кешем: иначе
// экран так и останется в «Ищем…» (см. тот же баг в RequestsTableView).
if (forceRender || !prev || pageSignature(prev) !== pageSignature(fresh)) {
writePage(cacheKey, fresh);
setRows(fresh.rows);
setTotalRows(fresh.totalRows);
@@ -202,7 +207,7 @@ export const SearchView: React.FC<ISearchViewProps> = ({
load().catch(() => undefined);
const unsubscribe = onRequestsChanged((force) => {
if (force) setRows(undefined);
load().catch(() => undefined);
load(force).catch(() => undefined);
});
const timer = window.setInterval(() => {
if (!document.hidden) load().catch(() => undefined);