mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(stalker): enhance pagination handling and add search phrase management
Entire-Checkpoint: c6e522b4276c
This commit is contained in:
1 parent
efa0385fc8
commit
cd111b6c36
5 files changed
+442
-14
No files matched your search
@@ -3,10 +3,12 @@ import {
|
||||
addStalkerPortal,
|
||||
addXtreamPortal,
|
||||
clickCategoryByNameExact,
|
||||
clickFirstGridListCard,
|
||||
closeElectronApp,
|
||||
defaultXtreamPassword,
|
||||
defaultXtreamUsername,
|
||||
expect,
|
||||
expectPathname,
|
||||
launchElectronApp,
|
||||
openWorkspaceSection,
|
||||
resetMockServers,
|
||||
@@ -15,6 +17,7 @@ import {
|
||||
waitForXtreamWorkspaceReady,
|
||||
} from './electron-test-fixtures';
|
||||
import {
|
||||
fetchStalkerCategoryFixture,
|
||||
fetchXtreamLiveFixture,
|
||||
fetchXtreamSeriesFixture,
|
||||
fetchXtreamVodFixture,
|
||||
@@ -28,7 +31,10 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
request,
|
||||
}) => {
|
||||
await resetMockServers(request, ['xtream']);
|
||||
const fixture = await fetchXtreamLiveFixture(request, xtreamCredentials);
|
||||
const fixture = await fetchXtreamLiveFixture(
|
||||
request,
|
||||
xtreamCredentials
|
||||
);
|
||||
const expectedServerOrder = fixture.items
|
||||
.map((item) => getXtreamTitle(item))
|
||||
.filter((title, index, titles) => titles.indexOf(title) === index)
|
||||
@@ -50,20 +56,32 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
await addXtreamPortal(app.mainWindow);
|
||||
await waitForXtreamWorkspaceReady(app.mainWindow);
|
||||
await openWorkspaceSection(app.mainWindow, 'Live TV');
|
||||
await clickCategoryByNameExact(app.mainWindow, fixture.categoryName);
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
fixture.categoryName
|
||||
);
|
||||
|
||||
await expectVisibleChannelTitles(app.mainWindow, expectedServerOrder);
|
||||
await expectVisibleChannelTitles(
|
||||
app.mainWindow,
|
||||
expectedServerOrder
|
||||
);
|
||||
|
||||
await setLiveSortMode(app.mainWindow, 'Name A-Z');
|
||||
await expectVisibleChannelTitles(app.mainWindow, expectedAscending);
|
||||
|
||||
await setLiveSortMode(app.mainWindow, 'Name Z-A');
|
||||
await expectVisibleChannelTitles(app.mainWindow, expectedDescending);
|
||||
await expectVisibleChannelTitles(
|
||||
app.mainWindow,
|
||||
expectedDescending
|
||||
);
|
||||
|
||||
await setLiveSortMode(app.mainWindow, 'Name A-Z');
|
||||
await openWorkspaceSection(app.mainWindow, 'Movies');
|
||||
await openWorkspaceSection(app.mainWindow, 'Live TV');
|
||||
await clickCategoryByNameExact(app.mainWindow, fixture.categoryName);
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
fixture.categoryName
|
||||
);
|
||||
await expectVisibleChannelTitles(app.mainWindow, expectedAscending);
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
@@ -75,17 +93,26 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
request,
|
||||
}) => {
|
||||
await resetMockServers(request, ['xtream']);
|
||||
const vodFixture = await fetchXtreamVodFixture(request, xtreamCredentials);
|
||||
const vodFixture = await fetchXtreamVodFixture(
|
||||
request,
|
||||
xtreamCredentials
|
||||
);
|
||||
const seriesFixture = await fetchXtreamSeriesFixture(
|
||||
request,
|
||||
xtreamCredentials
|
||||
);
|
||||
const expectedVodDateDesc = [...vodFixture.items]
|
||||
.sort((left, right) => getXtreamDateValue(right) - getXtreamDateValue(left))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
getXtreamDateValue(right) - getXtreamDateValue(left)
|
||||
)
|
||||
.map((item) => getXtreamTitle(item))
|
||||
.slice(0, visibleComparisonSize);
|
||||
const expectedVodDateAsc = [...vodFixture.items]
|
||||
.sort((left, right) => getXtreamDateValue(left) - getXtreamDateValue(right))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
getXtreamDateValue(left) - getXtreamDateValue(right)
|
||||
)
|
||||
.map((item) => getXtreamTitle(item))
|
||||
.slice(0, visibleComparisonSize);
|
||||
const expectedVodNameAsc = [...vodFixture.items]
|
||||
@@ -108,10 +135,16 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
await waitForXtreamWorkspaceReady(app.mainWindow);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Movies');
|
||||
await clickCategoryByNameExact(app.mainWindow, vodFixture.categoryName);
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
vodFixture.categoryName
|
||||
);
|
||||
await expectVisibleGridTitles(app.mainWindow, expectedVodDateDesc);
|
||||
|
||||
await setContentSortMode(app.mainWindow, 'Date Added (Oldest First)');
|
||||
await setContentSortMode(
|
||||
app.mainWindow,
|
||||
'Date Added (Oldest First)'
|
||||
);
|
||||
await expectVisibleGridTitles(app.mainWindow, expectedVodDateAsc);
|
||||
|
||||
await setContentSortMode(app.mainWindow, 'Name A-Z');
|
||||
@@ -121,14 +154,26 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
await expectVisibleGridTitles(app.mainWindow, expectedVodNameDesc);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Series');
|
||||
await clickCategoryByNameExact(app.mainWindow, seriesFixture.categoryName);
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
seriesFixture.categoryName
|
||||
);
|
||||
await setContentSortMode(app.mainWindow, 'Name A-Z');
|
||||
await expectVisibleGridTitles(app.mainWindow, expectedSeriesNameAsc);
|
||||
await expectVisibleGridTitles(
|
||||
app.mainWindow,
|
||||
expectedSeriesNameAsc
|
||||
);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Live TV');
|
||||
await openWorkspaceSection(app.mainWindow, 'Series');
|
||||
await clickCategoryByNameExact(app.mainWindow, seriesFixture.categoryName);
|
||||
await expectVisibleGridTitles(app.mainWindow, expectedSeriesNameAsc);
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
seriesFixture.categoryName
|
||||
);
|
||||
await expectVisibleGridTitles(
|
||||
app.mainWindow,
|
||||
expectedSeriesNameAsc
|
||||
);
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
@@ -165,6 +210,103 @@ test.describe('Electron Catalog Sorting', () => {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
});
|
||||
|
||||
test('keeps Xtream catalog page after opening VOD and series details, and resets grid scroll on page changes', async ({
|
||||
dataDir,
|
||||
request,
|
||||
}) => {
|
||||
await resetMockServers(request, ['xtream']);
|
||||
const vodFixture = await fetchXtreamVodFixture(
|
||||
request,
|
||||
xtreamCredentials
|
||||
);
|
||||
const seriesFixture = await fetchXtreamSeriesFixture(
|
||||
request,
|
||||
xtreamCredentials
|
||||
);
|
||||
const app = await launchElectronApp(dataDir);
|
||||
|
||||
try {
|
||||
await addXtreamPortal(app.mainWindow);
|
||||
await waitForXtreamWorkspaceReady(app.mainWindow);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Movies');
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
vodFixture.categoryName
|
||||
);
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
await expectCatalogScrollResetAfterNextPage(app.mainWindow);
|
||||
await clickFirstGridListCard(app.mainWindow);
|
||||
await expectPathname(
|
||||
app.mainWindow,
|
||||
/\/workspace\/xtreams\/[^/]+\/vod\/[^/]+\/[^/]+$/
|
||||
);
|
||||
await goBackFromDetail(app.mainWindow);
|
||||
await expectCatalogPageQuery(app.mainWindow, '2');
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Series');
|
||||
await clickCategoryByNameExact(
|
||||
app.mainWindow,
|
||||
seriesFixture.categoryName
|
||||
);
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
await expectCatalogScrollResetAfterNextPage(app.mainWindow);
|
||||
await clickFirstGridListCard(app.mainWindow);
|
||||
await expectPathname(
|
||||
app.mainWindow,
|
||||
/\/workspace\/xtreams\/[^/]+\/series\/[^/]+\/[^/]+$/
|
||||
);
|
||||
await goBackFromDetail(app.mainWindow);
|
||||
await expectCatalogPageQuery(app.mainWindow, '2');
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
});
|
||||
|
||||
test('resets Stalker VOD and series grid scroll when changing pages', async ({
|
||||
dataDir,
|
||||
request,
|
||||
}) => {
|
||||
await resetMockServers(request, ['stalker']);
|
||||
const vodFixture = await fetchStalkerCategoryFixture(request, 'vod');
|
||||
const seriesFixture = await fetchStalkerCategoryFixture(
|
||||
request,
|
||||
'series'
|
||||
);
|
||||
const app = await launchElectronApp(dataDir);
|
||||
|
||||
try {
|
||||
await addStalkerPortal(app.mainWindow);
|
||||
await waitForStalkerCatalog(app.mainWindow);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Movies');
|
||||
await clickCategoryByVisibleName(
|
||||
app.mainWindow,
|
||||
vodFixture.categoryName
|
||||
);
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
await expectCatalogScrollResetAfterNextPage(app.mainWindow, {
|
||||
expectContentChange: false,
|
||||
});
|
||||
await expectStalkerDetailBackPreservesCatalogPage(app.mainWindow);
|
||||
|
||||
await openWorkspaceSection(app.mainWindow, 'Series');
|
||||
await clickCategoryByVisibleName(
|
||||
app.mainWindow,
|
||||
seriesFixture.categoryName
|
||||
);
|
||||
await expectCatalogGridReady(app.mainWindow);
|
||||
await expectCatalogScrollResetAfterNextPage(app.mainWindow, {
|
||||
expectContentChange: false,
|
||||
});
|
||||
await expectStalkerDetailBackPreservesCatalogPage(app.mainWindow);
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const collator = new Intl.Collator(undefined, {
|
||||
@@ -221,6 +363,138 @@ async function expectVisibleGridTitles(
|
||||
.toEqual(expectedTitles);
|
||||
}
|
||||
|
||||
async function expectCatalogGridReady(page: Page): Promise<void> {
|
||||
await expect(
|
||||
page.locator('.category-content-layout mat-card').first()
|
||||
).toBeVisible({
|
||||
timeout: 20000,
|
||||
});
|
||||
}
|
||||
|
||||
async function expectCatalogScrollResetAfterNextPage(
|
||||
page: Page,
|
||||
options: { expectContentChange?: boolean } = {}
|
||||
): Promise<string[]> {
|
||||
const grid = catalogGrid(page);
|
||||
|
||||
await expect(grid).toBeVisible({ timeout: 20000 });
|
||||
await ensureCatalogCanGoNext(page);
|
||||
const rangeBefore = await catalogRangeText(page);
|
||||
const titlesBefore = await visibleGridTitles(page);
|
||||
await grid.evaluate((element: HTMLElement) => {
|
||||
element.scrollTo({ top: element.scrollHeight });
|
||||
});
|
||||
await expect.poll(() => getCatalogGridScrollTop(page)).toBeGreaterThan(0);
|
||||
|
||||
await page
|
||||
.locator('.category-content-header')
|
||||
.getByRole('button', { name: 'Next page' })
|
||||
.click();
|
||||
await expectCatalogPageQuery(page, '2');
|
||||
await expect.poll(() => catalogRangeText(page)).not.toBe(rangeBefore);
|
||||
if (options.expectContentChange !== false) {
|
||||
await expect
|
||||
.poll(() => visibleGridTitles(page))
|
||||
.not.toEqual(titlesBefore);
|
||||
}
|
||||
await expect.poll(() => getCatalogGridScrollTop(page)).toBeLessThan(2);
|
||||
return visibleGridTitles(page);
|
||||
}
|
||||
|
||||
async function expectStalkerDetailBackPreservesCatalogPage(
|
||||
page: Page
|
||||
): Promise<void> {
|
||||
const titlesOnPage = await visibleGridTitles(page);
|
||||
|
||||
await clickFirstGridListCard(page);
|
||||
await goBackFromDetail(page);
|
||||
|
||||
await expectCatalogPageQuery(page, '2');
|
||||
await expectCatalogGridReady(page);
|
||||
await expect.poll(() => visibleGridTitles(page)).toEqual(titlesOnPage);
|
||||
}
|
||||
|
||||
async function expectCatalogPageQuery(
|
||||
page: Page,
|
||||
expectedPage: string
|
||||
): Promise<void> {
|
||||
await expect
|
||||
.poll(() => new URL(page.url()).searchParams.get('page'))
|
||||
.toBe(expectedPage);
|
||||
}
|
||||
|
||||
async function goBackFromDetail(page: Page): Promise<void> {
|
||||
const backButton = page
|
||||
.locator('app-content-hero .hero__back-button')
|
||||
.first();
|
||||
|
||||
await expect(backButton).toBeVisible({ timeout: 20000 });
|
||||
try {
|
||||
await backButton.click({ timeout: 5000 });
|
||||
} catch {
|
||||
await backButton.evaluate((button: HTMLButtonElement) =>
|
||||
button.click()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function clickCategoryByVisibleName(
|
||||
page: Page,
|
||||
categoryName: string
|
||||
): Promise<void> {
|
||||
const category = page
|
||||
.locator('app-workspace-context-panel .category-item:visible')
|
||||
.filter({
|
||||
has: page.locator('.nav-item-label', {
|
||||
hasText: new RegExp(`^\\s*${escapeRegex(categoryName)}\\s*$`),
|
||||
}),
|
||||
})
|
||||
.first();
|
||||
|
||||
await expect(category).toBeVisible({ timeout: 20000 });
|
||||
await category.click();
|
||||
await expect.poll(() => category.getAttribute('aria-current')).toBe('true');
|
||||
}
|
||||
|
||||
function catalogGrid(page: Page) {
|
||||
return page.locator('app-category-content-view app-grid-list').first();
|
||||
}
|
||||
|
||||
async function ensureCatalogCanGoNext(page: Page): Promise<void> {
|
||||
const header = page.locator('.category-content-header');
|
||||
const nextButton = header.getByRole('button', { name: 'Next page' });
|
||||
|
||||
await expect(nextButton).toBeVisible({ timeout: 20000 });
|
||||
|
||||
if (await nextButton.isDisabled()) {
|
||||
await header.getByRole('button', { name: 'Previous page' }).click();
|
||||
await expect
|
||||
.poll(() => new URL(page.url()).searchParams.get('page'))
|
||||
.toBe(null);
|
||||
}
|
||||
|
||||
await expect(nextButton).toBeEnabled({ timeout: 20000 });
|
||||
}
|
||||
|
||||
async function catalogRangeText(page: Page): Promise<string> {
|
||||
return (
|
||||
(await page
|
||||
.locator('.category-content-header .mat-mdc-paginator-range-label')
|
||||
.first()
|
||||
.textContent()) ?? ''
|
||||
).trim();
|
||||
}
|
||||
|
||||
async function getCatalogGridScrollTop(page: Page): Promise<number> {
|
||||
return catalogGrid(page).evaluate((element: HTMLElement) =>
|
||||
Math.round(element.scrollTop)
|
||||
);
|
||||
}
|
||||
|
||||
function escapeRegex(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
async function visibleChannelTitles(page: Page): Promise<string[]> {
|
||||
return page
|
||||
.locator('[data-test-id="channel-item"] .channel-name')
|
||||
|
||||
+86
@@ -45,10 +45,39 @@ const TestContentStore = signalStore(
|
||||
setSelectedCategory(id: string | null | undefined) {
|
||||
patchState(store, { selectedCategoryId: id });
|
||||
},
|
||||
setPage(page: number) {
|
||||
patchState(store, { page });
|
||||
},
|
||||
})),
|
||||
withStalkerContent()
|
||||
);
|
||||
|
||||
function createDeferred<T>() {
|
||||
let resolve!: (value: T) => void;
|
||||
let reject!: (reason?: unknown) => void;
|
||||
const promise = new Promise<T>((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
return { promise, resolve, reject };
|
||||
}
|
||||
|
||||
function createContentResponse(title: string) {
|
||||
return {
|
||||
js: {
|
||||
data: [
|
||||
{
|
||||
id: title,
|
||||
name: title,
|
||||
category_id: '5',
|
||||
},
|
||||
],
|
||||
total_items: 28,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function flushResources(): Promise<void> {
|
||||
TestBed.flushEffects();
|
||||
await Promise.resolve();
|
||||
@@ -194,4 +223,61 @@ describe('withStalkerContent failure states', () => {
|
||||
'get_ordered_list failed'
|
||||
);
|
||||
});
|
||||
|
||||
it('ignores stale content responses after the selected page changes', async () => {
|
||||
const pendingByPage = new Map<
|
||||
number,
|
||||
ReturnType<typeof createDeferred<unknown>>[]
|
||||
>();
|
||||
|
||||
dataService.sendIpcEvent.mockImplementation(
|
||||
(_event: unknown, payload: { params?: { p?: number } }) => {
|
||||
const page = Number(payload.params?.p);
|
||||
const deferred = createDeferred<unknown>();
|
||||
const pending = pendingByPage.get(page) ?? [];
|
||||
pending.push(deferred);
|
||||
pendingByPage.set(page, pending);
|
||||
return deferred.promise;
|
||||
}
|
||||
);
|
||||
|
||||
store.setSelectedContentType('vod');
|
||||
store.setCategories('vod', [
|
||||
{
|
||||
category_id: '5',
|
||||
category_name: 'Movies',
|
||||
},
|
||||
]);
|
||||
store.setSelectedCategory('5');
|
||||
store.setCurrentPlaylist(PLAYLIST);
|
||||
void store.isPaginatedContentLoading();
|
||||
|
||||
await waitForCondition(() => pendingByPage.get(1)?.length === 1);
|
||||
pendingByPage
|
||||
.get(1)?.[0]
|
||||
.resolve(createContentResponse('Page 1 initial'));
|
||||
await waitForCondition(
|
||||
() => store.getPaginatedContent()[0]?.name === 'Page 1 initial'
|
||||
);
|
||||
|
||||
store.setPage(1);
|
||||
await waitForCondition(() => pendingByPage.get(2)?.length === 1);
|
||||
|
||||
store.setPage(0);
|
||||
await waitForCondition(() => pendingByPage.get(1)?.length === 2);
|
||||
pendingByPage
|
||||
.get(1)?.[1]
|
||||
.resolve(createContentResponse('Page 1 restored'));
|
||||
await waitForCondition(
|
||||
() => store.getPaginatedContent()[0]?.name === 'Page 1 restored'
|
||||
);
|
||||
|
||||
pendingByPage
|
||||
.get(2)?.[0]
|
||||
.resolve(createContentResponse('Page 2 stale'));
|
||||
await flushResources();
|
||||
|
||||
expect(store.page()).toBe(0);
|
||||
expect(store.getPaginatedContent()[0]?.name).toBe('Page 1 restored');
|
||||
});
|
||||
});
|
||||
+37
@@ -323,6 +323,30 @@ export function withStalkerContent() {
|
||||
}
|
||||
|
||||
const categoryParam = params.category || '*';
|
||||
const paramsPlaylistKey =
|
||||
params.currentPlaylist?._id ??
|
||||
params.currentPlaylist?.portalUrl ??
|
||||
null;
|
||||
const isCurrentRequest = (): boolean => {
|
||||
const currentPlaylist =
|
||||
storeContext.currentPlaylist();
|
||||
const currentPlaylistKey =
|
||||
currentPlaylist?._id ??
|
||||
currentPlaylist?.portalUrl ??
|
||||
null;
|
||||
|
||||
return (
|
||||
params.contentType ===
|
||||
storeContext.selectedContentType() &&
|
||||
params.category ===
|
||||
storeContext.selectedCategoryId() &&
|
||||
params.search ===
|
||||
storeContext.searchPhrase() &&
|
||||
params.pageIndex ===
|
||||
storeContext.page() + 1 &&
|
||||
paramsPlaylistKey === currentPlaylistKey
|
||||
);
|
||||
};
|
||||
const queryParams: Record<string, string | number> =
|
||||
{
|
||||
action: StalkerContentTypes[
|
||||
@@ -347,6 +371,11 @@ export function withStalkerContent() {
|
||||
}
|
||||
|
||||
try {
|
||||
patchState(store, {
|
||||
paginatedContent: [],
|
||||
contentError: null,
|
||||
});
|
||||
|
||||
const response =
|
||||
await executeStalkerRequest<StalkerOrderedListResponse>(
|
||||
requestDeps,
|
||||
@@ -354,6 +383,10 @@ export function withStalkerContent() {
|
||||
queryParams
|
||||
);
|
||||
|
||||
if (!isCurrentRequest()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!Array.isArray(response?.js?.data)) {
|
||||
const invalidResponseError = new Error(
|
||||
'Invalid response structure'
|
||||
@@ -411,6 +444,10 @@ export function withStalkerContent() {
|
||||
|
||||
return newItems;
|
||||
} catch (error) {
|
||||
if (!isCurrentRequest()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.warn('Error loading content', {
|
||||
contentType: params.contentType,
|
||||
category: params.category,
|
||||
|
||||
+19
@@ -23,6 +23,25 @@ describe('withStalkerSelection', () => {
|
||||
expect(store.page()).toBe(0);
|
||||
});
|
||||
|
||||
it('keeps paging when the search phrase is unchanged', () => {
|
||||
store.setSearchPhrase('matrix');
|
||||
store.setPage(2);
|
||||
|
||||
store.setSearchPhrase('matrix');
|
||||
|
||||
expect(store.searchPhrase()).toBe('matrix');
|
||||
expect(store.page()).toBe(2);
|
||||
});
|
||||
|
||||
it('resets paging when the search phrase changes', () => {
|
||||
store.setPage(2);
|
||||
|
||||
store.setSearchPhrase('matrix');
|
||||
|
||||
expect(store.searchPhrase()).toBe('matrix');
|
||||
expect(store.page()).toBe(0);
|
||||
});
|
||||
|
||||
it('synchronizes entity ids when the selected item changes', () => {
|
||||
store.setSelectedItem({
|
||||
id: '55',
|
||||
|
||||
+12
@@ -62,12 +62,24 @@ export function withStalkerSelection() {
|
||||
patchState(store, { selectedItvId: id });
|
||||
},
|
||||
setLimit(limit: number) {
|
||||
if (store.limit() === limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
patchState(store, { limit });
|
||||
},
|
||||
setPage(page: number) {
|
||||
if (store.page() === page) {
|
||||
return;
|
||||
}
|
||||
|
||||
patchState(store, { page });
|
||||
},
|
||||
setSearchPhrase(phrase: string) {
|
||||
if (store.searchPhrase() === phrase) {
|
||||
return;
|
||||
}
|
||||
|
||||
patchState(store, { searchPhrase: phrase, page: 0 });
|
||||
},
|
||||
setSelectedItem(selectedItem: StalkerVodSource | null | undefined) {
|
||||
|
||||
Reference in new issue
Block a user