diff --git a/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.scss b/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.scss new file mode 100644 index 0000000000..38a78bf2fb --- /dev/null +++ b/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.scss @@ -0,0 +1,32 @@ +.DatasetsSearchAndAnswerTableContainer { + .ResultTableSummaryView > .MesaComponent { + .TableToolbar { + .TableToolbar-Info { + order: -1; + } + } + } +} + +.DatasetsSearchAndAnswerFilter { + .TextExpressionContainer { + position: relative; + } + .wdk-Answer-filterFieldSelector { + width: 292px; + } + .wdk-Answer-filterSelectFieldsIcon { + position: relative; + right: 25px; + padding: 5px; + } + .HelpIconWrapper { + position: relative; + right: 12px; + } +} + +.DatasetsSearchAndAnswerBtn { + width: fit-content; + height: fit-content; +} diff --git a/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.tsx b/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.tsx index aa27898f82..2e27c4de41 100644 --- a/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.tsx +++ b/packages/libs/wdk-client/src/Components/SearchAndAnswer/Datasets/DatasetsSearchAndAnswer.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useCallback } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { RootState } from '../../../Core/State/Types'; import { useSelector } from 'react-redux'; import { SearchAndAnswer, TableResultTypePartial } from '../SearchAndAnswer'; @@ -8,13 +8,15 @@ import { } from '../../../Controllers/AnswerController'; import { downloadReport, ResultType } from '../../../Utils/WdkResult'; import { mapValues } from 'lodash'; -import { - Props as FormProps, - renderDefaultParamGroup, -} from '../../../Views/Question/DefaultQuestionForm'; +import { Props as FormProps } from '../../../Views/Question/DefaultQuestionForm'; import Icon from '../../Icon/IconAlt'; import { WdkDependenciesContext } from '../../../Hooks/WdkDependenciesEffect'; import { useNonNullableContext } from '../../../Hooks/NonNullableContext'; +import './DatasetsSearchAndAnswer.scss'; +import HelpIcon from '../../Icon/HelpIcon'; +import { Tooltip } from '@veupathdb/coreui'; +import TabbableContainer from '../../Display/TabbableContainer'; +import { LinksPosition } from '@veupathdb/coreui/lib/components/inputs/checkboxes/CheckboxTree/CheckboxTree'; const VIEW_ID = 'DatasetsPage'; const RECORD_NAME = 'dataset'; @@ -42,47 +44,93 @@ const DEFAULT_FORMATTING = { }; function DatasetsFormComponent(props: FormProps) { - const { state } = props; - // Need to add `isSearchPage` prop so that organism prefs are used - const parameterElements = useMemo( - () => - mapValues(props.parameterElements, (parameterElement) => { - return React.isValidElement(parameterElement) - ? React.cloneElement( - parameterElement, - { - pluginProps: { - ...parameterElement.props.pluginProps, - isSearchPage: true, - }, - } as any, - parameterElement.props.children - ) - : parameterElement; - }), - [props.parameterElements] - ); + const [showFields, setShowFields] = useState(false); - const updatedProps = useMemo( - () => ({ ...props, parameterElements }), - [props, parameterElements] - ); + const handleDocumentClick = (e: MouseEvent) => { + if ( + e.target instanceof Element && + !e.target.closest('.wdk-Answer-filterFieldSelector') + ) { + setShowFields(false); + } + }; + + useEffect(() => { + document.addEventListener('click', handleDocumentClick); + return () => document.removeEventListener('click', handleDocumentClick); + }, []); + + // Need to add `isSearchPage` prop so that organism prefs are used + const parameterElements = useMemo(() => { + // Let's go ahead and filter out parameters we aren't going to render + const { document_type, text_search_organism, ...elementsToRender } = + props.parameterElements; + return mapValues(elementsToRender, (parameterElement) => { + return React.isValidElement(parameterElement) + ? React.cloneElement( + parameterElement, + { + pluginProps: { + ...parameterElement.props.pluginProps, + isSearchPage: true, + ...(parameterElement.props.pluginProps.parameter.name === + 'text_expression' + ? { + placeholder: 'Search Data Sets', + } + : undefined), + ...(parameterElement.props.pluginProps.parameter.name === + 'text_fields' + ? { + linksPosition: LinksPosition.Top, + } + : undefined), + }, + } as any, + parameterElement.props.children + ) + : parameterElement; + }); + }, [props.parameterElements]); return ( <> - {state.question.groups - .filter((group) => group.displayType !== 'hidden') - .map((group) => { - const { parameters, ...remainingGroupProperties } = group; - const groupWithoutOrgParam = { - ...remainingGroupProperties, - parameters: parameters.filter( - (param) => - param !== 'text_search_organism' && param !== 'text_fields' - ), - }; - return renderDefaultParamGroup(groupWithoutOrgParam, updatedProps); - })} +
+ {parameterElements['text_expression']} + +
+ {showFields && ( + (e.key === 'Escape' ? setShowFields(false) : null)} + className="wdk-Answer-filterFieldSelector" + > + {parameterElements['text_fields']} +
+
+
+ )} ); } @@ -104,7 +152,7 @@ export function DatasetsSearchAndAnswer() { resultType: DEFAULT_RESULT_TYPE, reporterFormatting: DEFAULT_FORMATTING, }; - const { attributes, pagination, sorting } = answer.meta; + const { attributes } = answer.meta; return { resultType: { ...DEFAULT_RESULT_TYPE, @@ -124,8 +172,6 @@ export function DatasetsSearchAndAnswer() { formatConfig: { ...DEFAULT_FORMATTING.formatConfig, attributes, - pagination, - sorting, }, }, }; @@ -133,7 +179,7 @@ export function DatasetsSearchAndAnswer() { const downloadButton = (