Архивация списков #9
@@ -16,6 +16,7 @@ import { IMyRequest } from './models/IMyRequest';
|
||||
import { DataTable, IDataTableColumn } from '@tnsu/ui-kit';
|
||||
import { REQUEST_STATUS, REQUEST_STATUS_CHOICES, IRequestType, StatusBadge } from '../../shared/approval';
|
||||
import { onRequestsChanged } from '../../shared/requestEvents';
|
||||
import { traced } from './perfTrace';
|
||||
import { useRoutedQuery } from '../../shared/usePersistedQuery';
|
||||
import { IPage, pageKey, pageSignature, readPage, writePage } from './pageCache';
|
||||
import { Pager } from './Pager';
|
||||
@@ -394,7 +395,7 @@ export const RequestsTableView: React.FC<IRequestsTableViewProps> = ({
|
||||
|
||||
const load = async (forceRender = false): Promise<void> => {
|
||||
try {
|
||||
const fresh = await fetchPage();
|
||||
const fresh = await traced(`ИТОГО таблица:${view}#${page}`, fetchPage);
|
||||
if (cancelled) return;
|
||||
|
||||
// Перерисовываем, только если данные реально изменились — иначе при
|
||||
|
||||
@@ -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';
|
||||
@@ -184,7 +185,7 @@ export const SearchView: React.FC<ISearchViewProps> = ({
|
||||
|
||||
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);
|
||||
|
||||
@@ -232,6 +232,10 @@ export interface INavCounts {
|
||||
// своим запросом — но параллельно, и ровно тем же вызовом, что наполняет саму
|
||||
// вкладку: иначе счётчик и список могли бы разойтись.
|
||||
export async function getNavCounts(context: WebPartContext): Promise<INavCounts> {
|
||||
return traced('ИТОГО getNavCounts', () => getNavCountsInner(context));
|
||||
}
|
||||
|
||||
async function getNavCountsInner(context: WebPartContext): Promise<INavCounts> {
|
||||
const types = await getLinkedTypes(context);
|
||||
|
||||
const [turn, rework] = await Promise.all([
|
||||
@@ -352,8 +356,15 @@ async function indexApprovalsForPartition(
|
||||
const sp = spForSite(target.siteUrl, context);
|
||||
const list = sp.web.getList(target.listId);
|
||||
|
||||
const dataListInfo = await traced(`dataListTitle:${type.name}#${target.listId}`, () => list.select('Title')());
|
||||
const dataTitle = (dataListInfo.Title as string) || '';
|
||||
// target.title — из bulk-ответа /api/request-types/lists, уже загруженного
|
||||
// при старте страницы (см. IListTarget.title): 11 партиций — это 11 лишних
|
||||
// REST-запросов только за тем, что уже пришло бесплатно одним запросом.
|
||||
// REST — только если реестр партиций был недоступен (see listTargetsForType),
|
||||
// тогда Title взять больше неоткуда.
|
||||
const dataTitle =
|
||||
target.title ??
|
||||
((await traced(`dataListTitle:${type.name}#${target.listId}`, () => list.select('Title')())).Title as string) ??
|
||||
'';
|
||||
if (!DATA_LIST_SUFFIX.test(dataTitle)) {
|
||||
debug.approvalSkippedReason = `«${dataTitle}» не оканчивается на «— данные» — список согласования не ищем`;
|
||||
return debug;
|
||||
@@ -707,6 +718,14 @@ export interface IListTarget {
|
||||
siteUrl: string;
|
||||
/** Абсолютный префикс пути элементов этого списка, со слешем на конце. */
|
||||
prefix: string;
|
||||
/**
|
||||
* Title списка данных на момент регистрации партиции (см. IListPartition.title) —
|
||||
* уже пришёл бесплатно вместе с bulk-ответом /api/request-types/lists при
|
||||
* старте страницы. Заполнен только когда партиция известна реестру; для
|
||||
* фолбэка по RequestType.listId (реестр недоступен) — undefined, тогда
|
||||
* indexApprovalsForPartition сам дочитает Title через REST.
|
||||
*/
|
||||
title?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,7 +750,8 @@ export function listTargetsForType(type: IRequestType): IListTarget[] {
|
||||
return partitions.map((p) => ({
|
||||
listId: p.listId,
|
||||
siteUrl: p.siteUrl,
|
||||
prefix: `${siteOrigin(p.siteUrl).replace(/\/+$/, '')}${p.listId.replace(/\/+$/, '')}/`
|
||||
prefix: `${siteOrigin(p.siteUrl).replace(/\/+$/, '')}${p.listId.replace(/\/+$/, '')}/`,
|
||||
title: p.title
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,20 +3,15 @@
|
||||
* (индекс согласований, свои заявки по типу, конкретная партиция, Search),
|
||||
* а не просто «страница долго грузится».
|
||||
*
|
||||
* Включение/выключение БЕЗ пересборки — из консоли браузера:
|
||||
* window.rpPerfTrace = true // писать тайминги
|
||||
* window.rpPerfTrace = false // выключить (по умолчанию)
|
||||
* ВРЕМЕННО: пишет всегда, без флага-переключателя — этот модуль и все traced()
|
||||
* вокруг снимаются целиком, как только разбор текущей проблемы с
|
||||
* производительностью закончится (см. myRequests.service.ts, RequestsTableView.tsx,
|
||||
* SearchView.tsx).
|
||||
*/
|
||||
function enabled(): boolean {
|
||||
return !!(window as unknown as { rpPerfTrace?: boolean }).rpPerfTrace;
|
||||
}
|
||||
|
||||
const PREFIX = '[Перф]';
|
||||
|
||||
/** Оборачивает async-шаг замером времени. Без включённой трассировки — просто вызывает fn(). */
|
||||
/** Оборачивает async-шаг замером времени. */
|
||||
export async function traced<T>(label: string, fn: () => Promise<T>): Promise<T> {
|
||||
if (!enabled()) return fn();
|
||||
|
||||
const start = performance.now();
|
||||
try {
|
||||
return await fn();
|
||||
|
||||
Reference in New Issue
Block a user