-
-
- {}}
- patternType={SearchPatternType.regexp}
- setPatternType={() => {}}
- isSourcegraphDotCom={false}
- structuralSearchDisabled={false}
- queryState={{ query: 'type:file test AND test repo:contains.file(CHANGELOG)' }}
- onChange={() => {}}
- onSubmit={() => {}}
- authenticatedUser={null}
- searchContextsEnabled={true}
- showSearchContext={true}
- showSearchContextManagement={false}
- setSelectedSearchContextSpec={() => {}}
- selectedSearchContextSpec={undefined}
- fetchSearchContexts={() => {
- throw new Error('fetchSearchContexts')
- }}
- getUserSearchContextNamespaces={() => []}
- fetchStreamSuggestions={() => NEVER}
- settingsCascade={EMPTY_SETTINGS_CASCADE}
- globbing={false}
- isLightTheme={!isDarkTheme}
- telemetryService={NOOP_TELEMETRY_SERVICE}
- platformContext={{ requestGraphQL: () => EMPTY }}
- className=""
- containerClassName=""
- autoFocus={true}
- hideHelpButton={true}
- />
-
+
+
+
+ {}}
+ patternType={SearchPatternType.regexp}
+ setPatternType={() => {}}
+ isSourcegraphDotCom={false}
+ structuralSearchDisabled={false}
+ queryState={{ query: 'type:file test AND test repo:contains.file(CHANGELOG)' }}
+ onChange={() => {}}
+ onSubmit={() => {}}
+ authenticatedUser={null}
+ searchContextsEnabled={true}
+ showSearchContext={true}
+ showSearchContextManagement={false}
+ setSelectedSearchContextSpec={() => {}}
+ selectedSearchContextSpec={undefined}
+ fetchSearchContexts={() => {
+ throw new Error('fetchSearchContexts')
+ }}
+ getUserSearchContextNamespaces={() => []}
+ fetchStreamSuggestions={() => NEVER}
+ settingsCascade={EMPTY_SETTINGS_CASCADE}
+ globbing={false}
+ isLightTheme={!isDarkTheme}
+ telemetryService={NOOP_TELEMETRY_SERVICE}
+ platformContext={{ requestGraphQL: () => EMPTY }}
+ className=""
+ containerClassName=""
+ autoFocus={true}
+ hideHelpButton={true}
+ />
-
+
)
diff --git a/client/vscode/src/webview/search-panel/index.tsx b/client/vscode/src/webview/search-panel/index.tsx
index 02e35931385..a542258e6c4 100644
--- a/client/vscode/src/webview/search-panel/index.tsx
+++ b/client/vscode/src/webview/search-panel/index.tsx
@@ -5,8 +5,7 @@ import React, { useMemo } from 'react'
import { VSCodeProgressRing } from '@vscode/webview-ui-toolkit/react'
import * as Comlink from 'comlink'
import { createRoot } from 'react-dom/client'
-import { MemoryRouter } from 'react-router'
-import { CompatRouter } from 'react-router-dom-v5-compat'
+import { MemoryRouter } from 'react-router-dom'
import { wrapRemoteObservable } from '@sourcegraph/shared/src/api/client/api/common'
import { ShortcutProvider } from '@sourcegraph/shared/src/react-shortcuts'
@@ -117,9 +116,7 @@ root.render(
{/* Required for shared components that depend on `location`. */}
-
-
-
+
diff --git a/client/vscode/src/webview/sidebars/search/SearchSidebarView.tsx b/client/vscode/src/webview/sidebars/search/SearchSidebarView.tsx
index 2b68991a180..f80a840e8c5 100644
--- a/client/vscode/src/webview/sidebars/search/SearchSidebarView.tsx
+++ b/client/vscode/src/webview/sidebars/search/SearchSidebarView.tsx
@@ -1,6 +1,6 @@
import React, { FC, ReactElement, ReactNode, useCallback, useMemo } from 'react'
-import { useLocation, useNavigate } from 'react-router-dom-v5-compat'
+import { useLocation, useNavigate } from 'react-router-dom'
import { useDeepCompareEffectNoCheck } from 'use-deep-compare-effect'
import create from 'zustand'
diff --git a/client/web/dev/utils/get-api-proxy-settings.ts b/client/web/dev/utils/get-api-proxy-settings.ts
index d98d9558230..d4741e26aa5 100644
--- a/client/web/dev/utils/get-api-proxy-settings.ts
+++ b/client/web/dev/utils/get-api-proxy-settings.ts
@@ -49,7 +49,8 @@ export function getAPIProxySettings(options: GetAPIProxySettingsOptions): ProxyS
// the index.html generated by `getLocalIndexHTML`.
if (
getLocalIndexHTML &&
- proxyRes.statusCode === 200 &&
+ // router.go is not up to date with client routes and still serves index.html with 404
+ (proxyRes.statusCode === 200 || proxyRes.statusCode === 404) &&
proxyRes.headers['content-type'] &&
proxyRes.headers['content-type'].includes('text/html')
) {
diff --git a/client/web/src/Layout.tsx b/client/web/src/Layout.tsx
index 9ddfd263459..d6b8ca69893 100644
--- a/client/web/src/Layout.tsx
+++ b/client/web/src/Layout.tsx
@@ -1,7 +1,7 @@
import React, { Suspense, useCallback, useRef, useState } from 'react'
import classNames from 'classnames'
-import { useLocation, Navigate, Outlet } from 'react-router-dom-v5-compat'
+import { Outlet, useLocation, Navigate } from 'react-router-dom'
import { Observable } from 'rxjs'
import { TabbedPanelContent } from '@sourcegraph/branded/src/components/panel/TabbedPanelContent'
@@ -40,6 +40,7 @@ import type { NotebookProps } from './notebooks'
import { EnterprisePageRoutes, PageRoutes } from './routes.constants'
import { parseSearchURLQuery, SearchAggregationProps, SearchStreamingProps } from './search'
import { NotepadContainer } from './search/Notepad'
+import { SearchQueryStateObserver } from './SearchQueryStateObserver'
import { useExperimentalFeatures } from './stores'
import { ThemePreferenceProps, useTheme } from './theme'
import { getExperimentalFeatures } from './util/get-experimental-features'
@@ -274,6 +275,12 @@ export const Layout: React.FC
= props => {
userHistory={userHistory}
/>
)}
+
)
}
diff --git a/client/web/src/LegacyLayout.tsx b/client/web/src/LegacyLayout.tsx
index 70168e82a6c..9df137ff225 100644
--- a/client/web/src/LegacyLayout.tsx
+++ b/client/web/src/LegacyLayout.tsx
@@ -1,7 +1,7 @@
import React, { Suspense, useCallback, useRef, useState } from 'react'
import classNames from 'classnames'
-import { matchPath, useLocation, Route, Routes, Navigate } from 'react-router-dom-v5-compat'
+import { matchPath, useLocation, Route, Routes, Navigate } from 'react-router-dom'
import { Observable } from 'rxjs'
import { TabbedPanelContent } from '@sourcegraph/branded/src/components/panel/TabbedPanelContent'
@@ -51,6 +51,7 @@ import type { LegacyLayoutRouteComponentProps, LayoutRouteProps } from './routes
import { EnterprisePageRoutes, PageRoutes } from './routes.constants'
import { parseSearchURLQuery, SearchAggregationProps, SearchStreamingProps } from './search'
import { NotepadContainer } from './search/Notepad'
+import { SearchQueryStateObserver } from './SearchQueryStateObserver'
import type { SiteAdminAreaRoute } from './site-admin/SiteAdminArea'
import type { SiteAdminSideBarGroups } from './site-admin/SiteAdminSidebar'
import { useExperimentalFeatures } from './stores'
@@ -328,6 +329,12 @@ export const LegacyLayout: React.FunctionComponent
)}
+
)
}
diff --git a/client/web/src/LegacySourcegraphWebApp.tsx b/client/web/src/LegacySourcegraphWebApp.tsx
index acbff69c7e8..0c3e55d201e 100644
--- a/client/web/src/LegacySourcegraphWebApp.tsx
+++ b/client/web/src/LegacySourcegraphWebApp.tsx
@@ -4,10 +4,9 @@ import * as React from 'react'
import { ApolloProvider } from '@apollo/client'
import ServerIcon from 'mdi-react/ServerIcon'
-import { Router } from 'react-router'
-import { CompatRouter, Routes, Route } from 'react-router-dom-v5-compat'
+import { RouterProvider, createBrowserRouter, createRoutesFromElements, Route } from 'react-router-dom'
import { combineLatest, from, Subscription, fromEvent, of, Subject, Observable } from 'rxjs'
-import { first, startWith, switchMap, map, distinctUntilChanged } from 'rxjs/operators'
+import { startWith, switchMap } from 'rxjs/operators'
import { logger } from '@sourcegraph/common'
import { GraphQLClient, HTTPStatusError } from '@sourcegraph/http-client'
@@ -36,7 +35,6 @@ import {
getDefaultSearchContextSpec,
} from '@sourcegraph/shared/src/search'
import { FilterType } from '@sourcegraph/shared/src/search/query/filters'
-import { omitFilter } from '@sourcegraph/shared/src/search/query/transformer'
import { filterExists } from '@sourcegraph/shared/src/search/query/validate'
import { aggregateStreamingSearch } from '@sourcegraph/shared/src/search/stream'
import { EMPTY_SETTINGS_CASCADE, SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
@@ -68,8 +66,9 @@ import type { RepoRevisionContainerRoute } from './repo/RepoRevisionContainer'
import type { RepoSettingsAreaRoute } from './repo/settings/RepoSettingsArea'
import type { RepoSettingsSideBarGroup } from './repo/settings/RepoSettingsSidebar'
import type { LayoutRouteProps } from './routes'
-import { parseSearchURL, getQueryStateFromLocation, SearchAggregationProps } from './search'
+import { parseSearchURL, SearchAggregationProps } from './search'
import { SearchResultsCacheProvider } from './search/results/SearchResultsCacheProvider'
+import { GLOBAL_SEARCH_CONTEXT_SPEC } from './SearchQueryStateObserver'
import type { SiteAdminAreaRoute } from './site-admin/SiteAdminArea'
import type { SiteAdminSideBarGroups } from './site-admin/SiteAdminSidebar'
import {
@@ -77,18 +76,13 @@ import {
setExperimentalFeaturesFromSettings,
getExperimentalFeatures,
useNavbarQueryState,
- observeStore,
- useExperimentalFeatures,
} from './stores'
-import { setQueryStateFromURL } from './stores/navbarSearchQueryState'
import { eventLogger } from './tracking/eventLogger'
import type { UserAreaRoute } from './user/area/UserArea'
import type { UserAreaHeaderNavItem } from './user/area/UserAreaHeader'
import type { UserSettingsAreaRoute } from './user/settings/UserSettingsArea'
import type { UserSettingsSidebarItems } from './user/settings/UserSettingsSidebar'
import { UserSessionStores } from './UserSessionStores'
-import { globalHistory } from './util/globalHistory'
-import { observeLocation } from './util/location'
import { siteSubjectNoAdmin, viewerSubjectFromSettings } from './util/settings'
import styles from './LegacySourcegraphWebApp.module.scss'
@@ -160,8 +154,6 @@ const WILDCARD_THEME: WildcardTheme = {
isBranded: true,
}
-const GLOBAL_SEARCH_CONTEXT_SPEC = 'global'
-
setLinkComponent(RouterLink)
/**
@@ -268,58 +260,6 @@ export class LegacySourcegraphWebApp extends React.Component<
logger.error('Error sending search context to extensions!', error)
})
- // Update search query state whenever the URL changes
- this.subscriptions.add(
- combineLatest([
- observeStore(useExperimentalFeatures).pipe(
- map(([features]) => features.searchQueryInput === 'experimental'),
- // This ensures that the query stays unmodified until we know
- // whether the feature flag is set or not.
- startWith(true),
- distinctUntilChanged()
- ),
- getQueryStateFromLocation({
- location: observeLocation(globalHistory).pipe(startWith(globalHistory.location)),
- isSearchContextAvailable: (searchContext: string) =>
- this.props.searchContextsEnabled
- ? isSearchContextSpecAvailable({
- spec: searchContext,
- platformContext: this.platformContext,
- })
- .pipe(first())
- .toPromise()
- : Promise.resolve(false),
- }),
- ]).subscribe(([enableExperimentalSearchInput, parsedSearchURLAndContext]) => {
- if (parsedSearchURLAndContext.query) {
- // Only override filters and update query from URL if there
- // is a search query.
- if (!parsedSearchURLAndContext.searchContextSpec) {
- // If no search context is present we have to fall back
- // to the global search context to match the server
- // behavior.
- this.setSelectedSearchContextSpec(GLOBAL_SEARCH_CONTEXT_SPEC)
- } else if (
- parsedSearchURLAndContext.searchContextSpec.spec !== this.state.selectedSearchContextSpec
- ) {
- this.setSelectedSearchContextSpec(parsedSearchURLAndContext.searchContextSpec.spec)
- }
-
- const processedQuery =
- !enableExperimentalSearchInput &&
- parsedSearchURLAndContext.searchContextSpec &&
- this.props.searchContextsEnabled
- ? omitFilter(
- parsedSearchURLAndContext.query,
- parsedSearchURLAndContext.searchContextSpec.filter
- )
- : parsedSearchURLAndContext.query
-
- setQueryStateFromURL(parsedSearchURLAndContext, processedQuery)
- }
- })
- )
-
this.userRepositoriesUpdates.next()
}
@@ -359,6 +299,45 @@ export class LegacySourcegraphWebApp extends React.Component<
return null
}
+ const router = createBrowserRouter(
+ createRoutesFromElements(
+