diff --git a/client/src/components/Jobs/Jobs.jsx b/client/src/components/Jobs/Jobs.jsx index 1945d1bf7..48473b331 100644 --- a/client/src/components/Jobs/Jobs.jsx +++ b/client/src/components/Jobs/Jobs.jsx @@ -233,6 +233,7 @@ function JobsView({ } getRowProps={rowProps} columnMemoProps={[version]} /* TODOv3: dropV2Jobs. */ + searchTerm={query.query_string} /> ); diff --git a/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.jsx b/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.jsx new file mode 100644 index 000000000..71d13c10c --- /dev/null +++ b/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link, useLocation } from 'react-router-dom'; +import * as ROUTES from '../../../constants/routes'; +import { getOutputPath } from 'utils/jobsUtil'; +import './HighlightSearchTerm.scss'; + +const HighlightSearchTerm = ({ searchTerm, cell, id }) => { + const highlightParts = (content) => { + const parts = content.split(new RegExp(`(${searchTerm})`, 'gi')); + return parts.map((part, i) => + part.toLowerCase() === searchTerm.toLowerCase() ? ( + {part} + ) : ( + part + ) + ); + }; + + if (id == 'Output Location') { + const outputLocation = getOutputPath(cell.row.original); + + return outputLocation ? ( + + {highlightParts(outputLocation)} + + ) : null; + } else if (id == 'uuid') { + return {cell.render('Cell')}; + } else if (id == 'name') { + const jobName = cell.row.values[id]; + + return {highlightParts(jobName)}; + } + + return null; +}; + +HighlightSearchTerm.propTypes = { + searchTerm: PropTypes.string, + cell: PropTypes.object, + id: PropTypes.string, +}; + +HighlightSearchTerm.defaultProps = { + searchTerm: '', + outputLocation: '', +}; + +export default HighlightSearchTerm; \ No newline at end of file diff --git a/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.scss b/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.scss new file mode 100644 index 000000000..9f234d308 --- /dev/null +++ b/client/src/components/_common/HighlightSearchTerm/HighlightSearchTerm.scss @@ -0,0 +1,4 @@ +.highlight { + padding: 2.8px 0; + background-color: yellow; +} \ No newline at end of file diff --git a/client/src/components/_common/HighlightSearchTerm/index.js b/client/src/components/_common/HighlightSearchTerm/index.js new file mode 100644 index 000000000..aee968c3c --- /dev/null +++ b/client/src/components/_common/HighlightSearchTerm/index.js @@ -0,0 +1,3 @@ +import HighlightSearchTerm from './HighlightSearchTerm'; + +export default HighlightSearchTerm; \ No newline at end of file diff --git a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx index a3bbe85e5..e8fcfeaa6 100644 --- a/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx +++ b/client/src/components/_common/InfiniteScrollTable/InfiniteScrollTable.jsx @@ -3,6 +3,7 @@ import { useTable } from 'react-table'; import PropTypes from 'prop-types'; import LoadingSpinner from '../LoadingSpinner'; import './InfiniteScrollTable.scss'; +import { HighlightSearchTerm } from '_common'; const rowContentPropType = PropTypes.oneOfType([ PropTypes.string, @@ -54,6 +55,7 @@ const InfiniteScrollTable = ({ noDataText, getRowProps, columnMemoProps, + searchTerm, }) => { const columns = React.useMemo(() => tableColumns, columnMemoProps); const data = React.useMemo(() => tableData, [tableData]); @@ -101,7 +103,18 @@ const InfiniteScrollTable = ({ className: cell.column.className, })} > - {cell.render('Cell')} + {searchTerm !== '' && + (cell.column.id === 'name' || + cell.column.id === 'Output Location' || + cell.column.id === 'uuid') ? ( + + ) : ( + cell.render('Cell') + )} ); })} @@ -128,12 +141,15 @@ InfiniteScrollTable.propTypes = { noDataText: rowContentPropType, getRowProps: PropTypes.func, columnMemoProps: PropTypes.arrayOf(PropTypes.any), + searchTerm: PropTypes.string, + cell: PropTypes.object, }; InfiniteScrollTable.defaultProps = { onInfiniteScroll: (offset) => {}, isLoading: false, className: '', noDataText: '', + searchTerm: '', getRowProps: (row) => {}, columnMemoProps: [], }; diff --git a/client/src/components/_common/index.js b/client/src/components/_common/index.js index 3812495d2..ec663f8ca 100644 --- a/client/src/components/_common/index.js +++ b/client/src/components/_common/index.js @@ -16,6 +16,7 @@ export { default as Icon } from './Icon'; export { default as Message } from './Message'; export { default as InlineMessage } from './InlineMessage'; export { default as SectionMessage } from './SectionMessage'; +export { default as HighlightSearchTerm } from './HighlightSearchTerm'; export { default as Sidebar } from './Sidebar'; export { default as DescriptionList } from './DescriptionList'; export { default as DropdownSelector } from './DropdownSelector';