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', + }, + ]} + /> + + + )} + + ); +});