Skip to content
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

Update bitwarden extension #17153

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Conversation

marinsokol
Copy link
Contributor

@marinsokol marinsokol commented Feb 18, 2025

Description

This MR introduces options to search vault using username or url.

By default, search using username or url is disabled. To enable, options need to be activated in Search Vault command preferences.

Inspired by issues 16419 and 16965

Screencast

Checklist

- minor improvement
- update changelog
- update changelog
- add options to search by url or username
- Initial commit
@raycastbot raycastbot added extension fix / improvement Label for PRs with extension's fix improvements extension: bitwarden Issues related to the bitwarden extension labels Feb 18, 2025
@raycastbot
Copy link
Collaborator

raycastbot commented Feb 18, 2025

Thank you for your contribution! 🎉

🔔 @jomifepe @daniel-stoneuk @andreaselia @pernielsentikaer @eth-p @YamenSharaf @undefinedzack @anirudhganwal06 @ivaarsson @gasparhabif you might want to have a look.

You can use this guide to learn how to check out the Pull Request locally in order to test it.

Due to our current reduced availability, the initial review may take up to 10-15 business days

@jomifepe
Copy link
Contributor

jomifepe commented Feb 20, 2025

Hey! Thanks for contributing, but isn't this already implemented? The username and URL are added to the search keywords. Is it not working for you?

@marinsokol
Copy link
Contributor Author

sorry, i did not notice that username is working, but url is not working for me.

@jomifepe
Copy link
Contributor

sorry, i did not notice that username is working, but url is not working for me.

I just saw that the built-in List search is limited, and is not capable of fully fuzzy searching whole keywords, so this contribution is indeed needed.

Copy link
Contributor

@jomifepe jomifepe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for contributing, this is a good addition 🚀

I left some suggestions, tell me what you think!

Comment on lines 5 to 26
export const useVaultWithSearch = () => {
const { items, folders, isLoading, isEmpty } = useVaultContext();
const [searchText, setSearchText] = useState("");
const { shouldSearchUsername, shouldSearchUrl } = getPreferenceValues();

const searchedItems = useMemo(() => {
const searchTxt = searchText.toLowerCase().trim();
return searchTxt
? items.filter((item) => {
const matchesName = item.name.toLowerCase().includes(searchTxt);
const matchesUsername =
shouldSearchUsername && item.login?.username ? item.login.username.includes(searchTxt) : false;
const urls = shouldSearchUrl && item.login?.uris ? item.login.uris.map((uri) => uri.uri)?.join(" ") : null;
const matchesUrl = shouldSearchUrl && urls?.length ? urls.includes(searchTxt) : false;

return matchesName || matchesUsername || matchesUrl;
})
: items;
}, [items, searchText, shouldSearchUsername, shouldSearchUrl]);

return { items: searchedItems, folders, isLoading, isEmpty, setSearchText };
};
Copy link
Contributor

@jomifepe jomifepe Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Personally, I would not move the vault context here, and only use the hook for the search/filtering logic. This also replaces the extractKeywords function, so it can live in that file and reuse part of its logic.

Something like this:

// utils/search.ts

function hasValue(value: string | null | undefined): value is string {
  return !!(value && value !== SENSITIVE_VALUE_PLACEHOLDER);
}

function searchItems(items: Item[], searchText: string): Item[] {
  const searchTextLower = searchText.toLowerCase().trim();
  if (!searchTextLower) return items;

  return items.filter((item) => {
    const searchableProps = new Set([item.name, ITEM_TYPE_TO_LABEL[item.type]]);
    switch (item.type) {
      case ItemType.LOGIN: {
        const { username, uris } = item.login ?? {};
        if (hasValue(username)) searchableProps.add(username);
        if (uris?.length) uris.forEach(({ uri }) => hasValue(uri) && searchableProps.add(uri));
        break;
      }
      case ItemType.CARD: {
        const { brand, number } = item.card ?? {};
        if (hasValue(brand)) searchableProps.add(brand);
        if (hasValue(number)) searchableProps.add(number);
        break;
      }
    }

    return Array.from(searchableProps).some((p) => p.toLowerCase().includes(searchTextLower));
  });
}

export function useVaultSearch(items: Item[]) {
  const [searchText, setSearchText] = useState("");
  const filteredItems = useMemo(() => searchItems(items, searchText), [items, searchText]);
  return { setSearchText, filteredItems };
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, this makes sense. Will update MR

Comment on lines 82 to 99
{
"name": "shouldSearchUsername",
"type": "checkbox",
"required": false,
"default": false,
"title": "Include username when searching",
"label": "Search by Username",
"description": "By default search uses only title, this will also include username."
},
{
"name": "shouldSearchUrl",
"type": "checkbox",
"required": false,
"default": false,
"title": "Include url when searching",
"label": "Search by URL",
"description": "By default search uses only title, this will also include url."
},
Copy link
Contributor

@jomifepe jomifepe Feb 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 I saw that this was mentioned in one of the issue, but personally I don't think we need to have an option for this, it could simply be the default behavior. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was thinking about this. I added this as a safety barrier, so users do not get more results unexpectedly. I am more for removing it. If you agree, lets simplify this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah let's keep it simple for now.

@pernielsentikaer pernielsentikaer self-assigned this Feb 21, 2025
@pernielsentikaer
Copy link
Collaborator

Testing a AI review bot too, let's see what it says

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Summary

Added search functionality to the Bitwarden extension, allowing users to search vault items by username and URL in addition to the default title search.

  • Added new useVaultWithSearch hook in /extensions/bitwarden/src/context/search.tsx implementing case-insensitive search across name, username, and URL fields
  • Added two new preferences in package.json for enabling username and URL search (disabled by default)
  • Updated CHANGELOG.md with new feature entry using {PR_MERGE_DATE} placeholder
  • Added new contributor 'marinsokol' to package.json

💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!

4 file(s) reviewed, 4 comment(s)
Edit PR Review Bot Settings | Greptile

@LitoMore
Copy link
Contributor

You can consider using https://npmjs.com/fast-fuzzy for a better search experience.

@marinsokol
Copy link
Contributor Author

You can consider using https://npmjs.com/fast-fuzzy for a better search experience.

good idea, thanks. I updated MR with all suggestions and it is ready for next review.

@pernielsentikaer
Copy link
Collaborator

@LitoMore does this work as you proprosed now?

Is this ready for a final review @marinsokol

@LitoMore
Copy link
Contributor

Hi @marinsokol, here is a simpler code of fast-fuzzy for you:

https://github.com/LitoMore/simple-icons-figma/blob/f710a5f1d1ecf30fefde51c20187dd47c3a0053f/source/components/icons.tsx#L26-L39

You only need the Searcher to create a search instance. You can also use a useMemo to improve its performance:

import useMemo from 'react';
import {Searcher} from 'fast-fuzzy';

const searcher = useMemo(new Searcher(icons, {
	keySelector(icon) {
		return [
			icon.title,
			icon.description,
			icon.fooIsArrayOfString,
			icon.moreContentsForSearching,
		]
			.flat()
			.filter(Boolean) as string[];
	},
}), [icons]);

const searchResult = searchString ? searcher.search(searchString) : icons;

But it's fine to keep your current implementation. That's up to you.

@marinsokol
Copy link
Contributor Author

Hi @marinsokol, here is a simpler code of fast-fuzzy for you:

https://github.com/LitoMore/simple-icons-figma/blob/f710a5f1d1ecf30fefde51c20187dd47c3a0053f/source/components/icons.tsx#L26-L39

You only need the Searcher to create a search instance. You can also use a useMemo to improve its performance:

import useMemo from 'react';
import {Searcher} from 'fast-fuzzy';

const searcher = useMemo(new Searcher(icons, {
	keySelector(icon) {
		return [
			icon.title,
			icon.description,
			icon.fooIsArrayOfString,
			icon.moreContentsForSearching,
		]
			.flat()
			.filter(Boolean) as string[];
	},
}), [icons]);

const searchResult = searchString ? searcher.search(searchString) : icons;

But it's fine to keep your current implementation. That's up to you.

good idea, code looks much cleaner now that i updated MR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension: bitwarden Issues related to the bitwarden extension extension fix / improvement Label for PRs with extension's fix improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants