From aaf189abd1a9895017d1d205b87a36b2c7ac5942 Mon Sep 17 00:00:00 2001 From: Michael Franklin <22381693+illusional@users.noreply.github.com> Date: Tue, 31 Oct 2023 15:20:20 +1100 Subject: [PATCH] Improve stability of search (#594) Co-authored-by: Michael Franklin --- api/routes/web.py | 13 ++++++++--- web/src/shared/components/Header/Search.tsx | 26 +++++++++++++-------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/api/routes/web.py b/api/routes/web.py index d07ffc2ec..38255514b 100644 --- a/api/routes/web.py +++ b/api/routes/web.py @@ -81,11 +81,18 @@ async def search_by_keyword(keyword: str, connection=get_projectless_db_connecti projects = await pt.get_projects_accessible_by_user( connection.author, readonly=True ) - project_ids = [p.id for p in projects] - responses = await SearchLayer(connection).search(keyword, project_ids=project_ids) + pmap = {p.id: p for p in projects} + responses = await SearchLayer(connection).search( + keyword, project_ids=list(pmap.keys()) + ) for res in responses: - res.data.project = projects.get(res.data.project, res.data.project) # type: ignore + if res.data.project in pmap: + # the solution to the type issue is to create internal / external models + # and convert between them for transport + res.data.project = pmap[res.data.project].name # type: ignore + else: + res.data.project = str(res.data.project) return SearchResponseModel(responses=responses) diff --git a/web/src/shared/components/Header/Search.tsx b/web/src/shared/components/Header/Search.tsx index e8fa09ab0..a481ca0f3 100644 --- a/web/src/shared/components/Header/Search.tsx +++ b/web/src/shared/components/Header/Search.tsx @@ -72,12 +72,15 @@ const SearchReducer = (state: State, action: Action): State => { } } -const resultRenderer = ({ ...props }) => { +const resultRenderer = ({ data, ...props }) => { let components = [] let icon: React.ReactElement = <> let available: string | undefined let colour = 'black' - if (!props.data.id) { + if (!data) { + return An error occurred when rendering search results + } + if (!data?.id) { available = `No access to this ${props.type}` colour = 'gray' } @@ -89,27 +92,27 @@ const resultRenderer = ({ ...props }) => { switch (props.type) { case SearchResponseType.Sample: { - components.push(...(props.data.sample_external_ids || [])) + components.push(...(data.sample_external_ids || [])) icon = break } case SearchResponseType.Participant: { - components.push(...(props.data.participant_external_ids || [])) + components.push(...(data.participant_external_ids || [])) icon = break } case SearchResponseType.Family: { - components.push(...(props.data.family_external_ids || [])) + components.push(...(data.family_external_ids || [])) icon = break } case SearchResponseType.SequencingGroup: { - components.push(...(props.data.sample_external_ids || [])) + components.push(...(data.sample_external_ids || [])) icon = break } case SearchResponseType.Error: { - components.push(props.data.error) + components.push(data?.error) icon = break } @@ -120,7 +123,7 @@ const resultRenderer = ({ ...props }) => { const subtitle = components.length > 0 ? components.join(' ยท ') : null - const key = String(props.data.id || `${props.data.project}|${props.data.title}`) + const key = String(data.id || `${data.project}|${data.title}`) // prefer early return for empty results if (!props.title || !props.type) return <> @@ -148,7 +151,7 @@ const resultRenderer = ({ ...props }) => { fontStyle: 'italic', }} > - {props.data.project} + {data.project} @@ -227,7 +230,10 @@ const Searchbar: React.FunctionComponent = () => { { title: 'Error', type: 'error', - error: { error: er.message }, + data: { + id: '#error', + error: er.response?.data?.description || er.message, + }, }, ] as SearchResponse[], query: '',