-
-
Notifications
You must be signed in to change notification settings - Fork 832
feat: #1541 adding search history #1627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: #1541 adding search history #1627
Conversation
(nit) @lexafaxine sorry, can you update your description to something like
so that this PR is autolinked to the issue? ^^ |
@@ -0,0 +1,60 @@ | |||
import React from "react"; |
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.
import React from "react"; |
not necessary
))} | ||
</CommandGroup> | ||
</CommandList> | ||
</Command> |
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.
suggestion(ux): might be unrelated to this feature specifically, but I think there is a ux improvement that can be done
- after firing the search query upon typing, we should dismiss the "Command" dialog
2. or otherwise at least it should not show "No matching recent searches" - we can also maybe consider to dismiss the dialog if the user press "enter" button
3. seems like an intuitive thing to do, seeing that the dialog doesn't go away
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.
Hi @xuatz Thank u for the suggestions! They are really good points. You're right that showing "no results" when there is no result is not necessary in this situation. And regarding the close of the popover, I am considering UX like this:
- When there are search history that match user's typing, show the history. Close popover if there is no match.
- After user select one history item the popover will close. (Current behavior)
- No matter if there is matched history, close the popover if user press Enter, and in the same time blur the input and save the term to history.
Let me know if this sounds OK to you :)
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.
yeah sounds good to me 👍
setIsPopoverOpen(false); | ||
inputRef.current?.blur(); | ||
} | ||
}; |
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.
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.
Thank you for the suggestion! U r right so I tried changing to use the CommandInput which already has good UX out of box :) Therefore I requested a review again, please help review when available! Thanks🙏
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 ux is feeling great 💪
<CommandEmpty>No matching recent searches.</CommandEmpty> | ||
<CommandGroup heading="Recent Searches"> |
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.
I think these texts should be... what do you call this... t("label")
'ed? lol
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.
i18n added ^^
b33cdb0
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.
LGTM, but I didn't test mobile tho ^^
inputRef.current?.blur(); | ||
}; | ||
|
||
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { |
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.
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { | |
const handleKeyDown = (e: KeyboardEvent<HTMLInputElement>) => { |
just nitpicks ^^
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.
I guess cmdk has a restriction on keyboard event's type, if only using KeyboardEvent there will be type error :(
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.
LGTMv2 👍
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.
I tired it and it feels great! Left a bunch of comments.
@@ -45,7 +45,7 @@ export function useDoBookmarkSearch() { | |||
} | |||
const id = setTimeout(() => { | |||
doSearch(val); | |||
}, 10); | |||
}, 200); |
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.
Any reason why we increased the debounce? It makes the search feels slower. If we're adding the value onBlur, then the debounce value probably doesn't make a difference?
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.
You're right, that change left because I tried to save search during user's typing, reverted already in 6f83a20
apps/web/lib/searchHistory.tsx
Outdated
|
||
export function getSearchHistory(): string[] { | ||
try { | ||
const rawHistory = localStorage.getItem(BOOKMARK_SEARCH_HISTORY_KEY); |
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.
If we're keeping stuff in the user's localstorage, we'll probably need to clean it up otherwise it will leak between accounts on the same device. Which makes me wonder if it might be a good idea to store it in the database instead? If we're storing them in the database, they'll get synced across device, and it'll allow you to use mostly the same logic between the mobile and web app.
We don't need to address the localstorage idea in this PR, but if you agree, we can followup on it with a separate PR.
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.
Yeah I thought about it these days, and I think it's a good idea to implement it in database so we have sync across device and prevent leak across accounts on same device. And I also realized actually there are a lot of apps are doing something like this XD.
I would like to implement it as a separate PR as improvement :) Thank you for the idea!
apps/web/lib/searchHistory.tsx
Outdated
const parsed = JSON.parse(rawHistory) as string[]; | ||
if ( | ||
Array.isArray(parsed) && | ||
parsed.every((item) => typeof item === "string") | ||
) { | ||
return parsed; | ||
} |
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.
Might be clear to use a simple zod schema here instead?
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.
True, fixed in 6f83a20
apps/web/lib/searchHistory.tsx
Outdated
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 logic in this file seems exactly the same as the one in the mobile version (except for the storage utilities). It seems to me that we can move the hooks to the shared-react
package and pass in the getter and setter as inputs to the hook? This will allow you to share most of the code?
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.
moved in 4e214bf
apps/web/lib/searchHistory.tsx
Outdated
@@ -0,0 +1,37 @@ | |||
const BOOKMARK_SEARCH_HISTORY_KEY = "karakeep_search_history"; | |||
const MAX_HISTORY_ITEMS = 5; |
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.
How about we store something like 50, but by default render last 5 and only show the others as the user types?
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.
changed in 4e214bf
|
||
const handleCommandKeyDown = useCallback( | ||
(e: React.KeyboardEvent) => { | ||
if (e.key === "Enter") { |
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.
Something is wrong with the key down handler. Pressing enter correctly goes to the selected item when the search history first show up. But if you attempt to use Enter
on any filtered result, it doesn't work.
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.
good catch! there was actually some issue there 🙇 fixed in b5e0acf
@lexafaxine This is such a great addition, thanks a lot for all the effort you put in this PR and addressing all of our comments. Sorry it took long to merge! |
closes #1541
Changes
Add search history for web
Use local storage to store last 5 search history,
The popover showing search history will appear when input is focused.
According to the current search query implementation, history will only be saved to local storage after the input is blur, to prevent unintended saving.
Add search history for mobile
Use react-native async-storage to store last 5 search history,
Because we are showing user search history now in the search screen, user need to hit return to submit a search.
(Please refer to the demo video)
Demo video
web:
https://drive.google.com/file/d/1VCfapgyx8nqwxw7JajyC8HlXiJYvjNR7/view?usp=sharinghttps://drive.google.com/file/d/1sNfqTqymk3r3Mhbd9mvdOwWNMYvjobzK/view?usp=sharing
mobile: https://drive.google.com/file/d/1b5Xj5ekeFxb6IrzoWVUmZpMLWBHpCnBk/view?usp=sharing