This repository was archived by the owner on Feb 26, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9
Re introduce fulltext search #1523
Merged
bilalesi
merged 11 commits into
migration-merge
from
feature/4723-re-introduce-fulltext-search
May 28, 2024
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
b4c435c
update: add react-cmdk package
79f19f5
fix: invoke resource api only when the user is ready
2b3b4da
update: add fulltext search buttin to the header
5d6848f
update: add fulltext search component
04b4904
update: remove sort when use search query in resources listing
2b6f8dc
Remove unused import
danburonline 671dcb6
Download archive as zip instead of tar in resource container
Dinika 81b08de
update: code editor in dashboard config
1e09929
update: fix auto scroll on delete search string
6fb414a
update: refactor useFullTextSearch hook
564267e
update: fix dark mode for cmdk
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import { useEffect } from 'react'; | ||
import { Link } from 'react-router-dom'; | ||
import CommandPalette from 'react-cmdk'; | ||
import { Spin, Tag, Empty } from 'antd'; | ||
import { LoadingOutlined } from '@ant-design/icons'; | ||
|
||
import { getNormalizedTypes, getResourceLabel } from 'shared/utils'; | ||
import { useFullTextSearch } from './useFullTextSearch'; | ||
|
||
import 'react-cmdk/dist/cmdk.css'; | ||
import './styles.scss'; | ||
|
||
type Props = { | ||
openCmdk: boolean; | ||
onOpenCmdk(): void; | ||
}; | ||
|
||
const TagRenderer = ({ type }: { type?: string | string[] }) => { | ||
if (!type) return null; | ||
const types = getNormalizedTypes(type); | ||
return ( | ||
<div className="type-tags-list"> | ||
{types.map(t => ( | ||
<Tag color="blue" className="tag" title={t}> | ||
{t} | ||
</Tag> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
const FullTextSearch = ({ openCmdk, onOpenCmdk }: Props) => { | ||
const { | ||
search, | ||
onSearch, | ||
resetSearch, | ||
searchResults, | ||
isLoading, | ||
} = useFullTextSearch(); | ||
|
||
const onChangeOpen = () => { | ||
onOpenCmdk(); | ||
resetSearch(); | ||
}; | ||
|
||
let content = null; | ||
|
||
if (isLoading) { | ||
content = ( | ||
<div className="search-resources-loader"> | ||
<Spin size="large" indicator={<LoadingOutlined />} /> | ||
</div> | ||
); | ||
} else if (!Boolean(searchResults.length) && !Boolean(search)) { | ||
content = <div className="search-for-placeholder">Search for ""</div>; | ||
} else if (!Boolean(searchResults.length) && Boolean(search)) { | ||
content = <Empty description="No results found" />; | ||
} else { | ||
content = searchResults.map(({ id, title, items }) => ( | ||
<div className="cmdk-list-container" key={id}> | ||
<div className="cmdk-list-title"> | ||
<Tag color="geekblue">{title?.orgLabel}</Tag>| | ||
<Tag color="geekblue">{title?.projectLabel}</Tag> | ||
</div> | ||
<div className="cmdk-list-content"> | ||
{items.map(resource => { | ||
const label = getResourceLabel(resource); | ||
return ( | ||
<Link | ||
to={`/resolve/${encodeURIComponent(resource['@id'])}`} | ||
onClick={onOpenCmdk} | ||
className="cmdk-list-item" | ||
> | ||
<div className="item-title">{label}</div> | ||
<TagRenderer type={resource['@type']} /> | ||
</Link> | ||
); | ||
})} | ||
</div> | ||
</div> | ||
)); | ||
} | ||
|
||
useEffect(() => { | ||
const keyDown = (e: KeyboardEvent) => { | ||
if (e.ctrlKey && e.key === 'e') { | ||
e.preventDefault(); | ||
e.stopPropagation(); | ||
onOpenCmdk(); | ||
} | ||
}; | ||
|
||
document.addEventListener('keydown', keyDown); | ||
return () => document.removeEventListener('keydown', keyDown); | ||
}, []); | ||
|
||
return ( | ||
<CommandPalette | ||
onChangeSearch={onSearch} | ||
onChangeOpen={onChangeOpen} | ||
search={search} | ||
isOpen={openCmdk} | ||
page="root" | ||
placeholder="Search for resources" | ||
> | ||
{content} | ||
</CommandPalette> | ||
); | ||
}; | ||
|
||
export default FullTextSearch; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
@import '../../lib.scss'; | ||
|
||
.cmdk-list-container { | ||
padding: 10px; | ||
margin-top: 0 !important; | ||
} | ||
.cmdk-list-title { | ||
text-transform: uppercase !important; | ||
font-weight: bold !important; | ||
margin-bottom: 10px !important; | ||
color: $fusion-daybreak-7; | ||
display: flex; | ||
align-items: center; | ||
gap: 5px; | ||
|
||
.ant-tag { | ||
padding: 2px 4px; | ||
} | ||
} | ||
|
||
.cmdk-list-content { | ||
display: flex; | ||
flex-direction: column; | ||
gap: 3px; | ||
} | ||
|
||
.cmdk-list-item { | ||
padding: 10px 8px; | ||
margin-left: 5px; | ||
border-radius: 4px; | ||
font-size: 16px; | ||
color: #333; | ||
border: 1px solid #efefef; | ||
|
||
&:hover { | ||
background: $fusion-blue-1 !important; | ||
box-shadow: 0 2px 12px 0px rgba($color: #333, $alpha: 0.14); | ||
} | ||
} | ||
|
||
.type-tags-list { | ||
display: flex; | ||
align-items: center; | ||
justify-content: flex-start; | ||
gap: 3px; | ||
margin: 4px 0px; | ||
.tag { | ||
padding: 2px 3px; | ||
} | ||
} | ||
|
||
.item-creation_date { | ||
font-size: 12px; | ||
} | ||
|
||
.search-resources-loader { | ||
width: 100%; | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
padding-top: 10px; | ||
padding-bottom: 10px; | ||
} | ||
|
||
.search-for-placeholder { | ||
background-color: $fusion-neutral-2; | ||
padding: 10px; | ||
color: #333; | ||
user-select: none; | ||
border-radius: 4px; | ||
} | ||
|
||
@media (prefers-color-scheme: dark) { | ||
.cmdk-list-item { | ||
background: white; | ||
color: black; | ||
|
||
&:hover { | ||
background: #efefef !important; | ||
box-shadow: 0 2px 12px 0px rgba($color: white, $alpha: 0.14); | ||
color: black; | ||
.item-title { | ||
color: #333; | ||
} | ||
} | ||
} | ||
|
||
.search-for-placeholder { | ||
background-color: white; | ||
color: #101827; | ||
} | ||
|
||
.ant-empty { | ||
.ant-empty-description { | ||
color: white; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { useState } from 'react'; | ||
import { useNexusContext } from '@bbp/react-nexus'; | ||
import { useQuery } from 'react-query'; | ||
import { getOrgAndProjectFromProjectId } from 'shared/utils'; | ||
import { groupBy } from 'lodash'; | ||
|
||
export function useFullTextSearch() { | ||
const [search, setSearch] = useState(''); | ||
const nexus = useNexusContext(); | ||
|
||
const onSearch = (value: string) => setSearch(value); | ||
const resetSearch = () => setSearch(''); | ||
|
||
const { isLoading, data } = useQuery({ | ||
enabled: !!search, | ||
queryKey: ['cmdk-search', { search }], | ||
queryFn: () => | ||
nexus.Resource.list(undefined, undefined, { | ||
q: search, | ||
deprecated: false, | ||
}), | ||
select: data => data._results, | ||
staleTime: 2, | ||
}); | ||
|
||
const resources = groupBy(data, '_project'); | ||
|
||
const searchResults = Object.entries(resources).map(([key, value]) => { | ||
const orgProject = getOrgAndProjectFromProjectId(key); | ||
return { | ||
id: key, | ||
title: orgProject, | ||
items: value, | ||
}; | ||
}); | ||
|
||
return { | ||
search, | ||
onSearch, | ||
resetSearch, | ||
isLoading, | ||
searchResults, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
staleTime
in milliseconds right? 2 milliseconds sounds too low to me. Did you mean 2000 ms instead?