mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 13:31:54 +00:00
Remove createMemoryRouter from reference panel (#46718)
Co-authored-by: Valery Bugakov <skymk1@gmail.com>
This commit is contained in:
parent
80e3c0b2f5
commit
0b0e7cc614
@ -1,14 +1,10 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import { MockedResponse } from '@apollo/client/testing'
|
||||
import { EMPTY, NEVER, noop, of, Subscription } from 'rxjs'
|
||||
import { of } from 'rxjs'
|
||||
|
||||
import { logger } from '@sourcegraph/common'
|
||||
import { getDocumentNode, dataOrThrowErrors, useQuery } from '@sourcegraph/http-client'
|
||||
import { FlatExtensionHostAPI } from '@sourcegraph/shared/src/api/contract'
|
||||
import { pretendProxySubscribable, pretendRemote } from '@sourcegraph/shared/src/api/util'
|
||||
import { ViewerId } from '@sourcegraph/shared/src/api/viewerTypes'
|
||||
import { Controller } from '@sourcegraph/shared/src/extensions/controller'
|
||||
import { NOOP_TELEMETRY_SERVICE } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { NOOP_PLATFORM_CONTEXT } from '@sourcegraph/shared/src/testing/searchTestHelpers'
|
||||
|
||||
@ -100,7 +96,7 @@ export function buildReferencePanelMocks(): ReferencePanelMock {
|
||||
const resolveRepoRevisionBlobVariables: ResolveRepoAndRevisionVariables = {
|
||||
repoName,
|
||||
filePath: path,
|
||||
revision: '',
|
||||
revision: commit,
|
||||
}
|
||||
|
||||
const fetchHighlightedBlobVariables: ReferencesPanelHighlightedBlobVariables = {
|
||||
@ -112,7 +108,7 @@ export function buildReferencePanelMocks(): ReferencePanelMock {
|
||||
}
|
||||
|
||||
return {
|
||||
url: `/${repoName}/-/blob/${path}?L${line}:${character}&subtree=true#tab=references`,
|
||||
url: `/${repoName}@${commit}/-/blob/${path}?L${line}:${character}&subtree=true#tab=references`,
|
||||
requestMocks: [
|
||||
{
|
||||
request: {
|
||||
@ -304,6 +300,7 @@ const HIGHLIGHTED_FILE_MOCK = {
|
||||
commit: {
|
||||
id: 'R2l0Q29tbWl0OnsiciI6IlVtVndiM05wZEc5eWVUb3lNRFE9IiwiYyI6IjlkMWYzNTNhMjg1YjMwOTRiYzMzYmRhZTI3N2ExOWFlZGFiZThiNzEifQ==',
|
||||
blob: {
|
||||
content: 'content',
|
||||
highlight: {
|
||||
aborted: false,
|
||||
html: highlightedDiffFileContent,
|
||||
@ -319,26 +316,8 @@ const HIGHLIGHTED_FILE_MOCK = {
|
||||
},
|
||||
}
|
||||
|
||||
const NOOP_EXTENSIONS_CONTROLLER: Controller = {
|
||||
executeCommand: () => Promise.resolve(),
|
||||
registerCommand: () => new Subscription(),
|
||||
extHostAPI: Promise.resolve(
|
||||
pretendRemote<FlatExtensionHostAPI>({
|
||||
getContributions: () => pretendProxySubscribable(NEVER),
|
||||
registerContributions: () => pretendProxySubscribable(EMPTY).subscribe(noop as never),
|
||||
haveInitialExtensionsLoaded: () => pretendProxySubscribable(of(true)),
|
||||
addTextDocumentIfNotExists: () => {},
|
||||
addViewerIfNotExists: (): ViewerId => ({ viewerId: 'MOCK_VIEWER_ID' }),
|
||||
setEditorSelections: () => {},
|
||||
removeViewer: () => {},
|
||||
})
|
||||
),
|
||||
commandErrors: EMPTY,
|
||||
unsubscribe: noop,
|
||||
}
|
||||
|
||||
export const defaultProps: Omit<ReferencesPanelProps, 'externalHistory' | 'externalLocation'> = {
|
||||
extensionsController: NOOP_EXTENSIONS_CONTROLLER,
|
||||
export const defaultProps: ReferencesPanelProps = {
|
||||
extensionsController: null,
|
||||
telemetryService: NOOP_TELEMETRY_SERVICE,
|
||||
settingsCascade: {
|
||||
subjects: null,
|
||||
|
||||
@ -1,26 +1,19 @@
|
||||
import { Meta, Story } from '@storybook/react'
|
||||
import * as H from 'history'
|
||||
|
||||
import { MockedTestProvider } from '@sourcegraph/shared/src/testing/apollo'
|
||||
import { BrandedStory } from '@sourcegraph/wildcard/src/stories'
|
||||
|
||||
import { ReferencesPanelWithMemoryRouter } from './ReferencesPanel'
|
||||
import { ReferencesPanel } from './ReferencesPanel'
|
||||
import { buildReferencePanelMocks, defaultProps } from './ReferencesPanel.mocks'
|
||||
|
||||
import webStyles from '../SourcegraphWebApp.scss'
|
||||
|
||||
const config: Meta = {
|
||||
title: 'wildcard/ReferencesPanel',
|
||||
component: ReferencesPanelWithMemoryRouter,
|
||||
|
||||
decorators: [
|
||||
story => (
|
||||
<BrandedStory styles={webStyles}>{() => <div className="container mt-3 pb-3">{story()}</div>}</BrandedStory>
|
||||
),
|
||||
],
|
||||
component: ReferencesPanel,
|
||||
|
||||
parameters: {
|
||||
component: ReferencesPanelWithMemoryRouter,
|
||||
component: ReferencesPanel,
|
||||
chromatic: {
|
||||
disableSnapshot: false,
|
||||
},
|
||||
@ -32,19 +25,17 @@ export default config
|
||||
export const Simple: Story = () => {
|
||||
const { url, requestMocks } = buildReferencePanelMocks()
|
||||
|
||||
const fakeExternalHistory = H.createMemoryHistory()
|
||||
fakeExternalHistory.push(url)
|
||||
|
||||
return (
|
||||
<div style={{ width: 1200, height: 400 }}>
|
||||
<MockedTestProvider mocks={requestMocks}>
|
||||
<ReferencesPanelWithMemoryRouter
|
||||
{...defaultProps}
|
||||
externalHistory={fakeExternalHistory}
|
||||
externalLocation={fakeExternalHistory.location}
|
||||
initialActiveURL="/github.com/sourcegraph/go-diff@9d1f353a285b3094bc33bdae277a19aedabe8b71/-/blob/diff/diff.go?L16:2-16:10"
|
||||
/>
|
||||
</MockedTestProvider>
|
||||
</div>
|
||||
<BrandedStory styles={webStyles} initialEntries={[url]}>
|
||||
{() => (
|
||||
<div className="container mt-3 pb-3">
|
||||
<div style={{ width: 1200, height: 400 }}>
|
||||
<MockedTestProvider mocks={requestMocks}>
|
||||
<ReferencesPanel {...defaultProps} initialActiveURL={url} />
|
||||
</MockedTestProvider>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</BrandedStory>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,35 +1,31 @@
|
||||
import { render, RenderResult, within, fireEvent } from '@testing-library/react'
|
||||
import * as H from 'history'
|
||||
import { within, fireEvent } from '@testing-library/react'
|
||||
|
||||
import { MockedTestProvider, waitForNextApolloResponse } from '@sourcegraph/shared/src/testing/apollo'
|
||||
import '@sourcegraph/shared/dev/mockReactVisibilitySensor'
|
||||
import { renderWithBrandedContext } from '@sourcegraph/wildcard/src/testing'
|
||||
|
||||
import { ReferencesPanelWithMemoryRouter } from './ReferencesPanel'
|
||||
import { ReferencesPanel } from './ReferencesPanel'
|
||||
import { buildReferencePanelMocks, defaultProps } from './ReferencesPanel.mocks'
|
||||
|
||||
describe('ReferencesPanel', () => {
|
||||
async function renderReferencesPanel() {
|
||||
const { url, requestMocks } = buildReferencePanelMocks()
|
||||
|
||||
const fakeExternalHistory = H.createMemoryHistory()
|
||||
fakeExternalHistory.push(url)
|
||||
|
||||
const result: RenderResult = render(
|
||||
const result = renderWithBrandedContext(
|
||||
<MockedTestProvider mocks={requestMocks}>
|
||||
<ReferencesPanelWithMemoryRouter
|
||||
{...defaultProps}
|
||||
externalHistory={fakeExternalHistory}
|
||||
externalLocation={fakeExternalHistory.location}
|
||||
/>
|
||||
</MockedTestProvider>
|
||||
<ReferencesPanel {...defaultProps} />
|
||||
</MockedTestProvider>,
|
||||
{ route: url }
|
||||
)
|
||||
|
||||
await waitForNextApolloResponse()
|
||||
await waitForNextApolloResponse()
|
||||
return { result, externalHistory: fakeExternalHistory }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
it('renders definitions correctly', async () => {
|
||||
const { result } = await renderReferencesPanel()
|
||||
const result = await renderReferencesPanel()
|
||||
|
||||
expect(result.getByText('Definitions')).toBeVisible()
|
||||
|
||||
@ -43,7 +39,7 @@ describe('ReferencesPanel', () => {
|
||||
})
|
||||
|
||||
it('renders references correctly', async () => {
|
||||
const { result } = await renderReferencesPanel()
|
||||
const result = await renderReferencesPanel()
|
||||
|
||||
expect(result.getByText('References')).toBeVisible()
|
||||
|
||||
@ -57,7 +53,7 @@ describe('ReferencesPanel', () => {
|
||||
})
|
||||
|
||||
it('renders a code view when clicking on a location', async () => {
|
||||
const { result, externalHistory } = await renderReferencesPanel()
|
||||
const { history, ...result } = await renderReferencesPanel()
|
||||
|
||||
const definitionsList = result.getByTestId('definitions')
|
||||
const referencesList = result.getByTestId('references')
|
||||
@ -99,11 +95,11 @@ describe('ReferencesPanel', () => {
|
||||
expect(codeView).toHaveTextContent('package diff import')
|
||||
|
||||
// Assert the current URL points at the reference panel
|
||||
expect(externalHistory.createHref(externalHistory.location)).toBe(
|
||||
'/github.com/sourcegraph/go-diff/-/blob/diff/diff.go?L16:2&subtree=true#tab=references'
|
||||
expect(history.createHref(history.location)).toBe(
|
||||
'/github.com/sourcegraph/go-diff@9d1f353a285b3094bc33bdae277a19aedabe8b71/-/blob/diff/diff.go?L16:2&subtree=true#tab=references'
|
||||
)
|
||||
// Click on reference the second time promotes the active location to the URL (and main blob view)
|
||||
fireEvent.click(referenceButton)
|
||||
expect(externalHistory.createHref(externalHistory.location)).toBe(fullReferenceURL)
|
||||
expect(history.createHref(history.location)).toBe(fullReferenceURL)
|
||||
})
|
||||
})
|
||||
|
||||
@ -4,7 +4,7 @@ import { mdiArrowCollapseRight, mdiChevronDown, mdiChevronUp, mdiFilterOutline,
|
||||
import classNames from 'classnames'
|
||||
import * as H from 'history'
|
||||
import { capitalize, uniqBy } from 'lodash'
|
||||
import { MemoryRouter, useLocation } from 'react-router'
|
||||
import { useNavigate, useLocation } from 'react-router-dom-v5-compat'
|
||||
import { Observable, of } from 'rxjs'
|
||||
import { map } from 'rxjs/operators'
|
||||
|
||||
@ -96,37 +96,28 @@ export interface ReferencesPanelProps
|
||||
/** Whether to show the first loaded reference in mini code view */
|
||||
jumpToFirst?: boolean
|
||||
|
||||
/**
|
||||
* The panel runs inside its own MemoryRouter, we keep track of externalHistory
|
||||
* so that we're still able to actually navigate within the browser when required
|
||||
*/
|
||||
externalHistory: H.History
|
||||
externalLocation: H.Location
|
||||
|
||||
/**
|
||||
* Used to overwrite the initial active URL
|
||||
*/
|
||||
initialActiveURL?: string
|
||||
}
|
||||
interface State {
|
||||
repoName: string
|
||||
revision?: string
|
||||
filePath: string
|
||||
line: number
|
||||
character: number
|
||||
jumpToFirst: boolean
|
||||
collapsedState: {
|
||||
references: boolean
|
||||
definitions: boolean
|
||||
implementations: boolean
|
||||
}
|
||||
}
|
||||
|
||||
export const ReferencesPanelWithMemoryRouter: React.FunctionComponent<
|
||||
React.PropsWithChildren<ReferencesPanelProps>
|
||||
> = props => (
|
||||
// TODO: this won't be working with Router V6
|
||||
<MemoryRouter
|
||||
// Force router to remount the Panel when external location changes
|
||||
key={`${props.externalLocation.pathname}${props.externalLocation.search}${props.externalLocation.hash}`}
|
||||
initialEntries={[props.externalLocation]}
|
||||
>
|
||||
<ReferencesPanel {...props} />
|
||||
</MemoryRouter>
|
||||
)
|
||||
|
||||
const ReferencesPanel: React.FunctionComponent<React.PropsWithChildren<ReferencesPanelProps>> = props => {
|
||||
const location = useLocation()
|
||||
|
||||
function createStateFromLocation(location: H.Location): null | State {
|
||||
const { hash, pathname, search } = location
|
||||
const { line, character } = parseQueryAndHash(search, hash)
|
||||
const { line, character, viewState } = parseQueryAndHash(search, hash)
|
||||
const { filePath, repoName, revision } = parseBrowserRepoURL(pathname)
|
||||
|
||||
// If we don't have enough information in the URL, we can't render the panel
|
||||
@ -137,9 +128,42 @@ const ReferencesPanel: React.FunctionComponent<React.PropsWithChildren<Reference
|
||||
const searchParameters = new URLSearchParams(search)
|
||||
const jumpToFirst = searchParameters.get('jumpToFirst') === 'true'
|
||||
|
||||
const token = { repoName, line, character, filePath }
|
||||
const collapsedState: State['collapsedState'] = {
|
||||
references: viewState === 'references',
|
||||
definitions: viewState === 'definitions',
|
||||
implementations: viewState?.startsWith('implementations_') ?? false,
|
||||
}
|
||||
// If the URL doesn't contain tab=<tab>, we open it (likely because the
|
||||
// user clicked on a link in the preview code blob) to show definitions.
|
||||
if (!collapsedState.references && !collapsedState.definitions && !collapsedState.implementations) {
|
||||
collapsedState.definitions = true
|
||||
}
|
||||
|
||||
return <RevisionResolvingReferencesList {...props} {...token} revision={revision} jumpToFirst={jumpToFirst} />
|
||||
return { repoName, revision, filePath, line, character, jumpToFirst, collapsedState }
|
||||
}
|
||||
|
||||
export const ReferencesPanel: React.FunctionComponent<React.PropsWithChildren<ReferencesPanelProps>> = props => {
|
||||
// We store the state in a React state so that we do not update it when the
|
||||
// URL changes.
|
||||
const location = useLocation()
|
||||
const [state] = useState(createStateFromLocation(location))
|
||||
|
||||
if (state === null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<RevisionResolvingReferencesList
|
||||
{...props}
|
||||
repoName={state.repoName}
|
||||
revision={state.revision}
|
||||
filePath={state.filePath}
|
||||
line={state.line}
|
||||
character={state.character}
|
||||
jumpToFirst={state.jumpToFirst}
|
||||
collapsedState={state.collapsedState}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const RevisionResolvingReferencesList: React.FunctionComponent<
|
||||
@ -150,6 +174,7 @@ export const RevisionResolvingReferencesList: React.FunctionComponent<
|
||||
character: number
|
||||
filePath: string
|
||||
revision?: string
|
||||
collapsedState: State['collapsedState']
|
||||
}
|
||||
>
|
||||
> = props => {
|
||||
@ -204,6 +229,7 @@ interface ReferencesPanelPropsWithToken extends ReferencesPanelProps {
|
||||
isArchived: boolean
|
||||
fileContent: string
|
||||
useCodeIntel: NonNullable<ReferencesPanelProps['useCodeIntel']>
|
||||
collapsedState: State['collapsedState']
|
||||
}
|
||||
|
||||
const SearchTokenFindingReferencesList: React.FunctionComponent<
|
||||
@ -258,12 +284,15 @@ const ReferencesList: React.FunctionComponent<
|
||||
searchToken: string
|
||||
spec: LanguageSpec
|
||||
fileContent: string
|
||||
collapsedState: State['collapsedState']
|
||||
}
|
||||
>
|
||||
> = props => {
|
||||
const [filter, setFilter] = useState<string>()
|
||||
const debouncedFilter = useDebounce(filter, 150)
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
setFilter(undefined)
|
||||
}, [props.token])
|
||||
@ -386,34 +415,18 @@ const ReferencesList: React.FunctionComponent<
|
||||
// points to the same line. In case they press "back" in the browser history,
|
||||
// the promoted line should be highlighted.
|
||||
setActiveURL(url)
|
||||
props.externalHistory.push(url)
|
||||
navigate(url)
|
||||
}
|
||||
|
||||
const navigateToUrl = (url: string): void => {
|
||||
props.externalHistory.push(url)
|
||||
navigate(url)
|
||||
}
|
||||
|
||||
// Manual management of the open/closed state of collapsible lists so they
|
||||
// stay open/closed across re-renders and re-mounts.
|
||||
const location = useLocation()
|
||||
const initialCollapseState = useMemo(() => {
|
||||
const { viewState } = parseQueryAndHash(location.search, location.hash)
|
||||
const state = {
|
||||
references: viewState === 'references',
|
||||
definitions: viewState === 'definitions',
|
||||
implementations: viewState?.startsWith('implementations_') ?? false,
|
||||
}
|
||||
// If the URL doesn't contain tab=<tab>, we open it (likely because the
|
||||
// user clicked on a link in the preview code blob) to show definitions.
|
||||
if (!state.references && !state.definitions && !state.implementations) {
|
||||
state.definitions = true
|
||||
}
|
||||
return state
|
||||
}, [location])
|
||||
const [collapsed, setCollapsed] = useSessionStorage<Record<string, boolean>>(
|
||||
'sideblob-collapse-state-' + sessionStorageKeyFromToken(props.token),
|
||||
initialCollapseState
|
||||
props.collapsedState
|
||||
)
|
||||
|
||||
const handleOpenChange = (id: string, isOpen: boolean): void =>
|
||||
setCollapsed(previous => ({ ...previous, [id]: isOpen }))
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ import { AbsoluteRepoFile, ModeSpec, parseQueryAndHash, UIPositionSpec } from '@
|
||||
import { useObservable } from '@sourcegraph/wildcard'
|
||||
|
||||
import { CodeIntelligenceProps } from '../../../codeintel'
|
||||
import { ReferencesPanelWithMemoryRouter } from '../../../codeintel/ReferencesPanel'
|
||||
import { ReferencesPanel } from '../../../codeintel/ReferencesPanel'
|
||||
import { RepoRevisionSidebarCommits } from '../../RepoRevisionSidebarCommits'
|
||||
|
||||
interface Props
|
||||
@ -238,7 +238,7 @@ function useBlobPanelViews({
|
||||
panelDefinitions.push({
|
||||
id: 'references',
|
||||
provider: panelSubjectChanges.pipe(
|
||||
map(({ position, history, location }) => ({
|
||||
map(({ position }) => ({
|
||||
title: 'References',
|
||||
content: '',
|
||||
priority: 180,
|
||||
@ -251,15 +251,13 @@ function useBlobPanelViews({
|
||||
// This panel doesn't need a wrapper
|
||||
noWrapper: true,
|
||||
reactElement: position ? (
|
||||
<ReferencesPanelWithMemoryRouter
|
||||
<ReferencesPanel
|
||||
settingsCascade={settingsCascade}
|
||||
platformContext={platformContext}
|
||||
isLightTheme={isLightTheme}
|
||||
extensionsController={extensionsController}
|
||||
telemetryService={telemetryService}
|
||||
key="references"
|
||||
externalHistory={history}
|
||||
externalLocation={location}
|
||||
fetchHighlightedFileLineRanges={fetchHighlightedFileLineRanges}
|
||||
useCodeIntel={useCodeIntel}
|
||||
/>
|
||||
|
||||
12
package.json
12
package.json
@ -456,7 +456,7 @@
|
||||
"react-resizable": "^3.0.4",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-router-dom-v5-compat": "^6.3.0",
|
||||
"react-router-dom-v5-compat": "^6.7.0",
|
||||
"react-spring": "^9.4.2",
|
||||
"react-sticky-box": "1.0.2",
|
||||
"react-visibility-sensor": "^5.1.1",
|
||||
@ -487,6 +487,15 @@
|
||||
"zustand": "^3.6.9"
|
||||
},
|
||||
"packageManager": "pnpm@7.24.2",
|
||||
"pnpm": {
|
||||
"packageExtensions": {
|
||||
"react-router-dom-v5-compat": {
|
||||
"dependencies": {
|
||||
"@remix-run/router": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/webpack": "5",
|
||||
"history": "4.5.1",
|
||||
@ -495,4 +504,5 @@
|
||||
"tslib": "2.1.0",
|
||||
"jsprim": "1.4.2"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ overrides:
|
||||
tslib: 2.1.0
|
||||
jsprim: 1.4.2
|
||||
|
||||
packageExtensionsChecksum: 4b1de42ef6cd5dc58798836c97782882
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@ -339,7 +341,7 @@ importers:
|
||||
react-resizable: ^3.0.4
|
||||
react-router: ^5.2.0
|
||||
react-router-dom: ^5.2.0
|
||||
react-router-dom-v5-compat: ^6.3.0
|
||||
react-router-dom-v5-compat: ^6.7.0
|
||||
react-spring: ^9.4.2
|
||||
react-sticky-box: 1.0.2
|
||||
react-visibility-sensor: ^5.1.1
|
||||
@ -518,7 +520,7 @@ importers:
|
||||
react-resizable: 3.0.4_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
react-router: 5.2.0_react@18.1.0
|
||||
react-router-dom: 5.2.0_react@18.1.0
|
||||
react-router-dom-v5-compat: 6.3.0_xjeikfjhclro5pp2abrahotxli
|
||||
react-router-dom-v5-compat: 6.7.0_xjeikfjhclro5pp2abrahotxli
|
||||
react-spring: 9.4.2_ssv3vkwxg74iun7wj74vdfwzhu
|
||||
react-sticky-box: 1.0.2_react@18.1.0
|
||||
react-visibility-sensor: 5.1.1_ef5jwxihqo6n7gxfmzogljlgcm
|
||||
@ -26281,17 +26283,19 @@ packages:
|
||||
resize-observer-polyfill: 1.5.1
|
||||
dev: false
|
||||
|
||||
/react-router-dom-v5-compat/6.3.0_xjeikfjhclro5pp2abrahotxli:
|
||||
resolution: {integrity: sha512-lfnfDEAdfXf92VQQ692+aMFj9JKb73GZ7EbiQJeJT4sK+KUGvua3FGN2H8n2H5zSMaY1cvrihGiaI373cvv7OQ==}
|
||||
/react-router-dom-v5-compat/6.7.0_xjeikfjhclro5pp2abrahotxli:
|
||||
resolution: {integrity: sha512-pwK0hdpgbBnTxCv0/Yi1yCaVX0iglPxxDvuy6VK7MF/0q2MYEkqS186diGdktgXikKXmFMhhXR2h3IanBv0tAA==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
react-dom: '>=16.8'
|
||||
react-router-dom: 4 || 5
|
||||
dependencies:
|
||||
'@remix-run/router': 1.3.0
|
||||
history: 4.5.1
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
react-router: 6.3.0_react@18.1.0
|
||||
react-router: 6.7.0_react@18.1.0
|
||||
react-router-dom: 5.2.0_react@18.1.0
|
||||
dev: false
|
||||
|
||||
@ -26340,12 +26344,13 @@ packages:
|
||||
tiny-warning: 1.0.3
|
||||
dev: false
|
||||
|
||||
/react-router/6.3.0_react@18.1.0:
|
||||
resolution: {integrity: sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ==}
|
||||
/react-router/6.7.0_react@18.1.0:
|
||||
resolution: {integrity: sha512-KNWlG622ddq29MAM159uUsNMdbX8USruoKnwMMQcs/QWZgFUayICSn2oB7reHce1zPj6CG18kfkZIunSSRyGHg==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
dependencies:
|
||||
history: 4.5.1
|
||||
'@remix-run/router': 1.3.0
|
||||
react: 18.1.0
|
||||
dev: false
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user