Skip to content

Commit

Permalink
Merge branch 'main' into discover-ad-hoc-data-views-extension
Browse files Browse the repository at this point in the history
  • Loading branch information
davismcphee authored Jan 23, 2025
2 parents 76e11f4 + 8351418 commit c2328cd
Show file tree
Hide file tree
Showing 64 changed files with 1,087 additions and 791 deletions.
2 changes: 1 addition & 1 deletion .buildkite/pipelines/pull_request/response_ops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ steps:
- check_types
- check_oas_snapshot
timeout_in_minutes: 120
parallelism: 9
parallelism: 11
retry:
automatic:
- exit_status: '*'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ export { TableListViewTable, TableListViewProvider, TableListViewKibanaProvider

export type { TableListViewTableProps, RowActions } from './src';

export type { CustomSortingOptions } from './src/components';

export type { TableListViewKibanaDependencies } from './src/services';
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,9 @@ export { ItemDetails } from './item_details';
export { TableSortSelect } from './table_sort_select';
export { TagFilterPanel } from './tag_filter_panel';

export { type SortColumnField, getInitialSorting, saveSorting } from './table_sort_select';
export {
type SortColumnField,
type CustomSortingOptions,
getInitialSorting,
saveSorting,
} from './table_sort_select';
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { TableSortSelect } from './table_sort_select';
import { TagFilterPanel, TagFilterContextProvider } from './tag_filter_panel';
import { useTagFilterPanel } from './use_tag_filter_panel';
import type { Params as UseTagFilterPanelParams } from './use_tag_filter_panel';
import type { SortColumnField } from './table_sort_select';
import type { CustomSortingOptions, SortColumnField } from './table_sort_select';
import {
UserFilterPanel,
UserFilterContextProvider,
Expand Down Expand Up @@ -71,6 +71,7 @@ interface Props<T extends UserContentCommonSchema> extends State<T>, TagManageme
tableColumns: Array<EuiBasicTableColumn<T>>;
hasUpdatedAtMetadata: boolean;
hasRecentlyAccessedMetadata: boolean;
customSortingOptions?: CustomSortingOptions;
deleteItems: TableListViewTableProps<T>['deleteItems'];
tableItemsRowActions: TableItemsRowActions;
renderCreateButton: () => React.ReactElement | undefined;
Expand All @@ -95,6 +96,7 @@ export function Table<T extends UserContentCommonSchema>({
tableFilter,
hasUpdatedAtMetadata,
hasRecentlyAccessedMetadata,
customSortingOptions,
entityName,
entityNamePlural,
tagsToTableItemMap,
Expand Down Expand Up @@ -191,12 +193,19 @@ export function Table<T extends UserContentCommonSchema>({
tableSort={tableSort}
hasUpdatedAtMetadata={hasUpdatedAtMetadata}
hasRecentlyAccessedMetadata={hasRecentlyAccessedMetadata}
customSortingOptions={customSortingOptions}
onChange={onSortChange}
/>
);
},
};
}, [hasUpdatedAtMetadata, onSortChange, tableSort, hasRecentlyAccessedMetadata]);
}, [
hasUpdatedAtMetadata,
onSortChange,
tableSort,
hasRecentlyAccessedMetadata,
customSortingOptions,
]);

const tagFilterPanel = useMemo<SearchFilterConfig | null>(() => {
if (!isTaggingEnabled()) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type SortItem = EuiSelectableOption & {
direction: Direction;
};

export type SortColumnField = 'updatedAt' | 'attributes.title' | 'accessedAt';
export type SortColumnField = 'updatedAt' | 'attributes.title' | 'accessedAt' | string;

const i18nText = {
accessedDescSort: i18n.translate(
Expand Down Expand Up @@ -65,15 +65,26 @@ const i18nText = {
}),
};

export interface CustomSortingOptions {
field: string;
sortingLabels: TableColumnSortSelectOption[];
}
interface TableColumnSortSelectOption {
label: string;
direction: 'asc' | 'desc';
}

interface Props {
hasUpdatedAtMetadata: boolean;
hasRecentlyAccessedMetadata: boolean;
tableSort: State['tableSort'];
customSortingOptions?: CustomSortingOptions;
onChange?: (column: SortColumnField, direction: Direction) => void;
}

export function TableSortSelect({
tableSort,
customSortingOptions,
hasUpdatedAtMetadata,
hasRecentlyAccessedMetadata,
onChange,
Expand All @@ -97,6 +108,19 @@ export function TableSortSelect({
},
];

if (customSortingOptions) {
opts = opts.concat(
customSortingOptions.sortingLabels.map(({ label, direction }) => {
return {
column: customSortingOptions.field,
label,
direction,
append: direction === 'asc' ? <EuiIcon type="sortUp" /> : <EuiIcon type="sortDown" />,
};
})
);
}

if (hasRecentlyAccessedMetadata) {
opts = [
{
Expand Down Expand Up @@ -202,7 +226,7 @@ export function TableSortSelect({
};
});
});
}, [tableSort]);
}, [customSortingOptions, tableSort]);

return (
<EuiPopover
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { getTagList, localStorageMock } from './mocks';
import { TableListViewTable, type TableListViewTableProps } from './table_list_view_table';
import { getActions } from './table_list_view.test.helpers';
import type { Services } from './services';
import { CustomSortingOptions } from './components/table_sort_select';

const mockUseEffect = useEffect;

Expand Down Expand Up @@ -591,6 +592,9 @@ describe('TableListView', () => {
component.update();
const filterOptions = find('sortSelect').find('li');

// Check that the second option is 'Name Z-A'
expect(filterOptions.at(1).text()).toBe('Name Z-A ');

// Click 'Name Z-A'
act(() => {
filterOptions.at(1).simulate('click');
Expand Down Expand Up @@ -708,6 +712,213 @@ describe('TableListView', () => {
});
});

describe('column sorting with custom columns', () => {
const customSortingOptions: CustomSortingOptions = {
field: 'typeTitle',
sortingLabels: [
{
label: 'Type A-Z',
direction: 'asc',
},
{
label: 'Type Z-A',
direction: 'desc',
},
],
};
const customTableColumn = {
field: 'typeTitle',
name: 'Type',
sortable: true,
};

const setupCustomColumnSorting = registerTestBed<string, TableListViewTableProps>(
WithServices<TableListViewTableProps>(TableListViewTable, {
TagList: getTagList({ references: [] }),
}),
{
defaultProps: { ...requiredProps, customSortingOptions, customTableColumn },
}
);

const hits: Array<UserContentCommonSchema & { typeTitle: string }> = [
{
id: '123',
updatedAt: twoDaysAgo.toISOString(),
type: 'maps',
attributes: {
title: 'Item 2',
},
references: [],
typeTitle: 'Vega',
},
{
id: '456',
updatedAt: yesterday.toISOString(),
type: 'vega',
attributes: {
title: 'Item 1',
},
references: [],
typeTitle: 'Lens',
},
];

test('filter select should change the sort order based on custom select option', async () => {
let testBed: TestBed;

await act(async () => {
testBed = await setupCustomColumnSorting({
findItems: jest.fn().mockResolvedValue({ total: hits.length, hits }),
});
});

let { component, table, find } = testBed!;
const { openSortSelect } = getActions(testBed!);
component.update();

let { tableCellsValues } = table.getMetaData('itemsInMemTable');

expect(tableCellsValues).toEqual([
['Item 1', 'Lens', yesterdayToString],
['Item 2', 'Vega', twoDaysAgoToString],
]);

act(() => {
openSortSelect();
});
component.update();
const filterOptions = find('sortSelect').find('li');

// Check that the fourth option is 'Type Z-A'
expect(filterOptions.at(3).text()).toBe('Type Z-A ');

// Click 'Type Z-A'
act(() => {
filterOptions.at(3).simulate('click');
});
component.update();

({ tableCellsValues } = table.getMetaData('itemsInMemTable'));

expect(tableCellsValues).toEqual([
['Item 2', 'Vega', twoDaysAgoToString],
['Item 1', 'Lens', yesterdayToString],
]);

expect(localStorage.getItem('tableSort:test')).toBe(
'{"field":"typeTitle","direction":"desc"}'
);

component.unmount();
await act(async () => {
testBed = await setupCustomColumnSorting({
findItems: jest.fn().mockResolvedValue({ total: hits.length, hits }),
});
});

({ component, table, find } = testBed!);
component.update();
({ tableCellsValues } = table.getMetaData('itemsInMemTable'));

expect(tableCellsValues).toEqual([
['Item 2', 'Vega', twoDaysAgoToString],
['Item 1', 'Lens', yesterdayToString],
]);
});

test('should update the select option when custom column header is selected', async () => {
const getCustomTableColumnSortButton = (testBed: TestBed, text: string) => {
const buttons = testBed.find('tableHeaderSortButton');
let wrapper: ReactWrapper | undefined;

buttons.forEach((_wrapper) => {
if (wrapper) {
return;
}

if (_wrapper.text().includes(text)) {
wrapper = _wrapper;
}
});
return wrapper;
};

let testBed: TestBed;

await act(async () => {
testBed = await setupCustomColumnSorting({
findItems: jest.fn().mockResolvedValue({ total: hits.length, hits }),
});
});

const { component, table, find } = testBed!;
const { openSortSelect } = getActions(testBed!);
component.update();

act(() => {
openSortSelect();
});
component.update();
let filterOptions = find('sortSelect').find('li');

expect(filterOptions.length).toBe(6);
expect(filterOptions.map((wrapper) => wrapper.text())).toEqual([
'Name A-Z ',
'Name Z-A ',
'Type A-Z ',
'Type Z-A ',
'Recently updated. Checked option. ',
'Least recently updated ',
]);

const typeColumnHeaderButton = getCustomTableColumnSortButton(testBed!, 'Type');

if (!typeColumnHeaderButton) {
throw new Error('Could not find table header button containing "Type".');
}

act(() => {
typeColumnHeaderButton.simulate('click');
});
component.update();

let { tableCellsValues } = table.getMetaData('itemsInMemTable');

expect(tableCellsValues).toEqual([
['Item 1', 'Lens', yesterdayToString],
['Item 2', 'Vega', twoDaysAgoToString],
]);

act(() => {
typeColumnHeaderButton.simulate('click');
});
component.update();
({ tableCellsValues } = table.getMetaData('itemsInMemTable'));

expect(tableCellsValues).toEqual([
['Item 2', 'Vega', twoDaysAgoToString],
['Item 1', 'Lens', yesterdayToString],
]);

act(() => {
openSortSelect();
});
component.update();

filterOptions = find('sortSelect').find('li');

expect(filterOptions.map((wrapper) => wrapper.text())).toEqual([
'Name A-Z ',
'Name Z-A ',
'Type A-Z ',
'Type Z-A. Checked option. ',
'Recently updated ',
'Least recently updated ',
]);
});
});

describe('column sorting with recently accessed', () => {
const setupColumnSorting = registerTestBed<string, TableListViewTableProps>(
WithServices<TableListViewTableProps>(TableListViewTable, {
Expand Down Expand Up @@ -1560,6 +1771,9 @@ describe('TableListView', () => {
openSortSelect();
const filterOptions = find('sortSelect').find('li');

// Check that the second option is 'Name Z-A'
expect(filterOptions.at(1).text()).toBe('Name Z-A ');

// Click 'Name Z-A'
act(() => {
filterOptions.at(1).simulate('click');
Expand Down
Loading

0 comments on commit c2328cd

Please sign in to comment.