diff --git a/frontend/packages/data-portal/app/components/BrowseData/BrowseDataSearch.tsx b/frontend/packages/data-portal/app/components/BrowseData/BrowseDataSearch.tsx index 9db153e70..001d25f98 100644 --- a/frontend/packages/data-portal/app/components/BrowseData/BrowseDataSearch.tsx +++ b/frontend/packages/data-portal/app/components/BrowseData/BrowseDataSearch.tsx @@ -1,10 +1,13 @@ import { InputSearch } from '@czi-sds/components' import { useDebouncedEffect } from '@react-hookz/web' import { useSearchParams } from '@remix-run/react' -import { useRef, useState } from 'react' +import { useAtom } from 'jotai' +import { useHydrateAtoms } from 'jotai/utils' +import { useEffect, useRef } from 'react' import { QueryParams } from 'app/constants/query' import { i18n } from 'app/i18n' +import { searchQueryAtom } from 'app/state/search' /** * The amount of time to wait after the user has typed in a query before @@ -15,7 +18,14 @@ const SEARCH_QUERY_DEBOUNCE_TIME_MS = 500 export function BrowseDataSearch() { const [searchParams, setSearchParams] = useSearchParams() - const [query, setQuery] = useState(searchParams.get(QueryParams.Search) ?? '') + const [query, setQuery] = useAtom(searchQueryAtom) + + useHydrateAtoms([ + [searchQueryAtom, searchParams.get(QueryParams.Search) ?? ''], + ]) + + // Reset when navigating away + useEffect(() => () => setQuery(''), [setQuery]) // If the user hasn't typed in a key for 500ms, then update the search params. const initialLoadRef = useRef(true) diff --git a/frontend/packages/data-portal/app/components/NoFilteredResults.tsx b/frontend/packages/data-portal/app/components/NoFilteredResults.tsx index 1c7edb04b..a73cfb003 100644 --- a/frontend/packages/data-portal/app/components/NoFilteredResults.tsx +++ b/frontend/packages/data-portal/app/components/NoFilteredResults.tsx @@ -1,4 +1,9 @@ -import { ReactNode } from 'react' +import { Button } from '@czi-sds/components' +import { useSetAtom } from 'jotai' + +import { useFilter } from 'app/hooks/useFilter' +import { useI18n } from 'app/hooks/useI18n' +import { searchQueryAtom } from 'app/state/search' function NoResultsImage() { return ( @@ -20,25 +25,44 @@ function NoResultsImage() { } export function NoFilteredResults({ - actions, - description, - title, + showSearchTip, }: { - actions?: ReactNode - description: string - title: string + showSearchTip?: boolean }) { + const setSearchQuery = useSetAtom(searchQueryAtom) + const { reset } = useFilter() + const { t } = useI18n() + return (
-
+

- {title} + {t('noResultsFound')}

-

{description}

+
+

{t('noResultsBeforeYouTryAgain')}

+ +
    + {showSearchTip &&
  • {t('noResultsSearch')}
  • } +
  • {t('noResultsCorrectSpelling')}
  • +
  • {t('noResultsRemoveFilters')}
  • +
+
-
{actions}
+
+ +
diff --git a/frontend/packages/data-portal/app/components/TablePageLayout.tsx b/frontend/packages/data-portal/app/components/TablePageLayout.tsx index 7588d5c94..e06155556 100644 --- a/frontend/packages/data-portal/app/components/TablePageLayout.tsx +++ b/frontend/packages/data-portal/app/components/TablePageLayout.tsx @@ -225,7 +225,9 @@ function TablePageTabContent({
- {filteredCount === 0 && noFilteredResults} + {filteredCount === 0 && ( +
{noFilteredResults}
+ )} {filteredCount > MAX_PER_PAGE && (
`${count} of ${max} ${type}`, - filterNoResultsFound: 'No results were found', filterRange: 'Filter Range', filterTooRestrictive: 'The applied filters may be too restrictive.', frames: 'Frames', diff --git a/frontend/packages/data-portal/app/routes/browse-data.datasets.tsx b/frontend/packages/data-portal/app/routes/browse-data.datasets.tsx index 4804b8b18..5eb497067 100644 --- a/frontend/packages/data-portal/app/routes/browse-data.datasets.tsx +++ b/frontend/packages/data-portal/app/routes/browse-data.datasets.tsx @@ -1,4 +1,4 @@ -import { Button, CellHeaderDirection } from '@czi-sds/components' +import { CellHeaderDirection } from '@czi-sds/components' import { json, LoaderFunctionArgs } from '@remix-run/node' import { Order_By } from 'app/__generated__/graphql' @@ -12,7 +12,6 @@ import { QueryParams } from 'app/constants/query' import { getBrowseDatasets } from 'app/graphql/getBrowseDatasets.server' import { getDatasetsFilterData } from 'app/graphql/getDatasetsFilterData.server' import { useDatasets } from 'app/hooks/useDatasets' -import { useFilter } from 'app/hooks/useFilter' import { useI18n } from 'app/hooks/useI18n' import { useBrowseDatasetFilterHistory, @@ -52,7 +51,6 @@ export async function loader({ request }: LoaderFunctionArgs) { export default function BrowseDatasetsPage() { const { datasetCount, filteredDatasetCount } = useDatasets() - const { reset } = useFilter() const { t } = useI18n() const { setPreviousBrowseDatasetParams } = useBrowseDatasetFilterHistory() @@ -72,13 +70,7 @@ export default function BrowseDatasetsPage() { 'https://chanzuckerberg.github.io/cryoet-data-portal/cryoet_data_portal_docsite_data.html#datasets', filterPanel: , table: , - noFilteredResults: ( - {t('clearFilters')}} - /> - ), + noFilteredResults: , filteredCount: filteredDatasetCount, totalCount: datasetCount, countLabel: t('datasets'), diff --git a/frontend/packages/data-portal/app/routes/browse-data.depositions.tsx b/frontend/packages/data-portal/app/routes/browse-data.depositions.tsx index c91699a3d..34406d9d6 100644 --- a/frontend/packages/data-portal/app/routes/browse-data.depositions.tsx +++ b/frontend/packages/data-portal/app/routes/browse-data.depositions.tsx @@ -1,15 +1,13 @@ -import { Button, CellHeaderDirection } from '@czi-sds/components' +import { CellHeaderDirection } from '@czi-sds/components' import { json, LoaderFunctionArgs, redirect } from '@remix-run/node' import { Order_By } from 'app/__generated__/graphql' import { apolloClient } from 'app/apollo.server' import { DepositionTable } from 'app/components/BrowseData/DepositionTable' -import { NoFilteredResults } from 'app/components/NoFilteredResults' import { TablePageLayout } from 'app/components/TablePageLayout' import { QueryParams } from 'app/constants/query' import { getBrowseDepositions } from 'app/graphql/getBrowseDepositions.server' import { useDepositions } from 'app/hooks/useDepositions' -import { useFilter } from 'app/hooks/useFilter' import { useI18n } from 'app/hooks/useI18n' import { getFeatureFlag } from 'app/utils/featureFlags' @@ -51,7 +49,6 @@ export async function loader({ request }: LoaderFunctionArgs) { export default function BrowseDepositionsPage() { const { depositionCount, filteredDepositionCount } = useDepositions() - const { reset } = useFilter() const { t } = useI18n() return ( @@ -63,13 +60,6 @@ export default function BrowseDepositionsPage() { learnMoreLink: 'https://chanzuckerberg.github.io/cryoet-data-portal/cryoet_data_portal_docsite_data.html#depositions', table: , - noFilteredResults: ( - {t('clearFilters')}} - /> - ), filteredCount: filteredDepositionCount, totalCount: depositionCount, countLabel: t('depositions'), diff --git a/frontend/packages/data-portal/app/routes/datasets.$id.tsx b/frontend/packages/data-portal/app/routes/datasets.$id.tsx index 9b393133a..51c44f8cb 100644 --- a/frontend/packages/data-portal/app/routes/datasets.$id.tsx +++ b/frontend/packages/data-portal/app/routes/datasets.$id.tsx @@ -8,6 +8,7 @@ import { DatasetHeader } from 'app/components/Dataset/DatasetHeader' import { RunsTable } from 'app/components/Dataset/RunsTable' import { DepositionFilterBanner } from 'app/components/DepositionFilterBanner' import { DownloadModal } from 'app/components/Download' +import { NoFilteredResults } from 'app/components/NoFilteredResults' import { RunFilter } from 'app/components/RunFilter' import { TablePageLayout } from 'app/components/TablePageLayout' import { RUN_FILTERS } from 'app/constants/filterQueryParams' @@ -86,6 +87,7 @@ export default function DatasetByIdPage() { filteredCount: dataset.filtered_runs_count.aggregate?.count ?? 0, totalCount: dataset.runs_aggregate.aggregate?.count ?? 0, countLabel: i18n.runs, + noFilteredResults: , }, ]} downloadModal={ diff --git a/frontend/packages/data-portal/app/routes/depositions.$id.tsx b/frontend/packages/data-portal/app/routes/depositions.$id.tsx index 2ebebfcdf..695b7ba56 100644 --- a/frontend/packages/data-portal/app/routes/depositions.$id.tsx +++ b/frontend/packages/data-portal/app/routes/depositions.$id.tsx @@ -12,6 +12,7 @@ import { DatasetFilter } from 'app/components/DatasetFilter' import { DepositionMetadataDrawer } from 'app/components/Deposition' import { DatasetsTable } from 'app/components/Deposition/DatasetsTable' import { DepositionHeader } from 'app/components/Deposition/DepositionHeader' +import { NoFilteredResults } from 'app/components/NoFilteredResults' import { TablePageLayout } from 'app/components/TablePageLayout' import { DEPOSITION_FILTERS } from 'app/constants/filterQueryParams' import { QueryParams } from 'app/constants/query' @@ -164,6 +165,7 @@ export default function DepositionByIdPage() { filteredCount: filteredDatasetsCount, filterPanel: , countLabel: t('datasets'), + noFilteredResults: , }, ]} drawers={} diff --git a/frontend/packages/data-portal/app/routes/runs.$id.tsx b/frontend/packages/data-portal/app/routes/runs.$id.tsx index 9e388fc62..25638e7d5 100644 --- a/frontend/packages/data-portal/app/routes/runs.$id.tsx +++ b/frontend/packages/data-portal/app/routes/runs.$id.tsx @@ -10,6 +10,7 @@ import { apolloClient, apolloClientV2 } from 'app/apollo.server' import { AnnotationFilter } from 'app/components/AnnotationFilter/AnnotationFilter' import { DepositionFilterBanner } from 'app/components/DepositionFilterBanner' import { DownloadModal } from 'app/components/Download' +import { NoFilteredResults } from 'app/components/NoFilteredResults' import { NoTotalResults } from 'app/components/NoTotalResults' import { RunHeader } from 'app/components/Run' import { AnnotationDrawer } from 'app/components/Run/AnnotationDrawer' @@ -211,6 +212,7 @@ export default function RunByIdPage() { ]} /> ), + noFilteredResults: , }, ...(multipleTomogramsEnabled ? [ diff --git a/frontend/packages/data-portal/app/state/search.ts b/frontend/packages/data-portal/app/state/search.ts new file mode 100644 index 000000000..46a9b1f1e --- /dev/null +++ b/frontend/packages/data-portal/app/state/search.ts @@ -0,0 +1,3 @@ +import { atom } from 'jotai' + +export const searchQueryAtom = atom('') diff --git a/frontend/packages/data-portal/public/locales/en/translation.json b/frontend/packages/data-portal/public/locales/en/translation.json index cfe63831c..a37173be6 100644 --- a/frontend/packages/data-portal/public/locales/en/translation.json +++ b/frontend/packages/data-portal/public/locales/en/translation.json @@ -75,7 +75,6 @@ "cellLineOrStrainName": "Cell Line or Strain Name", "cellName": "Cell Name", "cellularComponent": "Cellular Component", - "clearFilters": "Clear Filters", "clickToDownloadViaBrowser": "Click to download via your browser", "close": "Close", "comingFall2024": "Coming in Fall 2024", @@ -173,7 +172,6 @@ "filterByDepositionId": "Filter by Deposition ID", "filterByObjectId": "Filter by Object ID", "filterCountOfMaxType": "{{count}} of {{max}} {{type}}", - "filterNoResultsFound": "No results were found", "filterRange": "Filter Range", "filterTooRestrictive": "The applied filters may be too restrictive.", "frames": "Frames", @@ -248,6 +246,11 @@ "no": "No", "noAnnotationsAvailable": "No Annotations Available", "noAnnotationsAvailableToDownload": "No annotations available to download", + "noResultsBeforeYouTryAgain": "Before you try again, here are some tips:", + "noResultsCorrectSpelling": "Ensure your spelling is correct.", + "noResultsFound": "No results found", + "noResultsRemoveFilters": "Consider removing or adjusting filters for broader results.", + "noResultsSearch": "Search only looks for words in dataset names.", "noTomogramAvailable": "No tomogram available", "noTomogramsAvailable": "No tomograms available", "noTomogramsAvailableToDownload": "No tomograms available to download", @@ -318,6 +321,7 @@ "relatedEmpiarEntry": "Related EMPIAR Entry", "releaseDate": "Release Date", "reportIssueOnGithub": "Report Issue on GitHub", + "resetAll": "Reset All", "resolutionsAvailable": "Samplings Available", "resultsMustIncludeAllFileTypes": "Results must include all selected file types", "returnToDeposition": "Return To Deposition",