Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Create search and search-ui packages #29773

Merged
merged 32 commits into from
Jan 20, 2022
Merged

Conversation

tjkandala
Copy link
Contributor

@tjkandala tjkandala commented Jan 14, 2022

Closes #29705.

Motivation

One goal of v1 of the new Sourcegraph VS Code extension is to provide a familiar experience for existing Sourcegraph users in their IDEs, which also makes the potential transition to using Sourcegraph.com easier for new users (acquired through the new VS Code extension). The easiest way to make that happen is to use the same components as the web application.

VSCE_Components 001

To that end, this PR introduces two new packages in order to share essential search code between client applications.

New Packages

  • search: General search types (e.g. QueryState. Can be used in any client context (e.g. web app, browser extension, CLIs).
  • search-ui: Search UI components that adhere to our branding. Can be used only in branded clients (e.g. web app, VS Code extension)

For reviewers

This PR is best reviewed by commit. I've done my best to make sure each commit is simple and that the code is in a working state. The overall diff is very misleading in terms of complexity; the vast majority of changes are updates to imports and stuff like making components accept PlatformContext in order to abstract GQL requests. The build is passing and search features check out in manual testing. However, we can split this into multiple PRs if that would increase confidence!

Changes

  • <SearchBox> (really all of web/src/search/input) to search-ui
    • Moves to to enable this:
      • CurrentAuthState query, export AuthenticatedUser type alias (does this belong in a separate auth package?)
      • web/src/keyboardShortcuts to shared/src/keyboardShortcuts
        • also needs isMacPlatform, lazyComponent, and observeResize from web/src/util to be moved to shared/src/util
      • web/src/search/useQueryIntelligence to search/src/useQueryIntelligence. This only depends on stuff already in shared (moving to search)
      • <MonacoEditor> from web/src/components to shared/src/components. This only depends on stuff already in shared (moving to search)
      • web/src/search/helpers.tsx to move to search, not search-ui
      • Settings schema type generation to move to shared (needed for quick links and <FilterLink>)
      • TemporarySettings to move to shared
      • Most of web/src/search/backend.tsx to search
      • SyntaxHighlightedSearchQuery to search-ui
  • <StreamingSearchResultsList> to search-ui. We could just move <StreamingSearchResults>, but that component is too intertwined with web stuff (e.g. code insights, search stack) so I think it makes more sense to pull out the list component and other shared components (like SearchAlert) and assemble an independent VSCE search results page. Additionally, <StreamingSearchResults> renders the search sidebar, whereas we want to render that in a VS Code sidebar webview.
    • Moves to enable this:
      • <ModalVideo> to search-ui
      • <ErrorAlert> to branded (maybe wildcard?)
      • <SearchResult> and <CommitSearchResultMatch> to search-ui
        • highlightCode from web/src/search/backend.tsx to search
      • Make web/src/user/settings/codeHosts/OrgUserNeedsCodeHost.tsx a render prop (depends on Apollo Client which will not be implemented for VSCE v1)
      • <NoResultsPage> to search-ui
        • Will have to pass in experimental features as prop instead of using useExperimentalFeatures (zustand store). Eventually we should think about how to more elegantly manage our zustand stores across clients
        • <AnnotatedSearchInput> to search-ui
  • <SearchSidebar> to search-ui as mentioned in the previous point.
    • Moves to to enable this:
      • This depends on the global useNavbarQueryState, so we should make a general SearchQueryState interface in search and pass the store instance as a prop.
      • <Revisions> sidebar section will stay in web until we get Apollo client working for VS Code webviews. Refactor <SearchSidebar> to accept getRevisions prop
      • <OnboardingTour> is web-only (for now?), so add a prefixContent prop for web consumers to render it into
      • Move client/web/src/search/helpers/queryExample.ts to search

Candidates for moves in future PRs

  • shared/src/search/query, shared/src/search/suggestions, and shared/src/search/stream.ts to search
    • move <FileMatch> to search-ui

@cla-bot cla-bot bot added the cla-signed label Jan 14, 2022
@tjkandala tjkandala force-pushed the tjk/create-search-packages branch 6 times, most recently from a109d42 to a9a92f2 Compare January 17, 2022 22:28
Comment on lines 8 to 9
// Implemented in /web as navbar query state, /vscode as webview query state.
export interface SearchQueryState {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is this? The interface for useNavbarQueryState store pulled out to be shared with the VS Code extension.

I implemented a separate zustand store (ignore the fact that it's instantiated in a component, it's a temporary hack :) ) in the VS Code prototype and it seems to work well!

@@ -0,0 +1,16 @@
export enum SectionID {
Copy link
Contributor Author

@tjkandala tjkandala Jan 17, 2022

Choose a reason for hiding this comment

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

Temporary settings must be defined here to prevent circular dependency (search-ui <-> shared). I tried some more flexible solutions, like making the temporary settings schema generic, but it didn't seem to worth the effort to makes the types work (and kind of defeats the purpose of autocomplete knowing about all the possible temporary settings keys)

@@ -224,7 +228,7 @@ export const SearchSidebar: React.FunctionComponent<SearchSidebarProps> = props

return (
<div className={classNames(styles.searchSidebar, props.className)}>
{props.showOnboardingTour && <OnboardingTour className="mb-1" telemetryService={props.telemetryService} />}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The onboarding tour doesn't make sense for VS Code yet, so SearchSidebar shouldn't depend on it

@@ -49,16 +52,18 @@ export interface SearchSidebarProps
* Content to render inside sidebar, but before other sections.
*/
prefixContent?: JSX.Element

buildSearchURLQueryFromQueryState: (queryParameters: BuildSearchQueryURLParameters) => string
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The current implementation references the zustand store directly, so it should be passed as a prop by each client

@tjkandala tjkandala requested review from a team, limitedmage, fkling and abeatrix January 17, 2022 22:35
@tjkandala tjkandala marked this pull request as ready for review January 17, 2022 22:48
@sourcegraph-bot
Copy link
Contributor

sourcegraph-bot commented Jan 17, 2022

Notifying subscribers in CODENOTIFY files for diff c7f9aea...2b6580f.

Notify File(s)
@courier-new client/web/src/enterprise/batches/close/BatchChangeCloseAlert.tsx
client/web/src/enterprise/batches/close/ExternalChangesetCloseNode.tsx
client/web/src/enterprise/batches/create/CreateBatchChangePage.tsx
client/web/src/enterprise/batches/create/CreateOrEditBatchChangePage.tsx
client/web/src/enterprise/batches/create/editor/MonacoBatchSpecEditor.tsx
client/web/src/enterprise/batches/create/useBatchSpecCode.ts
client/web/src/enterprise/batches/create/useNamespaces.ts
client/web/src/enterprise/batches/create/workspaces-preview/WorkspacesPreview.tsx
client/web/src/enterprise/batches/detail/BatchChangeDetailsActionSection.tsx
client/web/src/enterprise/batches/detail/BatchChangeDetailsPage.tsx
client/web/src/enterprise/batches/detail/bulk-operations/BulkOperationNode.tsx
client/web/src/enterprise/batches/detail/changesets/CloseChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/CreateCommentModal.tsx
client/web/src/enterprise/batches/detail/changesets/DetachChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/ExternalChangesetNode.tsx
client/web/src/enterprise/batches/detail/changesets/MergeChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/PublishChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/ReenqueueChangesetsModal.tsx
client/web/src/enterprise/batches/execution/BatchSpecExecutionDetailsPage.tsx
client/web/src/enterprise/batches/execution/WorkspaceDetails.tsx
client/web/src/enterprise/batches/global/GlobalBatchChangesArea.tsx
client/web/src/enterprise/batches/list/BatchChangeListPage.tsx
client/web/src/enterprise/batches/preview/CreateUpdateBatchChangeAlert.tsx
client/web/src/enterprise/batches/settings/AddCredentialModal.tsx
client/web/src/enterprise/batches/settings/RemoveCredentialModal.tsx
@efritz client/web/src/enterprise/codeintel/configuration/components/ConfigurationEditor.tsx
client/web/src/enterprise/codeintel/configuration/components/GitObjectPreview.tsx
client/web/src/enterprise/codeintel/configuration/components/RepositoryPreview.tsx
client/web/src/enterprise/codeintel/configuration/pages/CodeIntelConfigurationPolicyPage.tsx
client/web/src/enterprise/codeintel/indexes/components/EnqueueForm.tsx
client/web/src/enterprise/codeintel/indexes/pages/CodeIntelIndexPage.tsx
client/web/src/enterprise/codeintel/repo/RepositoryCodeIntelArea.tsx
client/web/src/enterprise/codeintel/shared/components/CodeIntelStateDescription.tsx
client/web/src/enterprise/codeintel/uploads/pages/CodeIntelUploadPage.tsx
@eseliger client/web/src/enterprise/batches/close/BatchChangeCloseAlert.tsx
client/web/src/enterprise/batches/close/ExternalChangesetCloseNode.tsx
client/web/src/enterprise/batches/create/CreateBatchChangePage.tsx
client/web/src/enterprise/batches/create/CreateOrEditBatchChangePage.tsx
client/web/src/enterprise/batches/create/editor/MonacoBatchSpecEditor.tsx
client/web/src/enterprise/batches/create/useBatchSpecCode.ts
client/web/src/enterprise/batches/create/useNamespaces.ts
client/web/src/enterprise/batches/create/workspaces-preview/WorkspacesPreview.tsx
client/web/src/enterprise/batches/detail/BatchChangeDetailsActionSection.tsx
client/web/src/enterprise/batches/detail/BatchChangeDetailsPage.tsx
client/web/src/enterprise/batches/detail/bulk-operations/BulkOperationNode.tsx
client/web/src/enterprise/batches/detail/changesets/CloseChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/CreateCommentModal.tsx
client/web/src/enterprise/batches/detail/changesets/DetachChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/ExternalChangesetNode.tsx
client/web/src/enterprise/batches/detail/changesets/MergeChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/PublishChangesetsModal.tsx
client/web/src/enterprise/batches/detail/changesets/ReenqueueChangesetsModal.tsx
client/web/src/enterprise/batches/execution/BatchSpecExecutionDetailsPage.tsx
client/web/src/enterprise/batches/execution/WorkspaceDetails.tsx
client/web/src/enterprise/batches/global/GlobalBatchChangesArea.tsx
client/web/src/enterprise/batches/list/BatchChangeListPage.tsx
client/web/src/enterprise/batches/preview/CreateUpdateBatchChangeAlert.tsx
client/web/src/enterprise/batches/settings/AddCredentialModal.tsx
client/web/src/enterprise/batches/settings/RemoveCredentialModal.tsx
@limitedmage client/web/src/enterprise/code-monitoring/CodeMonitorInfo.tsx
client/web/src/enterprise/code-monitoring/CodeMonitorList.tsx
client/web/src/enterprise/code-monitoring/CodeMonitoringPage.tsx
client/web/src/enterprise/code-monitoring/global/GlobalCodeMonitoringArea.tsx
client/web/src/integration/search.test.ts
client/web/src/search/QuickLinks.tsx
client/web/src/search/SearchConsolePage.tsx
client/web/src/search/SearchPageWrapper.tsx
client/web/src/search/SearchStack.tsx
client/web/src/search/backend.tsx
client/web/src/search/helpers.test.tsx
client/web/src/search/helpers.tsx
client/web/src/search/home/LoggedOutHomepage.tsx
client/web/src/search/home/SearchPage.tsx
client/web/src/search/home/SearchPageInput.tsx
client/web/src/search/index.tsx
client/web/src/search/input/SearchNavbarItem.tsx
client/web/src/search/input/SearchOnboardingTour.ts
client/web/src/search/notebook/NotebookContent.tsx
client/web/src/search/notebook/SearchNotebook.story.tsx
client/web/src/search/notebook/SearchNotebook.tsx
client/web/src/search/notebook/SearchNotebookMarkdownBlock.tsx
client/web/src/search/notebook/SearchNotebookPage.tsx
client/web/src/search/notebook/SearchNotebookQueryBlock.story.tsx
client/web/src/search/notebook/SearchNotebookQueryBlock.tsx
client/web/src/search/panels/RecentSearchesPanel.tsx
client/web/src/search/panels/RepositoriesPanel.tsx
client/web/src/search/results/DidYouMean.tsx
client/web/src/search/results/SearchResultsInfoBar.tsx
client/web/src/search/results/StreamingSearchResults.story.tsx
client/web/src/search/results/StreamingSearchResults.test.tsx
client/web/src/search/results/StreamingSearchResults.tsx
client/web/src/search/results/components/CreateCodeInsightButton.tsx
client/web/src/search/results/sidebar/Revisions.mocks.ts
client/web/src/search/results/sidebar/Revisions.story.tsx
client/web/src/search/results/sidebar/Revisions.test.tsx
client/web/src/search/results/sidebar/Revisions.tsx

@tjkandala tjkandala requested review from a team and novoselrok and removed request for abeatrix January 17, 2022 22:52
Comment on lines 39 to 44
/**
* Zustand store. Passed as a prop because there may be different global stores across clients
* (e.g. VS Code extension, web app), so the sidebar expects a store with the minimal interface
* for search.
*/
useQueryState: UseStore<SearchQueryState>
Copy link
Contributor

Choose a reason for hiding this comment

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

I'll need to do a more thorough review, but some quick initial thoughts:

Somehow passing a store/hook as prop feels weird to me. If possible, I feel like refactoring the component to accept whatever they get from the store as props, and introducing "container" components that then implement/provide this as necessary (e.g. one of the the extension and one for the web app) would be cleaner. But maybe I'm overthinking this.

Eventually we should think about how to more elegantly manage our zustand stores across clients

Contexts could help with that. We tried to use the zustand stores via context, but their type definition was difficult to get right. But alternatively we could pass the stores themselves via context (those references won't change anyway). This could also be combined with my previous statement. Curious what @sourcegraph/frontend-platform thinks.

Copy link
Member

Choose a reason for hiding this comment

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

@fkling, it seems we can benefit from using zustand stores via context. Is it possible that type definition issues are solved in the new version? Maybe, if it's a couple of hours of effort, it makes sense to fix them ourselves in the third party? It will make the usage via context easier to understand since it will follow zustand documentation.

In general, I agree that it would be great to avoid prop drilling and rely more on React context, especially for cross-package depedencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Somehow passing a store/hook as prop feels weird to me. If possible, I feel like refactoring the component to accept whatever they get from the store as props, and introducing "container" components that then implement/provide this as necessary (e.g. one of the the extension and one for the web app) would be cleaner. But maybe I'm overthinking this.

This is a good solution because the reason I didn't do it in the first place was that I un-creatively only considered the current parent as a candidate for lifting the zustand subscription to, which would be counterproductive performance-wise. I'll try the context approach first and fall back to the container approach if it takes too long. Thank you both!

Copy link
Contributor

@fkling fkling Jan 18, 2022

Choose a reason for hiding this comment

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

FWIW, I'm OK with having a less optimal solution now and then clean this up. While you can absolutely try context, I feel like this would be better in a separate PR.

And just to clarify what I and Valery meant (because we meant different things 😆 ): I thought that passing down the store functions (e.g. useNavbarQueryState) via context would be an OK compromise, but it does make it a bit awkward to use (don't actually know the context API off the top of my head but something along these lines:

const useNavbarQueryState = useContext(...)
const {state} = useNavbarQueryState(...)

which is not that common).

Zustand offers proper context support and the nice thing about it that you wouldn't even have to update the components that use the stores (afaik). I think you could get away with just updating the implementation of the stores.
However, there are couple of things to consider:

  • In the past we argued that having multiple contexts (one per store) isn't desirable. At the same time I think that merging everything into a single store isn't great either. A compromise could be that we have a single store for "individual" single global values (theme, isSourcegraphDotCom, etc) and a separate store for more complex state (search query state).
  • For search query state, I moved a lot of the "action" functions from the store the module level (example). I liked that because components didn't have to subscribe to the store just to get a value (the function) that never changes. But I don't think that would work with context anymore and they would have to be moved back to the store. I'm ok with that but it's additional work.

Not sure how we should best coordinate all that 😅

Copy link
Contributor Author

@tjkandala tjkandala Jan 18, 2022

Choose a reason for hiding this comment

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

I went off and basically implemented what seems to be Valery's proposal before I read this comment 😅. I can do it the zustand way, just wondering now that we have it, does it still feel worth moving to a separate PR? I thought this was a change with limited scope since only search package components would have to worry about this, but I see that it would open a can of worms with the multiple contexts issue...

For search query state, I moved a lot of the "action" functions from the store the module level (example). I liked that because components didn't have to subscribe to the store just to get a value (the function) that never changes. But I don't think that would work with context anymore and they would have to be moved back to the store. I'm ok with that but it's additional work.

These are used only in web since <SearchBox> takes these as props, which is helpful since it means <SearchSidebar> is the only shared (search) component that directly references the zustand store. So it's not a problem we have to tackle yet? I don't see it as an issue that web helpers reference the web store directly

Copy link
Contributor

Choose a reason for hiding this comment

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

I can do it the zustand way, just wondering now that we have it, does it still feel worth moving to a separate PR?

Yeah, probably not worth it to do in a separate PR. I thought it might be weird to have some stores use context and not others, but maybe we shouldn't be dogmatic about this and use whether makes sense for that specific situations.

I know I proposed this, but seeing the store passed via context is weird too 😆 But it's OK for me if you want to keep it that way for now. I can also migrate it the "zustand way" at some point. I also feel like we might need to have a proper discussion again how we want to tackle this overall, outside of this specific PR.

which is helpful since it means <SearchSidebar> is the only shared (search) component that directly references the zustand store

Ah... I somehow didn't realize which components are actually all affected by this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Got it, I opened an issue (#29984) to track this tech debt

@valerybugakov
Copy link
Member

@tjkandala, thank you for extracting it into a separate PR! 💜 I will look into it by the end of tomorrow.
In the meantime, I know @vovakulikov worked on refactoring of the SearchInput component, and part of this new implementation probably will be extracted into the wildcard package.

Vova, will this work create major merge conflicts? Does it make sense for you to sync with @tjkandala on it?

@fkling
Copy link
Contributor

fkling commented Jan 18, 2022

To make matters worse, I'm also working on a bigger refactor that adds quite a bit of code to the query state store: https://github.com/sourcegraph/sourcegraph/pull/29825 . We'll have to coordinate this somehow.

@vovakulikov
Copy link
Contributor

@tjkandala If you're interested in new Monaco field components, they still live in code insights shared components. You can find them here and live demo here

So there are no other places where it's used yet. But when I get time I'm gonna implement the rest of the needed UI for Monaco and reduce the number of abstractions over the Monaco input component. (at the moment we have at least 3 places where we use different implementations of Monaco - search page, notebook fields, code insights creation UI)

@tjkandala
Copy link
Contributor Author

@fkling At the risk of sounding naive, I don't think our PRs conflict too much conceptually? Would be a pretty big merge conflict though so coordination is important. I will have some PRs in the near future that would also ideally build off of yours (in the prototype I added lots of custom code for global search context state; your PR would make it a lot easier).

If we think this is mergable, how about this order:

  1. We merge this PR once approved
  2. We rebase your store refactor PR on top of main
  3. I can work on the VS Code extension based on your branch

@vovakulikov Looks great! So there won't likely be merge conflicts, right?

@tjkandala tjkandala force-pushed the tjk/create-search-packages branch from a5ade72 to bc49e0e Compare January 18, 2022 21:15
Copy link
Contributor

@limitedmage limitedmage left a comment

Choose a reason for hiding this comment

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

This looks like the right approach to me. Left some minor comments and will defer to @fkling re: state management, but otherwise LGTM!

@@ -0,0 +1 @@
export * from './SyntaxHighlightedSearchQuery'
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure this is related to search UI in particular. This is used in multiple places in the product, not just search UI. I think this component would live better in shared.

@@ -14,6 +14,7 @@ interface ModalVideoProps {
onToggle?: (isOpen: boolean) => void
showCaption?: boolean
className?: string
assetsRoot?: string
}

export const ModalVideo: React.FunctionComponent<ModalVideoProps> = ({
Copy link
Contributor

Choose a reason for hiding this comment

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

This component also seems to me more apt for shared than search-ui

@@ -1,7 +1,6 @@
import { Optional } from 'utility-types'

import { SectionID as NoResultsSectionID } from '../../search/results/NoResultsPage'
import { SectionID } from '../../search/results/sidebar/SearchSidebar'
import { SectionID, NoResultsSectionID } from './searchSidebar'
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if now that we'll have have temporary settings in shared if we could easily plug them into the browser and editor extensions for even better settings sync

client/search-ui/src/input/SearchContextCtaPrompt.tsx Outdated Show resolved Hide resolved
@vovakulikov
Copy link
Contributor

vovakulikov commented Jan 19, 2022

@tjkandala

So there won't likely be merge conflicts, right?

It's correct. We just need to take into account that there will be a new place where we store our existing search box Monaco abstraction/components (I mean a newly created search-ui package in this PR) if we start Monaco migration before this PR got merged but I suspect we will start doing something with Monaco later and after this PR is merged, so no conflicts

Copy link
Member

@valerybugakov valerybugakov left a comment

Choose a reason for hiding this comment

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

Looks great! Thank you for taking an iterative approach and instead of moving to the shared package, creating a couple of workspaces with clearer purpose 🙌

Agree with @limitedmage that some components are not specific only to the search UI, but we can iterate on it in follow-up PRs since we tearing the shared package apart anyways.

client/search-ui/src/input/MonacoQueryInput.tsx Outdated Show resolved Hide resolved
@@ -1,19 +1,18 @@
import classNames from 'classnames'
import React from 'react'

import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
Copy link
Member

Choose a reason for hiding this comment

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

Looks like a great candidate to be moved to the Wildcard package. We can work on it in a follow-up PR.

@tjkandala
Copy link
Contributor Author

Thanks @valerybugakov and @limitedmage! I'll address the issues regarding ideal place for certain files to live in follow-up PRs. I'll merge on approval on state management strategy (and coordinating PRs) from @fkling!

Copy link
Contributor

@fkling fkling left a comment

Choose a reason for hiding this comment

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

Yep, merge this PR and I'll rebase my PR 🙂

tjkandala and others added 25 commits January 20, 2022 12:42
SearchUserNeedsCodeHost depends on code (currently) unsupported on VS Code
(Apollo Client)
The web implementation of this function directly references the zustand store
Unblocks SearchSidebar move, along with some other import changes
Co-authored-by: Juliana Peña <juliana@sourcegraph.com>
@tjkandala tjkandala force-pushed the tjk/create-search-packages branch from fcf8f02 to 2b6580f Compare January 20, 2022 17:43
@tjkandala tjkandala merged commit 29ef1da into main Jan 20, 2022
@tjkandala tjkandala deleted the tjk/create-search-packages branch January 20, 2022 17:56
davejrt pushed a commit that referenced this pull request Jan 26, 2022
Co-authored-by: Juliana Peña <juliana@sourcegraph.com>
davejrt pushed a commit that referenced this pull request Feb 15, 2022
Co-authored-by: Juliana Peña <juliana@sourcegraph.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

VSCE: Create search and search UI packages
6 participants