perf(web): свод 2 — состояние вкладки с поколениями запросов
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
900a3c6535
commit
78e06583f4
@ -110,3 +110,51 @@ export function getSvod2RowId(row) {
|
|||||||
if (isPlaceholderRow(row)) return `ph-${row.index}`;
|
if (isPlaceholderRow(row)) return `ph-${row.index}`;
|
||||||
return `${row.data?.header?.source_form}-${row.data?.header?.source_id}-${row.data?.line_id}`;
|
return `${row.data?.header?.source_form}-${row.data?.header?.source_id}-${row.data?.line_id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createSheetPagingState() {
|
||||||
|
return {
|
||||||
|
generation: 0,
|
||||||
|
dataGeneration: 0,
|
||||||
|
pendingQueryKey: '',
|
||||||
|
loadedQueryKey: '',
|
||||||
|
total: 0,
|
||||||
|
facets: null,
|
||||||
|
pages: new Map(),
|
||||||
|
loading: false,
|
||||||
|
error: '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function svod2PagingReducer(state, action) {
|
||||||
|
if (action.generation !== state.generation && action.type !== 'begin') return state;
|
||||||
|
switch (action.type) {
|
||||||
|
case 'begin':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
generation: action.generation,
|
||||||
|
pendingQueryKey: action.queryKey,
|
||||||
|
error: '',
|
||||||
|
loading: action.mode === 'load' ? true : state.loading,
|
||||||
|
...(action.mode === 'load' ? { pages: new Map(), total: 0, facets: null } : {}),
|
||||||
|
};
|
||||||
|
case 'page': {
|
||||||
|
const first = state.dataGeneration !== action.generation;
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
pages: first ? new Map([[action.pageIndex, action.rows]]) : touchPage(state.pages, action.pageIndex, action.rows, action.keepPages),
|
||||||
|
dataGeneration: action.generation,
|
||||||
|
loadedQueryKey: first ? state.pendingQueryKey : state.loadedQueryKey,
|
||||||
|
total: action.total,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
case 'facets':
|
||||||
|
return { ...state, facets: action.facets };
|
||||||
|
case 'fail':
|
||||||
|
if (action.mode === 'scroll') return state;
|
||||||
|
return { ...state, error: action.message, pages: new Map(), total: 0 };
|
||||||
|
case 'settled':
|
||||||
|
return { ...state, loading: false };
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import {
|
|||||||
buildSvod2PageParams,
|
buildSvod2PageParams,
|
||||||
buildSvod2QueryParams,
|
buildSvod2QueryParams,
|
||||||
buildWindowRows,
|
buildWindowRows,
|
||||||
|
createSheetPagingState,
|
||||||
facetsToMaps,
|
facetsToMaps,
|
||||||
getMissingPages,
|
getMissingPages,
|
||||||
getPageCount,
|
getPageCount,
|
||||||
@ -16,6 +17,7 @@ import {
|
|||||||
getWindowRange,
|
getWindowRange,
|
||||||
isPlaceholderRow,
|
isPlaceholderRow,
|
||||||
shouldShowFound,
|
shouldShowFound,
|
||||||
|
svod2PagingReducer,
|
||||||
touchPage,
|
touchPage,
|
||||||
} from './svod2Paging.js';
|
} from './svod2Paging.js';
|
||||||
|
|
||||||
@ -152,3 +154,105 @@ test('getSvod2RowId', () => {
|
|||||||
assert.equal(isPlaceholderRow({ data: {} }), false);
|
assert.equal(isPlaceholderRow({ data: {} }), false);
|
||||||
assert.equal(isPlaceholderRow(undefined), false);
|
assert.equal(isPlaceholderRow(undefined), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const begin = (s, generation, mode, queryKey = 'k') => svod2PagingReducer(s, { type: 'begin', generation, mode, queryKey });
|
||||||
|
const page = (s, generation, pageIndex, rows, total) =>
|
||||||
|
svod2PagingReducer(s, { type: 'page', generation, pageIndex, rows, total, keepPages: [pageIndex] });
|
||||||
|
|
||||||
|
test('начальное состояние вкладки', () => {
|
||||||
|
const s = createSheetPagingState();
|
||||||
|
assert.equal(s.generation, 0);
|
||||||
|
assert.equal(s.dataGeneration, 0);
|
||||||
|
assert.equal(s.total, 0);
|
||||||
|
assert.equal(s.facets, null);
|
||||||
|
assert.equal(s.loading, false);
|
||||||
|
assert.equal(s.error, '');
|
||||||
|
assert.equal(s.pages.size, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('устаревшие page/facets/fail игнорируются', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = begin(s, 2, 'refine');
|
||||||
|
for (const a of [
|
||||||
|
{ type: 'page', generation: 1, pageIndex: 0, rows: [], total: 9 },
|
||||||
|
{ type: 'facets', generation: 1, facets: {} },
|
||||||
|
{ type: 'fail', generation: 1, mode: 'load', message: 'x' },
|
||||||
|
{ type: 'settled', generation: 1 },
|
||||||
|
])
|
||||||
|
assert.equal(svod2PagingReducer(s, a), s);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('load ставит loading и pendingQueryKey, сбрасывает error', () => {
|
||||||
|
const s = begin(createSheetPagingState(), 1, 'load', 'q1');
|
||||||
|
assert.equal(s.loading, true);
|
||||||
|
assert.equal(s.generation, 1);
|
||||||
|
assert.equal(s.pendingQueryKey, 'q1');
|
||||||
|
assert.equal(s.error, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('refine оставляет прежние строки до первого ответа нового поколения', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = page(s, 1, 0, ['a', 'b'], 2);
|
||||||
|
s = svod2PagingReducer(s, { type: 'facets', generation: 1, facets: { total: 2 } });
|
||||||
|
s = svod2PagingReducer(s, { type: 'settled', generation: 1 });
|
||||||
|
s = begin(s, 2, 'refine', 'k2');
|
||||||
|
assert.deepEqual(s.pages.get(0), ['a', 'b']);
|
||||||
|
assert.equal(s.total, 2);
|
||||||
|
assert.deepEqual(s.facets, { total: 2 });
|
||||||
|
assert.equal(s.loading, false);
|
||||||
|
assert.equal(s.pendingQueryKey, 'k2');
|
||||||
|
s = page(s, 2, 0, ['c'], 1);
|
||||||
|
assert.deepEqual([...s.pages.keys()], [0]);
|
||||||
|
assert.deepEqual(s.pages.get(0), ['c']);
|
||||||
|
assert.equal(s.dataGeneration, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('первый ответ поколения ставит loadedQueryKey', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load', 'k');
|
||||||
|
assert.equal(s.loadedQueryKey, '');
|
||||||
|
s = page(s, 1, 0, ['a'], 1);
|
||||||
|
assert.equal(s.loadedQueryKey, 'k');
|
||||||
|
assert.equal(s.dataGeneration, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ошибка догрузки (scroll) не меняет состояние, страница снова среди недостающих', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = page(s, 1, 0, ['a'], 600);
|
||||||
|
assert.equal(svod2PagingReducer(s, { type: 'fail', generation: s.generation, mode: 'scroll', message: 'x' }), s);
|
||||||
|
assert.deepEqual(getMissingPages([0, 1], s.pages, new Set()), [1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ошибка load очищает строки и ставит error', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = page(s, 1, 0, ['a'], 5);
|
||||||
|
s = svod2PagingReducer(s, { type: 'fail', generation: 1, mode: 'load', message: 'x' });
|
||||||
|
assert.equal(s.error, 'x');
|
||||||
|
assert.equal(s.pages.size, 0);
|
||||||
|
assert.equal(s.total, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ошибка refine очищает строки и ставит error', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = page(s, 1, 0, ['a'], 5);
|
||||||
|
s = begin(s, 2, 'refine');
|
||||||
|
s = svod2PagingReducer(s, { type: 'fail', generation: 2, mode: 'refine', message: 'y' });
|
||||||
|
assert.equal(s.error, 'y');
|
||||||
|
assert.equal(s.pages.size, 0);
|
||||||
|
assert.equal(s.total, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('последний total поколения побеждает', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = page(s, 1, 0, ['a'], 5563);
|
||||||
|
s = page(s, 1, 1, ['b'], 5560);
|
||||||
|
assert.equal(s.total, 5560);
|
||||||
|
assert.equal(s.pages.size, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('facets и settled текущего поколения', () => {
|
||||||
|
let s = begin(createSheetPagingState(), 1, 'load');
|
||||||
|
s = svod2PagingReducer(s, { type: 'facets', generation: 1, facets: { total: 3 } });
|
||||||
|
assert.deepEqual(s.facets, { total: 3 });
|
||||||
|
s = svod2PagingReducer(s, { type: 'settled', generation: 1 });
|
||||||
|
assert.equal(s.loading, false);
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user