fix(editor): Fix pagination and sorting issue for insights (#16288)

This commit is contained in:
Guillaume Jacquart
2025-06-13 10:08:08 +02:00
committed by GitHub
parent 8d6e796b92
commit 84c51b1bd9
3 changed files with 55 additions and 8 deletions

View File

@@ -1,8 +1,22 @@
import userEvent from '@testing-library/user-event';
import { render, within } from '@testing-library/vue';
import { render, screen, waitFor, within } from '@testing-library/vue';
import { config } from '@vue/test-utils';
import ElementPlus from 'element-plus';
import { createComponentRenderer } from '@n8n/design-system/__tests__/render';
import N8nDataTableServer, { type TableHeader } from './N8nDataTableServer.vue';
const renderComponent = createComponentRenderer(N8nDataTableServer);
const getRenderedOptions = async () => {
const dropdown = await waitFor(() => screen.getByRole('listbox'));
expect(dropdown).toBeInTheDocument();
return dropdown.querySelectorAll('.el-select-dropdown__item');
};
config.global.plugins.push(ElementPlus);
const itemFactory = () => ({
id: crypto.randomUUID() as string,
firstName: crypto.randomUUID() as string,
@@ -84,8 +98,7 @@ describe('N8nDataTableServer', () => {
});
it('should emit options for sorting / pagination', async () => {
const { container, emitted, getByTestId } = render(N8nDataTableServer, {
//@ts-expect-error testing-library errors due to header generics
const { container, emitted, getByTestId, findAllByRole } = renderComponent({
props: { items, headers, itemsLength: 100 },
});
@@ -93,7 +106,17 @@ describe('N8nDataTableServer', () => {
await userEvent.click(container.querySelector('thead tr th')!);
await userEvent.click(within(getByTestId('pagination')).getByLabelText('page 2'));
expect(emitted('update:options').length).toBe(3);
// change the page size select option
const selectInput = await findAllByRole('combobox'); // Find the select input
await userEvent.click(selectInput[0]);
const options = await getRenderedOptions();
expect(options.length).toBe(4);
const option50 = Array.from(options).find((option) => option.textContent === '50');
await userEvent.click(option50!);
expect(emitted('update:options').length).toBeGreaterThanOrEqual(4);
expect(emitted('update:options')[0]).toStrictEqual([
expect.objectContaining({ sortBy: [{ id: 'id', desc: false }] }),
]);
@@ -101,6 +124,24 @@ describe('N8nDataTableServer', () => {
expect.objectContaining({ sortBy: [{ id: 'id', desc: true }] }),
]);
expect(emitted('update:options')[2]).toStrictEqual([expect.objectContaining({ page: 1 })]);
expect(emitted('update:options')[3]).toStrictEqual([
expect.objectContaining({ itemsPerPage: 50 }),
]);
});
it('should emit options for sorting with initial sort', async () => {
const { container, emitted } = renderComponent({
props: { items, headers, itemsLength: 100, sortBy: [{ id: 'id', desc: true }] },
});
await userEvent.click(container.querySelector('thead tr th')!);
await userEvent.click(container.querySelector('thead tr th')!);
expect(emitted('update:options').length).toBe(2);
expect(emitted('update:options')[0]).toStrictEqual([expect.objectContaining({ sortBy: [] })]);
expect(emitted('update:options')[1]).toStrictEqual([
expect.objectContaining({ sortBy: [{ id: 'id', desc: false }] }),
]);
});
it('should not show the pagination if there are no items', async () => {

View File

@@ -205,7 +205,10 @@ const page = defineModel<number>('page', { default: 0 });
watch(page, () => table.setPageIndex(page.value));
const itemsPerPage = defineModel<number>('items-per-page', { default: 10 });
watch(itemsPerPage, () => (page.value = 0));
watch(itemsPerPage, () => {
page.value = 0;
table.setPageSize(itemsPerPage.value);
});
const pagination = computed<PaginationState>({
get() {
@@ -225,13 +228,16 @@ const showPagination = computed(() => props.itemsLength > Math.min(...props.page
const sortBy = defineModel<SortingState>('sort-by', { default: [], required: false });
function handleSortingChange(updaterOrValue: Updater<SortingState>) {
sortBy.value =
const newValue =
typeof updaterOrValue === 'function' ? updaterOrValue(sortBy.value) : updaterOrValue;
sortBy.value = newValue;
// Use newValue instead of sortBy.value to ensure the latest value is used
// This is because of the async nature of the Vue reactivity system
emit('update:options', {
page: page.value,
itemsPerPage: itemsPerPage.value,
sortBy: sortBy.value,
sortBy: newValue,
});
}

View File

@@ -57,7 +57,7 @@ const transformFilter = ({ id, desc }: { id: string; desc: boolean }) => {
const fetchPaginatedTableData = ({
page = 0,
itemsPerPage = 20,
itemsPerPage = 25,
sortBy,
dateRange = selectedDateRange.value,
}: {