From 6b9ed2c062a67da977fbb1189fd80b00f7d699a6 Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Wed, 19 Nov 2025 15:42:24 -0800 Subject: [PATCH 1/7] - DEVSU-2757 - Establish search params as context - Use search params context to create query edit dialog in reports search view --- app/components/DataTable/index.scss | 2 +- app/components/DataTable/index.tsx | 53 +++++++++++ app/context/SearchParamsContext/index.ts | 14 +++ app/context/SearchParamsContext/types.d.ts | 15 +++ app/views/MainView/index.tsx | 102 +++++++++++---------- app/views/ReportsSearchView/index.tsx | 12 ++- app/views/SearchView/index.tsx | 39 ++++---- 7 files changed, 163 insertions(+), 74 deletions(-) create mode 100644 app/context/SearchParamsContext/index.ts create mode 100644 app/context/SearchParamsContext/types.d.ts diff --git a/app/components/DataTable/index.scss b/app/components/DataTable/index.scss index e066a4c22..f199f5dba 100644 --- a/app/components/DataTable/index.scss +++ b/app/components/DataTable/index.scss @@ -37,7 +37,7 @@ display: flex; justify-content: space-between; } - + &__action { margin: 0 8px; } diff --git a/app/components/DataTable/index.tsx b/app/components/DataTable/index.tsx index 3982e8bae..c55194240 100644 --- a/app/components/DataTable/index.tsx +++ b/app/components/DataTable/index.tsx @@ -12,12 +12,19 @@ import { import cloneDeep from 'lodash/cloneDeep'; import useGrid from '@/hooks/useGrid'; import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + Fab, IconButton, Menu, MenuItem, Typography, } from '@mui/material'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; +import ManageSearchIcon from '@mui/icons-material/ManageSearch'; import DemoDescription from '@/components/DemoDescription'; import ReportContext from '@/context/ReportContext'; @@ -36,6 +43,7 @@ import NoRowsOverlay from './components/NoRowsOverlay'; import { getDate } from '../../utils/date'; import './index.scss'; +import SearchDescription from '@/views/SearchView/components/SearchDescription'; const MAX_VISIBLE_ROWS = 12; const MAX_TABLE_HEIGHT = '517px'; @@ -233,6 +241,7 @@ const DataTable = forwardRef(({ const [menuAnchor, setMenuAnchor] = useState(); const [showReorder, setShowReorder] = useState(false); const [columnWithNames, setColumnWithNames] = useState([]); + const [showQueryEditDialog, setShowQueryEditDialog] = useState(false); const defaultColDef = useMemo(() => ({ sortable: !showReorder, @@ -506,6 +515,14 @@ const DataTable = forwardRef(({ setMenuAnchor(null); }, [handleTSVExport, onAdd, tableType, toggleReorder]); + const handleQueryEdit = useCallback(() => { + setShowQueryEditDialog(true); + }, []); + + const handleCloseQueryEdit = useCallback(() => { + setShowQueryEditDialog(false); + }, []); + const handlePaginationChanged = useCallback((params) => { const { api, newData, newPage, columnApi, @@ -554,6 +571,42 @@ const DataTable = forwardRef(({
{titleText && ({titleText})}
+ {isSearch && ( + <> + + + + + + + Edit Query + + + + + + + + + + + )} {(canAdd || canToggleColumns || canExport || canReorder) && ( ({ + searchParams: null, + setSearchParams: () => {}, +}); + +export default SearchParamsContext; + +export type { + SearchParamsType, + SearchParamsContextType, +}; diff --git a/app/context/SearchParamsContext/types.d.ts b/app/context/SearchParamsContext/types.d.ts new file mode 100644 index 000000000..3d119c93b --- /dev/null +++ b/app/context/SearchParamsContext/types.d.ts @@ -0,0 +1,15 @@ +type SearchParamsType = { + keyword: string; + category: string; + threshold: string; +}; + +type SearchParamsContextType = { + searchParams: SearchParamsType[] | null, + setSearchParams: React.Dispatch>; +}; + +export { + SearchParamsType, + SearchParamsContextType, +}; \ No newline at end of file diff --git a/app/views/MainView/index.tsx b/app/views/MainView/index.tsx index 8ba01d8df..b5f60b9b0 100644 --- a/app/views/MainView/index.tsx +++ b/app/views/MainView/index.tsx @@ -26,6 +26,7 @@ import { keycloak, logout } from '@/services/management/auth'; import './index.scss'; import { Box } from '@mui/system'; import { toInteger } from 'lodash'; +import SearchParamsContext, { SearchParamsType } from '@/context/SearchParamsContext'; const LoginView = lazy(() => import('../LoginView')); const TermsView = lazy(() => import('../TermsView')); @@ -196,6 +197,7 @@ const Main = (): JSX.Element => { }); const [sidebarMaximized, setSidebarMaximized] = useState(false); const [isNavVisible, setIsNavVisible] = useState(true); + const [searchParams, setSearchParams] = useState([]); const secContextVal = useMemo(() => ({ authorizationToken, setAuthorizationToken, userDetails, setUserDetails, @@ -205,58 +207,64 @@ const Main = (): JSX.Element => { sidebarMaximized, setSidebarMaximized, }), [sidebarMaximized, setSidebarMaximized]); + const searchParamsContextValue = useMemo(() => ({ + searchParams, setSearchParams, + }), [searchParams, setSearchParams]); + return ( -
-
- {isNavVisible ? ( - <> - - - - ) : null} - +
+
+ {isNavVisible ? ( + <> + + + + ) : null} + + + + )} > - - - )} - > - - - - - - - - - - - - - - - - - - - - - - - - - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index 4ad4d31e8..a946e8f5e 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import { useLocation } from 'react-router-dom'; import api from '@/services/api'; import withLoading, { WithLoadingInjectedProps } from '@/hoc/WithLoading'; @@ -6,6 +6,7 @@ import snackbar from '@/services/SnackbarUtils'; import DataTable from '@/components/DataTable'; import searchReportsColumns from '@/utils/searchReportsColumns'; import searchColumnDefs from '@/components/ReportsTable/searchColumnDefs'; +import SearchParamsContext from '@/context/SearchParamsContext'; import '../ReportsView/index.scss'; import './index.scss'; @@ -17,13 +18,16 @@ const ReportsSearchView = ({ setIsLoading, }: ReportsSearchViewProps): JSX.Element => { const { search } = useLocation(); - const searchParams = decodeURIComponent(search); + const searchParamsTest = decodeURIComponent(search); const [rowData, setRowData] = useState([]); + const { searchParams } = useContext(SearchParamsContext); useEffect(() => { + console.log(searchParams); + const getData = async () => { try { - const { reports } = await api.get(`/reports${searchParams}`).request(); + const { reports } = await api.get(`/reports${searchParamsTest}`).request(); setRowData(reports.map((report) => { const [analyst] = report.users @@ -55,7 +59,7 @@ const ReportsSearchView = ({ } }; getData(); - }, [search, setIsLoading]); + }, [search, setIsLoading, searchParams]); if (isLoading) { return null; } diff --git a/app/views/SearchView/index.tsx b/app/views/SearchView/index.tsx index 33a2c1190..0353268ff 100644 --- a/app/views/SearchView/index.tsx +++ b/app/views/SearchView/index.tsx @@ -20,6 +20,7 @@ import SearchIcon from '@mui/icons-material/Search'; import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import SearchDescription from './components/SearchDescription'; import React, { useCallback, useEffect, useState } from 'react'; +import { SearchParamsType } from '@/context/SearchParamsContext'; import { MIN_KEYWORD_LENGTH, DEFAULT_THRESHOLD, @@ -28,12 +29,6 @@ import { BACKSPACE_KEY, } from '@/constants'; -type SearchKeyType = { - category: string; - keyword: string; - threshold: number; -}; - // Custom css to alter select dropdown border radius const useStyles = makeStyles({ categoryBorder: { @@ -47,7 +42,7 @@ const useStyles = makeStyles({ }); const SearchView = () => { - const [searchKey, setSearchKey] = useState([]); + const [searchParams, setSearchParams] = useState([]); const [searchThreshold, setSearchThreshold] = useState(DEFAULT_THRESHOLD); const [searchCategory, setSearchCategory] = useState('keyVariant'); const [searchKeyword, setSearchKeyword] = useState(''); @@ -59,17 +54,17 @@ const SearchView = () => { // Calls submit function const handleSubmit = useCallback(() => { - if (!searchKey) { + if (!searchParams) { setSearchErrorMessage('Please enter a search keyword'); return; } const searchUrl: string[] = []; - searchKey.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); + searchParams.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); history.push({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), }); - }, [searchKey, history, encodeURIComponent]); + }, [searchParams, history, encodeURIComponent]); // Validate threshold value useEffect(() => { @@ -113,33 +108,33 @@ const SearchView = () => { setSearchErrorMessage(''); if (code === BACKSPACE_KEY && !target.value) { // Delete the last entry - setSearchKey((currData) => currData.slice(0, -1)); + setSearchParams((currData) => currData.slice(0, -1)); } if (code === ENTER_KEY || code === NUMPAD_ENTER_KEY) { // Allow user to press enter to submit search when there is no new character being entered for new keyword - if (searchKey.length > 0 && !target.value) { + if (searchParams.length > 0 && !target.value) { setSearchErrorMessage(''); const searchUrl: string[] = []; - searchKey.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); + searchParams.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); history.push({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), }); } // Validate value - if ((searchKey.length < 1 && target.value.length < MIN_KEYWORD_LENGTH ) || (searchKey.length > 0 && target.value.length > 0 && target.value.length < MIN_KEYWORD_LENGTH)) { + if ((searchParams.length < 1 && target.value.length < MIN_KEYWORD_LENGTH ) || (searchParams.length > 0 && target.value.length > 0 && target.value.length < MIN_KEYWORD_LENGTH)) { setSearchErrorMessage(`Must have 1 or more terms of at least ${MIN_KEYWORD_LENGTH} characters`); } else { setSearchErrorMessage(''); // Add new entry - setSearchKey((currData) => [...currData, { + setSearchParams((currData) => [...currData, { category: searchCategory, keyword: searchKeyword, threshold: searchThreshold, - } as SearchKeyType]); + } as SearchParamsType]); } } - }, [searchKey, searchCategory, searchKeyword, searchThreshold]); + }, [searchParams, searchCategory, searchKeyword, searchThreshold]); const handleOpen = useCallback(() => { setShowDialog(true); @@ -148,7 +143,7 @@ const SearchView = () => { const handleClose = useCallback(() => { setShowDialog(false); }, []); - + return (
@@ -213,7 +208,7 @@ const SearchView = () => { multiple options={[]} freeSolo - value={searchKey} + value={searchParams} disableClearable sx={{ '& fieldset': { @@ -226,7 +221,7 @@ const SearchView = () => { width: '100%', }} limitTags={4} - renderTags={(value) => value.map(({ category, keyword, threshold }: SearchKeyType, index: number) => ( + renderTags={(value) => value.map(({ category, keyword, threshold }: SearchParamsType, index: number) => ( { error={Boolean(searchErrorMessage)} onChange={handleKeywordChange} onKeyDown={handleKeyDown} - placeholder={searchKey.length < 1 ? 'After inputting a keyword, press enter to add search chip. Press backspace to delete.' : ''} + placeholder={searchParams.length < 1 ? 'After inputting a keyword, press enter to add search chip. Press backspace to delete.' : ''} InputProps={{ ...params.InputProps, endAdornment: ( @@ -254,7 +249,7 @@ const SearchView = () => { color="primary" size="large" onClick={handleSubmit} - disabled={searchKey.length < 1 || !!searchErrorMessage || !!thresholdErrorMessage} + disabled={searchParams.length < 1 || !!searchErrorMessage || !!thresholdErrorMessage} type="submit" sx={{ display: 'flex', From b02bffcc00ab4cb08c8c06a6f3e9b911810b9926 Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Mon, 24 Nov 2025 16:23:36 -0800 Subject: [PATCH 2/7] - DEVSU-2757 - Create new Edit Query button in report search view to edit search parameters without returning to search view --- .../components/QueryEditDialog/index.scss | 50 +++ .../components/QueryEditDialog/index.tsx | 343 ++++++++++++++++++ app/components/DataTable/index.tsx | 57 +-- app/context/SearchParamsContext/index.ts | 2 +- app/hooks/useSearchParams.tsx | 7 + app/views/ReportsSearchView/index.tsx | 8 +- app/views/SearchView/index.tsx | 35 +- 7 files changed, 428 insertions(+), 74 deletions(-) create mode 100644 app/components/DataTable/components/QueryEditDialog/index.scss create mode 100644 app/components/DataTable/components/QueryEditDialog/index.tsx create mode 100644 app/hooks/useSearchParams.tsx diff --git a/app/components/DataTable/components/QueryEditDialog/index.scss b/app/components/DataTable/components/QueryEditDialog/index.scss new file mode 100644 index 000000000..1ded438d7 --- /dev/null +++ b/app/components/DataTable/components/QueryEditDialog/index.scss @@ -0,0 +1,50 @@ +.query-edit-dialog-search { + + &__component { + width: fit-content; + } + + &__bar { + box-sizing: border-box; + display: flex; + margin-top: 24px; + padding-left: 12px; + padding-right: 12px; + width: 100%; + } + + &__keyword-input { + -webkit-tap-highlight-color: transparent; + width: 850px; + display: flex; + } + + &__category-input { + width: 200px; + display: flex; + } + + &__threshold-input { + width: 70px; + display: flex; + + // Removes arrows in number input + input::-webkit-outer-spin-button, + input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; + } + input[type=number] { + -moz-appearance: textfield; + } + } + + .error-dialog { + max-width: 1100px; + min-width: 1100px; + margin-top: 8px; + height: auto; + padding-left: 48px; + padding-right: 48px; + } +} \ No newline at end of file diff --git a/app/components/DataTable/components/QueryEditDialog/index.tsx b/app/components/DataTable/components/QueryEditDialog/index.tsx new file mode 100644 index 000000000..811720d2b --- /dev/null +++ b/app/components/DataTable/components/QueryEditDialog/index.tsx @@ -0,0 +1,343 @@ +import { + TextField, + Typography, + Button, + Chip, + Autocomplete, + FormControl, + MenuItem, + Select, + SelectChangeEvent, + InputAdornment, + Dialog, + DialogActions, + DialogContent, + DialogTitle, +} from '@mui/material'; +import { makeStyles } from '@mui/styles'; +import { useHistory } from 'react-router-dom'; +import SearchIcon from '@mui/icons-material/Search'; +import ManageSearchIcon from '@mui/icons-material/ManageSearch'; +import React, { useCallback, useEffect, useState } from 'react'; +import { SearchParamsType } from '@/context/SearchParamsContext'; +import useSearchParams from '@/hooks/useSearchParams'; + +import './index.scss'; + +import { + MIN_KEYWORD_LENGTH, + DEFAULT_THRESHOLD, + ENTER_KEY, + NUMPAD_ENTER_KEY, + BACKSPACE_KEY, +} from '@/constants'; + +// Custom css to alter select dropdown border radius +const useStyles = makeStyles({ + categoryBorder: { + '& .MuiOutlinedInput-notchedOutline': { + borderTopLeftRadius: '25px', + borderBottomLeftRadius: '25px', + borderTopRightRadius: '0px', + borderBottomRightRadius: '0px', + }, + }, +}); + +const SearchBar = ({ onSuccess }: { onSuccess: (searchParams: SearchParamsType[]) => void }) => { + const { searchParams, setSearchParams } = useSearchParams(); + const [searchThreshold, setSearchThreshold] = useState(DEFAULT_THRESHOLD); + const [searchCategory, setSearchCategory] = useState('keyVariant'); + const [searchKeyword, setSearchKeyword] = useState(''); + const [searchErrorMessage, setSearchErrorMessage] = useState(''); + const [thresholdErrorMessage, setThresholdErrorMessage] = useState(''); + const customCss = useStyles(); + + // Validate threshold value + useEffect(() => { + if (!searchThreshold) { + setThresholdErrorMessage('Threshold must not be empty'); + } else { + const numThreshold = parseFloat(searchThreshold); + if (!Number.isNaN(numThreshold)) { + if (numThreshold < 0 || numThreshold > 1) { + setThresholdErrorMessage('Threshold must be between 0 and 1'); + } else { + setThresholdErrorMessage(''); + } + } else { + setThresholdErrorMessage('Threshold must be a number'); + } + } + }, [searchThreshold]); + + const handleCategoryChange = (event: SelectChangeEvent) => { + setSearchCategory(event.target.value); + }; + + const handleThresholdChange = useCallback((event) => { + const newThreshold = event.target.value; + + if (newThreshold !== searchThreshold) { + setSearchThreshold(newThreshold); + } + }, [searchThreshold]); + + const handleKeywordChange = useCallback((event) => { + const newKeyword = event.target.value; + + if (newKeyword !== searchKeyword) { + setSearchKeyword(newKeyword); + } + }, [searchKeyword]); + + // Calls submit function + const handleSubmit = useCallback(() => { + if (!searchParams) { + setSearchErrorMessage('Please enter a search keyword'); + return; + } + onSuccess(searchParams); + }, [searchParams, onSuccess]); + + const handleKeyDown = useCallback((e) => { + const { code, target } = e; + setSearchErrorMessage(''); + if (code === BACKSPACE_KEY && !target.value) { + // Delete the last entry + setSearchParams((currData) => currData.slice(0, -1)); + } + if (code === ENTER_KEY || code === NUMPAD_ENTER_KEY) { + e.preventDefault(); + // Allow user to press enter to submit search when there is no new character being entered for new keyword + if (searchParams.length > 0 && !target.value) { + setSearchErrorMessage(''); + handleSubmit(); + return; + } + // Validate value + if ( + (searchParams.length < 1 && target.value.length < MIN_KEYWORD_LENGTH) || + (searchParams.length > 0 && target.value.length > 0 && target.value.length < MIN_KEYWORD_LENGTH) + ) { + setSearchErrorMessage(`Must have 1 or more terms of at least ${MIN_KEYWORD_LENGTH} characters`); + return; + } + setSearchErrorMessage(''); + // Add new entry + setSearchParams([ + ...searchParams, + { + category: searchCategory, + keyword: searchKeyword, + threshold: searchThreshold, + }, + ]); + setSearchKeyword(''); + } + }, [searchParams, searchCategory, searchKeyword, searchThreshold, handleSubmit]); + + return ( +
+
+
+ + + +
+
+ +
+
+ value.map(({ category, keyword, threshold }: SearchParamsType, index: number) => ( + + ))} + renderInput={(params) => ( + + + + + {params.InputProps.endAdornment} + + ), + }} + /> + )} + /> +
+
+
+ + {searchErrorMessage} + +
+
+ + {thresholdErrorMessage} + +
+
+ ); +}; + +const QueryEditDialog = () => { + const [showQueryEditDialog, setShowQueryEditDialog] = useState(false); + const history = useHistory(); + + const openQueryEdit = useCallback(() => { + setShowQueryEditDialog(true); + }, []); + + const closeQueryEdit = useCallback(() => { + setShowQueryEditDialog(false); + }, []); + + const handleQueryEdit = useCallback((searchParams) => { + closeQueryEdit(); + + if (searchParams) { + const searchUrl = searchParams + .map((key) => `[${key.category}|${key.keyword}|${key.threshold}]`) + .join(''); + history.replace({ + pathname: '/search/result', + search: encodeURIComponent(`searchParams=${searchUrl}`), + }); + } + }, [history]); + + return ( + <> + + + + + + + Edit Query + + + + + + + + + + + ); +} + +export default QueryEditDialog; \ No newline at end of file diff --git a/app/components/DataTable/index.tsx b/app/components/DataTable/index.tsx index c55194240..17a5aee91 100644 --- a/app/components/DataTable/index.tsx +++ b/app/components/DataTable/index.tsx @@ -12,19 +12,12 @@ import { import cloneDeep from 'lodash/cloneDeep'; import useGrid from '@/hooks/useGrid'; import { - Button, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - Fab, IconButton, Menu, MenuItem, Typography, } from '@mui/material'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; -import ManageSearchIcon from '@mui/icons-material/ManageSearch'; import DemoDescription from '@/components/DemoDescription'; import ReportContext from '@/context/ReportContext'; @@ -43,7 +36,7 @@ import NoRowsOverlay from './components/NoRowsOverlay'; import { getDate } from '../../utils/date'; import './index.scss'; -import SearchDescription from '@/views/SearchView/components/SearchDescription'; +import QueryEditDialog from './components/QueryEditDialog'; const MAX_VISIBLE_ROWS = 12; const MAX_TABLE_HEIGHT = '517px'; @@ -241,7 +234,6 @@ const DataTable = forwardRef(({ const [menuAnchor, setMenuAnchor] = useState(); const [showReorder, setShowReorder] = useState(false); const [columnWithNames, setColumnWithNames] = useState([]); - const [showQueryEditDialog, setShowQueryEditDialog] = useState(false); const defaultColDef = useMemo(() => ({ sortable: !showReorder, @@ -515,14 +507,6 @@ const DataTable = forwardRef(({ setMenuAnchor(null); }, [handleTSVExport, onAdd, tableType, toggleReorder]); - const handleQueryEdit = useCallback(() => { - setShowQueryEditDialog(true); - }, []); - - const handleCloseQueryEdit = useCallback(() => { - setShowQueryEditDialog(false); - }, []); - const handlePaginationChanged = useCallback((params) => { const { api, newData, newPage, columnApi, @@ -566,46 +550,15 @@ const DataTable = forwardRef(({ return (
- {Boolean(rowData.length) || canEdit ? ( + {Boolean(rowData.length) || canEdit || isSearch ? ( <>
{titleText && ({titleText})}
{isSearch && ( - <> - - - - - - - Edit Query - - - - - - - - - - + + + )} {(canAdd || canToggleColumns || canExport || canReorder) && ( diff --git a/app/context/SearchParamsContext/index.ts b/app/context/SearchParamsContext/index.ts index b9bec2215..66e4c2fcb 100644 --- a/app/context/SearchParamsContext/index.ts +++ b/app/context/SearchParamsContext/index.ts @@ -3,7 +3,7 @@ import { SearchParamsType, SearchParamsContextType } from './types'; const SearchParamsContext = React.createContext({ searchParams: null, - setSearchParams: () => {}, + setSearchParams: () => {[]}, }); export default SearchParamsContext; diff --git a/app/hooks/useSearchParams.tsx b/app/hooks/useSearchParams.tsx new file mode 100644 index 000000000..0b258a87c --- /dev/null +++ b/app/hooks/useSearchParams.tsx @@ -0,0 +1,7 @@ +import { useContext } from 'react'; + +import SearchParamsContext, { SearchParamsContextType } from '@/context/SearchParamsContext'; + +const useSearchParams = (): SearchParamsContextType => useContext(SearchParamsContext); + +export default useSearchParams; diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index a946e8f5e..6987b0e80 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -6,7 +6,6 @@ import snackbar from '@/services/SnackbarUtils'; import DataTable from '@/components/DataTable'; import searchReportsColumns from '@/utils/searchReportsColumns'; import searchColumnDefs from '@/components/ReportsTable/searchColumnDefs'; -import SearchParamsContext from '@/context/SearchParamsContext'; import '../ReportsView/index.scss'; import './index.scss'; @@ -18,16 +17,13 @@ const ReportsSearchView = ({ setIsLoading, }: ReportsSearchViewProps): JSX.Element => { const { search } = useLocation(); - const searchParamsTest = decodeURIComponent(search); + const searchParams = decodeURIComponent(search); const [rowData, setRowData] = useState([]); - const { searchParams } = useContext(SearchParamsContext); useEffect(() => { - console.log(searchParams); - const getData = async () => { try { - const { reports } = await api.get(`/reports${searchParamsTest}`).request(); + const { reports } = await api.get(`/reports${searchParams}`).request(); setRowData(reports.map((report) => { const [analyst] = report.users diff --git a/app/views/SearchView/index.tsx b/app/views/SearchView/index.tsx index 0353268ff..27befbab2 100644 --- a/app/views/SearchView/index.tsx +++ b/app/views/SearchView/index.tsx @@ -21,6 +21,8 @@ import QuestionMarkIcon from '@mui/icons-material/QuestionMark'; import SearchDescription from './components/SearchDescription'; import React, { useCallback, useEffect, useState } from 'react'; import { SearchParamsType } from '@/context/SearchParamsContext'; +import useSearchParams from '@/hooks/useSearchParams'; + import { MIN_KEYWORD_LENGTH, DEFAULT_THRESHOLD, @@ -42,7 +44,7 @@ const useStyles = makeStyles({ }); const SearchView = () => { - const [searchParams, setSearchParams] = useState([]); + const { searchParams, setSearchParams } = useSearchParams(); const [searchThreshold, setSearchThreshold] = useState(DEFAULT_THRESHOLD); const [searchCategory, setSearchCategory] = useState('keyVariant'); const [searchKeyword, setSearchKeyword] = useState(''); @@ -64,7 +66,7 @@ const SearchView = () => { pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), }); - }, [searchParams, history, encodeURIComponent]); + }, [searchParams, history]); // Validate threshold value useEffect(() => { @@ -114,25 +116,28 @@ const SearchView = () => { // Allow user to press enter to submit search when there is no new character being entered for new keyword if (searchParams.length > 0 && !target.value) { setSearchErrorMessage(''); - const searchUrl: string[] = []; - searchParams.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); - history.push({ - pathname: '/search/result', - search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), - }); + handleSubmit(); + return; } // Validate value - if ((searchParams.length < 1 && target.value.length < MIN_KEYWORD_LENGTH ) || (searchParams.length > 0 && target.value.length > 0 && target.value.length < MIN_KEYWORD_LENGTH)) { + if ( + (searchParams.length < 1 && target.value.length < MIN_KEYWORD_LENGTH) || + (searchParams.length > 0 && target.value.length > 0 && target.value.length < MIN_KEYWORD_LENGTH) + ) { setSearchErrorMessage(`Must have 1 or more terms of at least ${MIN_KEYWORD_LENGTH} characters`); - } else { - setSearchErrorMessage(''); - // Add new entry - setSearchParams((currData) => [...currData, { + return; + } + setSearchErrorMessage(''); + // Add new entry + setSearchParams([ + ...searchParams, + { category: searchCategory, keyword: searchKeyword, threshold: searchThreshold, - } as SearchParamsType]); - } + }, + ]); + setSearchKeyword(''); } }, [searchParams, searchCategory, searchKeyword, searchThreshold]); From fb8b621044b44dec855b831e8029664e0b7f1713 Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Tue, 25 Nov 2025 13:52:33 -0800 Subject: [PATCH 3/7] - Update report search view query logic to use react query - Add loading indicator to edit query button when api is loading --- app/common.d.ts | 1 + .../components/QueryEditDialog/index.tsx | 12 +++-- app/components/DataTable/index.tsx | 5 +- app/views/ReportsSearchView/index.tsx | 53 +++++++++++-------- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/app/common.d.ts b/app/common.d.ts index d33966b80..ffc1926ef 100644 --- a/app/common.d.ts +++ b/app/common.d.ts @@ -44,6 +44,7 @@ type RecordDefaults = { ident: string; updatedAt: string | null; createdAt: string | null; + deletedAt: string | null; }; type UserGroupMemberType = { diff --git a/app/components/DataTable/components/QueryEditDialog/index.tsx b/app/components/DataTable/components/QueryEditDialog/index.tsx index 811720d2b..ab06c6d08 100644 --- a/app/components/DataTable/components/QueryEditDialog/index.tsx +++ b/app/components/DataTable/components/QueryEditDialog/index.tsx @@ -13,6 +13,7 @@ import { DialogActions, DialogContent, DialogTitle, + CircularProgress, } from '@mui/material'; import { makeStyles } from '@mui/styles'; import { useHistory } from 'react-router-dom'; @@ -278,7 +279,7 @@ const SearchBar = ({ onSuccess }: { onSuccess: (searchParams: SearchParamsType[] ); }; -const QueryEditDialog = () => { +const QueryEditDialog = ({isApiLoading}) => { const [showQueryEditDialog, setShowQueryEditDialog] = useState(false); const history = useHistory(); @@ -297,7 +298,7 @@ const QueryEditDialog = () => { const searchUrl = searchParams .map((key) => `[${key.category}|${key.keyword}|${key.threshold}]`) .join(''); - history.replace({ + history.push({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl}`), }); @@ -312,12 +313,17 @@ const QueryEditDialog = () => { color="primary" size="large" onClick={openQueryEdit} + disabled={isApiLoading} style={{ borderRadius: 10, padding: '4px 8px', }} > - + { + isApiLoading + ? + : + } Edit Query diff --git a/app/components/DataTable/index.tsx b/app/components/DataTable/index.tsx index 17a5aee91..15aec565f 100644 --- a/app/components/DataTable/index.tsx +++ b/app/components/DataTable/index.tsx @@ -164,6 +164,8 @@ type DataTableCustomProps = { isPaginated?: boolean; /* Whether the data table is being used to display search results for reports by variant */ isSearch?: boolean; + /* Whether the data for table is being loaded */ + isApiLoading?: boolean; /* Callback function when add is called */ onAdd?: (row: Record) => void; /* Callback function when delete is called */ @@ -210,6 +212,7 @@ const DataTable = forwardRef(({ isPaginated = true, isPrint, isSearch = false, + isApiLoading = false, onAdd, onDelete, onEdit, @@ -557,7 +560,7 @@ const DataTable = forwardRef(({
{isSearch && ( - + )} {(canAdd || canToggleColumns || canExport || canReorder) && ( diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index 6987b0e80..db235514b 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -1,31 +1,41 @@ -import React, { useState, useEffect, useContext } from 'react'; +import React, { useMemo } from 'react'; import { useLocation } from 'react-router-dom'; import api from '@/services/api'; -import withLoading, { WithLoadingInjectedProps } from '@/hoc/WithLoading'; import snackbar from '@/services/SnackbarUtils'; import DataTable from '@/components/DataTable'; +import withLoading, { WithLoadingInjectedProps } from '@/hoc/WithLoading'; import searchReportsColumns from '@/utils/searchReportsColumns'; import searchColumnDefs from '@/components/ReportsTable/searchColumnDefs'; +import { useQuery } from 'react-query'; +import { ReportType } from '@/context/ReportContext'; import '../ReportsView/index.scss'; import './index.scss'; type ReportsSearchViewProps = WithLoadingInjectedProps; +/** + * Report table containing all searched reports + */ const ReportsSearchView = ({ isLoading, setIsLoading, }: ReportsSearchViewProps): JSX.Element => { const { search } = useLocation(); - const searchParams = decodeURIComponent(search); - const [rowData, setRowData] = useState([]); - useEffect(() => { - const getData = async () => { - try { - const { reports } = await api.get(`/reports${searchParams}`).request(); + const searchParams = useMemo(() => { + return decodeURIComponent(search); + }, [decodeURIComponent, search]); - setRowData(reports.map((report) => { + const { data: reportsData, isFetching: isApiLoading } = useQuery( + `/reports${searchParams}`, + async ({ queryKey: [route] }) => await api.get(route).request(), + { + staleTime: Infinity, + retry: 1, + enabled: Boolean(searchParams), + select: (response) => { + const reports = response.reports.map((report: ReportType) => { const [analyst] = report.users .filter((u) => u.role === 'analyst' && !u.deletedAt) .map((u) => u.user); @@ -38,35 +48,36 @@ const ReportsSearchView = ({ .filter((u) => u.role === 'bioinformatician') .map((u) => u.user); - const reportData = report; + const cleanedReport = report; - if (!report.patientInformation) { - reportData.patientInformation = {}; + if (!cleanedReport.patientInformation) { + cleanedReport.patientInformation = null; } return ( - searchReportsColumns(reportData, analyst, reviewer, bioinformatician) + searchReportsColumns(cleanedReport, analyst, reviewer, bioinformatician) ); - })); - } catch (err) { - snackbar.error(`Network error: ${err}`); - } finally { + }); setIsLoading(false); + return reports; + }, + onError: (err: any) => { + snackbar.error(`API error: ${err.message}`) } - }; - getData(); - }, [search, setIsLoading, searchParams]); + }, + ); if (isLoading) { return null; } return (
); From 71b3674b41600886384bb984fed521a3aee603ad Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Tue, 25 Nov 2025 16:01:46 -0800 Subject: [PATCH 4/7] - Minor logic updates + lint --- .../components/QueryEditDialog/index.tsx | 7 +- app/components/DataTable/index.tsx | 72 +++++++++---------- app/views/ReportsSearchView/index.tsx | 7 +- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/app/components/DataTable/components/QueryEditDialog/index.tsx b/app/components/DataTable/components/QueryEditDialog/index.tsx index ab06c6d08..db2a9375c 100644 --- a/app/components/DataTable/components/QueryEditDialog/index.tsx +++ b/app/components/DataTable/components/QueryEditDialog/index.tsx @@ -32,6 +32,7 @@ import { NUMPAD_ENTER_KEY, BACKSPACE_KEY, } from '@/constants'; +import { useQueryClient } from 'react-query'; // Custom css to alter select dropdown border radius const useStyles = makeStyles({ @@ -282,6 +283,7 @@ const SearchBar = ({ onSuccess }: { onSuccess: (searchParams: SearchParamsType[] const QueryEditDialog = ({isApiLoading}) => { const [showQueryEditDialog, setShowQueryEditDialog] = useState(false); const history = useHistory(); + const queryClient = useQueryClient(); const openQueryEdit = useCallback(() => { setShowQueryEditDialog(true); @@ -298,10 +300,13 @@ const QueryEditDialog = ({isApiLoading}) => { const searchUrl = searchParams .map((key) => `[${key.category}|${key.keyword}|${key.threshold}]`) .join(''); - history.push({ + history.replace({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl}`), }); + queryClient.refetchQueries({ + queryKey: [`/reports?searchParams=${searchUrl}`] + }); } }, [history]); diff --git a/app/components/DataTable/index.tsx b/app/components/DataTable/index.tsx index 15aec565f..0a28f05fb 100644 --- a/app/components/DataTable/index.tsx +++ b/app/components/DataTable/index.tsx @@ -564,42 +564,42 @@ const DataTable = forwardRef(({ )} {(canAdd || canToggleColumns || canExport || canReorder) && ( - - setMenuAnchor(event.currentTarget)} - className="data-table__icon-button" - size="large" - > - - - setMenuAnchor(null)} - > - {canAdd && ( - handleMenuItemClick('add')}> - {addText || 'Add row'} - - )} - {canToggleColumns && ( - handleMenuItemClick('toggle')}> - Toggle Columns - - )} - {canExport && ( - handleMenuItemClick('export')}> - Export to TSV - - )} - {canReorder && ( - handleMenuItemClick('reorder')}> - Reorder Rows - - )} - {additionalTableMenuItems && additionalTableMenuItems(gridApi)} - - + + setMenuAnchor(event.currentTarget)} + className="data-table__icon-button" + size="large" + > + + + setMenuAnchor(null)} + > + {canAdd && ( + handleMenuItemClick('add')}> + {addText || 'Add row'} + + )} + {canToggleColumns && ( + handleMenuItemClick('toggle')}> + Toggle Columns + + )} + {canExport && ( + handleMenuItemClick('export')}> + Export to TSV + + )} + {canReorder && ( + handleMenuItemClick('reorder')}> + Reorder Rows + + )} + {additionalTableMenuItems && additionalTableMenuItems(gridApi)} + + )}
diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index db235514b..7bca387ff 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -31,7 +31,7 @@ const ReportsSearchView = ({ `/reports${searchParams}`, async ({ queryKey: [route] }) => await api.get(route).request(), { - staleTime: Infinity, + staleTime: 0, retry: 1, enabled: Boolean(searchParams), select: (response) => { @@ -58,10 +58,13 @@ const ReportsSearchView = ({ searchReportsColumns(cleanedReport, analyst, reviewer, bioinformatician) ); }); - setIsLoading(false); return reports; }, + onSettled: () => { + setIsLoading(false); + }, onError: (err: any) => { + setIsLoading(false); snackbar.error(`API error: ${err.message}`) } }, From ed091356eaa6731511817d136516da1bfe8df873 Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Wed, 26 Nov 2025 14:19:17 -0800 Subject: [PATCH 5/7] - Add delete button to search chips - Persist context so refreshing the view does not get rid of search chips --- .../components/QueryEditDialog/index.tsx | 12 ++++++- app/views/ReportsSearchView/index.tsx | 32 ++++++++++++++++--- app/views/SearchView/index.tsx | 19 +++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/app/components/DataTable/components/QueryEditDialog/index.tsx b/app/components/DataTable/components/QueryEditDialog/index.tsx index db2a9375c..46e77b61f 100644 --- a/app/components/DataTable/components/QueryEditDialog/index.tsx +++ b/app/components/DataTable/components/QueryEditDialog/index.tsx @@ -139,6 +139,15 @@ const SearchBar = ({ onSuccess }: { onSuccess: (searchParams: SearchParamsType[] } }, [searchParams, searchCategory, searchKeyword, searchThreshold, handleSubmit]); + const handleDeleteSearchKey = useCallback((idx) => { + setSearchParams((currData) => { + const nextData = [...currData]; + nextData.splice(idx, 1); + return nextData; + }); + setSearchErrorMessage(''); + }, []); + return (
@@ -223,6 +232,7 @@ const SearchBar = ({ onSuccess }: { onSuccess: (searchParams: SearchParamsType[] key={`${keyword}-${index}`} label={`${category} | ${keyword} | ${threshold}`} sx={{ marginRight: '5px' }} + onDelete={() => handleDeleteSearchKey(index)} /> ))} renderInput={(params) => ( @@ -308,7 +318,7 @@ const QueryEditDialog = ({isApiLoading}) => { queryKey: [`/reports?searchParams=${searchUrl}`] }); } - }, [history]); + }, [history, queryClient]); return ( <> diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index 7bca387ff..0b6ddfdc8 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -8,6 +8,8 @@ import searchReportsColumns from '@/utils/searchReportsColumns'; import searchColumnDefs from '@/components/ReportsTable/searchColumnDefs'; import { useQuery } from 'react-query'; import { ReportType } from '@/context/ReportContext'; +import useSearchParams from '@/hooks/useSearchParams'; +import { SearchParamsType } from '@/context/SearchParamsContext'; import '../ReportsView/index.scss'; import './index.scss'; @@ -22,18 +24,34 @@ const ReportsSearchView = ({ setIsLoading, }: ReportsSearchViewProps): JSX.Element => { const { search } = useLocation(); + const { searchParams, setSearchParams } = useSearchParams(); - const searchParams = useMemo(() => { + const searchParamsUrl = useMemo(() => { return decodeURIComponent(search); }, [decodeURIComponent, search]); + const parseSearchParamsFromUrl = (searchParamsUrl: string) => { + const params: SearchParamsType[] = []; + const regex = /\[([^|]+)\|([^|]+)\|([^]+?)\]/g; + let match = []; + + while ((match = regex.exec(searchParamsUrl)) !== null) { + params.push({ + category: match[1], + keyword: match[2], + threshold: match[3], + }); + } + + return params; + } + const { data: reportsData, isFetching: isApiLoading } = useQuery( - `/reports${searchParams}`, + `/reports${searchParamsUrl}`, async ({ queryKey: [route] }) => await api.get(route).request(), { staleTime: 0, - retry: 1, - enabled: Boolean(searchParams), + enabled: Boolean(searchParamsUrl), select: (response) => { const reports = response.reports.map((report: ReportType) => { const [analyst] = report.users @@ -62,9 +80,13 @@ const ReportsSearchView = ({ }, onSettled: () => { setIsLoading(false); + + // Re-populating context using url without having to store search params in local storage + if (!searchParams || !searchParams.length) { + setSearchParams(parseSearchParamsFromUrl(searchParamsUrl)); + } }, onError: (err: any) => { - setIsLoading(false); snackbar.error(`API error: ${err.message}`) } }, diff --git a/app/views/SearchView/index.tsx b/app/views/SearchView/index.tsx index 27befbab2..3a7fea25a 100644 --- a/app/views/SearchView/index.tsx +++ b/app/views/SearchView/index.tsx @@ -30,6 +30,7 @@ import { NUMPAD_ENTER_KEY, BACKSPACE_KEY, } from '@/constants'; +import { useQueryClient } from 'react-query'; // Custom css to alter select dropdown border radius const useStyles = makeStyles({ @@ -53,6 +54,7 @@ const SearchView = () => { const [thresholdErrorMessage, setThresholdErrorMessage] = useState(''); const [showDialog, setShowDialog] = useState(false); const customCss = useStyles(); + const queryClient = useQueryClient(); // Calls submit function const handleSubmit = useCallback(() => { @@ -62,11 +64,14 @@ const SearchView = () => { } const searchUrl: string[] = []; searchParams.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); - history.push({ + history.replace({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), }); - }, [searchParams, history]); + queryClient.refetchQueries({ + queryKey: [`/reports?searchParams=${searchUrl.join('')}`] + }); + }, [searchParams, history, queryClient]); // Validate threshold value useEffect(() => { @@ -148,6 +153,15 @@ const SearchView = () => { const handleClose = useCallback(() => { setShowDialog(false); }, []); + + const handleDeleteSearchKey = useCallback((idx) => { + setSearchParams((currData) => { + const nextData = [...currData]; + nextData.splice(idx, 1); + return nextData; + }); + setSearchErrorMessage(''); + }, []); return (
@@ -233,6 +247,7 @@ const SearchView = () => { key={`${keyword}-${index}`} label={`${category} | ${keyword} | ${threshold}`} sx={{ marginRight: '5px' }} + onDelete={() => handleDeleteSearchKey(index)} /> ))} renderInput={(params) => ( From bf5616fcff12035d8aaaa4cdd6df8c87b4bab86c Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Wed, 26 Nov 2025 15:53:05 -0800 Subject: [PATCH 6/7] - Update navigate method from replace to push - Update handle query edit dependencies --- app/components/DataTable/components/QueryEditDialog/index.tsx | 4 ++-- app/views/SearchView/index.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/DataTable/components/QueryEditDialog/index.tsx b/app/components/DataTable/components/QueryEditDialog/index.tsx index 46e77b61f..3c9dcf710 100644 --- a/app/components/DataTable/components/QueryEditDialog/index.tsx +++ b/app/components/DataTable/components/QueryEditDialog/index.tsx @@ -310,7 +310,7 @@ const QueryEditDialog = ({isApiLoading}) => { const searchUrl = searchParams .map((key) => `[${key.category}|${key.keyword}|${key.threshold}]`) .join(''); - history.replace({ + history.push({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl}`), }); @@ -318,7 +318,7 @@ const QueryEditDialog = ({isApiLoading}) => { queryKey: [`/reports?searchParams=${searchUrl}`] }); } - }, [history, queryClient]); + }, [history, queryClient, closeQueryEdit]); return ( <> diff --git a/app/views/SearchView/index.tsx b/app/views/SearchView/index.tsx index 3a7fea25a..930bba4c3 100644 --- a/app/views/SearchView/index.tsx +++ b/app/views/SearchView/index.tsx @@ -64,7 +64,7 @@ const SearchView = () => { } const searchUrl: string[] = []; searchParams.forEach((key) => searchUrl.push(`[${key.category}|${key.keyword}|${key.threshold}]`)); - history.replace({ + history.push({ pathname: '/search/result', search: encodeURIComponent(`searchParams=${searchUrl.join('')}`), }); From fe59712e4fec64f06cac2271dd213418019bc00f Mon Sep 17 00:00:00 2001 From: bnguyen-bcgsc Date: Mon, 1 Dec 2025 16:00:14 -0800 Subject: [PATCH 7/7] - Fix empty rendered table bug in reports search view after query returns no record --- app/views/ReportsSearchView/index.scss | 10 ++++++++++ app/views/ReportsSearchView/index.tsx | 17 +++++++---------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/views/ReportsSearchView/index.scss b/app/views/ReportsSearchView/index.scss index 6bc9c7ac1..eacf709c3 100644 --- a/app/views/ReportsSearchView/index.scss +++ b/app/views/ReportsSearchView/index.scss @@ -3,3 +3,13 @@ .reports-table { height: calc(100% - #{$navbar-size}); } + +.centered { + flex-grow: 1; + height: 100%; + align-items: center; + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; +} diff --git a/app/views/ReportsSearchView/index.tsx b/app/views/ReportsSearchView/index.tsx index 0b6ddfdc8..4666adbcc 100644 --- a/app/views/ReportsSearchView/index.tsx +++ b/app/views/ReportsSearchView/index.tsx @@ -3,26 +3,21 @@ import { useLocation } from 'react-router-dom'; import api from '@/services/api'; import snackbar from '@/services/SnackbarUtils'; import DataTable from '@/components/DataTable'; -import withLoading, { WithLoadingInjectedProps } from '@/hoc/WithLoading'; import searchReportsColumns from '@/utils/searchReportsColumns'; import searchColumnDefs from '@/components/ReportsTable/searchColumnDefs'; import { useQuery } from 'react-query'; import { ReportType } from '@/context/ReportContext'; import useSearchParams from '@/hooks/useSearchParams'; import { SearchParamsType } from '@/context/SearchParamsContext'; +import { CircularProgress } from '@mui/material'; import '../ReportsView/index.scss'; import './index.scss'; -type ReportsSearchViewProps = WithLoadingInjectedProps; - /** * Report table containing all searched reports */ -const ReportsSearchView = ({ - isLoading, - setIsLoading, -}: ReportsSearchViewProps): JSX.Element => { +const ReportsSearchView = (): JSX.Element => { const { search } = useLocation(); const { searchParams, setSearchParams } = useSearchParams(); @@ -79,7 +74,7 @@ const ReportsSearchView = ({ return reports; }, onSettled: () => { - setIsLoading(false); + // setIsLoading(false); // Re-populating context using url without having to store search params in local storage if (!searchParams || !searchParams.length) { @@ -92,7 +87,9 @@ const ReportsSearchView = ({ }, ); - if (isLoading) { return null; } + if (isApiLoading) { + return
+ } return (
@@ -108,4 +105,4 @@ const ReportsSearchView = ({ ); }; -export default withLoading(ReportsSearchView); +export default ReportsSearchView;