From 7a1592babbe0c7361fedae187534405adf834ab2 Mon Sep 17 00:00:00 2001 From: Sloane Perrault Date: Mon, 6 Mar 2023 13:05:12 -0500 Subject: [PATCH] [Enterprise Search] Engines Search Preview - "Sort By" (#152253) ## Summary https://user-images.githubusercontent.com/1699281/222561456-55666a32-0508-4c49-b721-4bd71afb0d72.mov ### Checklist Delete any items that are not applicable to this PR. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [x] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [x] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --- .../engine_search_preview.tsx | 5 +- .../engine_search_preview_logic.ts | 17 ++++ .../search_ui_components.tsx | 86 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/engine_search_preview.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/engine_search_preview.tsx index f31fb2dd911a7..0d92ce8609807 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/engine_search_preview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/engine_search_preview.tsx @@ -47,6 +47,7 @@ import { ResultView, ResultsPerPageView, ResultsView, + Sorting, } from './search_ui_components'; class InternalEngineTransporter implements Transporter { @@ -85,7 +86,7 @@ export const EngineSearchPreview: React.FC = () => { const [showAPICallFlyout, setShowAPICallFlyout] = useState(false); const [lastAPICall, setLastAPICall] = useState(null); const { engineName, isLoadingEngine } = useValues(EngineViewLogic); - const { resultFields, searchableFields } = useValues(EngineSearchPreviewLogic); + const { resultFields, searchableFields, sortableFields } = useValues(EngineSearchPreviewLogic); const { engineData } = useValues(EngineIndicesLogic); const config: SearchDriverOptions = useMemo(() => { @@ -141,6 +142,8 @@ export const EngineSearchPreview: React.FC = () => { + + ; searchableFields: Record; + sortableFields: string[]; } export const EngineSearchPreviewLogic = kea< @@ -86,5 +87,21 @@ export const EngineSearchPreviewLogic = kea< return searchableFields; }, ], + sortableFields: [ + () => [selectors.engineFieldCapabilitiesData], + (data: EngineSearchPreviewValues['engineFieldCapabilitiesData']) => { + if (!data) return []; + + return Object.entries(data.field_capabilities.fields) + .filter(([, mappings]) => + Object.entries(mappings).some( + ([, { metadata_field: isMeta, aggregatable }]) => + // Aggregatable are also _sortable_ + aggregatable && !isMeta + ) + ) + .map(([field]) => field); + }, + ], }), }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/search_ui_components.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/search_ui_components.tsx index c685cf5898e3d..3ba57405ffe93 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/search_ui_components.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/engine/engine_search_preview/search_ui_components.tsx @@ -14,16 +14,19 @@ import { EuiBasicTable, EuiBasicTableColumn, EuiButton, + EuiComboBox, EuiFieldSearch, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiPanel, EuiSelect, + EuiSpacer, EuiText, EuiTextColor, EuiTitle, } from '@elastic/eui'; +import { withSearch } from '@elastic/react-search-ui'; import type { InputViewProps, PagingInfoViewProps, @@ -31,6 +34,7 @@ import type { ResultsPerPageViewProps, ResultsViewProps, } from '@elastic/react-search-ui-views'; +import type { SearchContextState } from '@elastic/search-ui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage, FormattedHTMLMessage } from '@kbn/i18n-react'; @@ -224,3 +228,85 @@ export const ResultsPerPageView: React.FC = ({ ); + +export const Sorting = withSearch< + { sortableFields: string[] }, + Pick +>(({ setSort, sortList }) => ({ setSort, sortList }))(({ sortableFields, sortList, setSort }) => { + const [{ direction, field }] = !sortList?.length ? [{ direction: '', field: '' }] : sortList; + const relevance = i18n.translate( + 'xpack.enterpriseSearch.content.engine.searchPreivew.sortingView.relevanceLabel', + { defaultMessage: 'Relevance' } + ); + + return ( + + + + + + ({ label: f, value: f })), + ]} + selectedOptions={[{ label: !!field ? field : relevance, value: field }]} + onChange={([{ value }]) => + setSort(value === '' ? [] : [{ direction: 'asc', field: value }], 'asc') + } + /> + + {field !== '' && ( + <> + + + + + + { + switch (evt.target.value) { + case 'asc': + return setSort([{ direction: 'asc', field }], 'asc'); + case 'desc': + return setSort([{ direction: 'desc', field }], 'desc'); + } + }} + value={direction} + options={[ + { + text: i18n.translate( + 'xpack.enterpriseSearch.content.engine.searchPreview.sortingView.ascLabel', + { defaultMessage: 'Ascending' } + ), + value: 'asc', + }, + { + text: i18n.translate( + 'xpack.enterpriseSearch.content.engine.searchPreview.sortingView.descLabel', + { defaultMessage: 'Descending' } + ), + value: 'desc', + }, + ]} + /> + + + )} + + ); +});