Skip to content

Commit

Permalink
fix: Sidenav selection (#831)
Browse files Browse the repository at this point in the history
Tabs in sidenav were not being synced with history. Now if tab selected,
history is updated. If page is reloaded, tabs are synced to current
history. If link is clicked that updates sidenav panel, panel is updated
accordingly.
  • Loading branch information
bryans99 authored Sep 22, 2021
1 parent dd8a3f0 commit 52e3ef3
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ describe('SideNav', () => {
specs={specs}
spec={specState.spec}
specDispatch={specDispatch}
/>
/>,
['/3.1/methods']
)
expect(screen.getAllByText(allTagsPattern)).toHaveLength(2)
expect(
Expand Down
40 changes: 30 additions & 10 deletions packages/api-explorer/src/components/SideNav/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

import type { FC, Dispatch } from 'react'
import React, { useContext, useEffect, useState } from 'react'
import { useHistory, useLocation } from 'react-router-dom'
import {
Heading,
TabList,
Expand All @@ -43,7 +44,6 @@ import type {
ApiModel,
} from '@looker/sdk-codegen'
import { CriteriaToSet } from '@looker/sdk-codegen'
import { useRouteMatch } from 'react-router-dom'

import { SearchContext } from '../../context'
import type { SpecAction } from '../../reducers'
Expand All @@ -66,25 +66,38 @@ interface SideNavProps {
specDispatch: Dispatch<SpecAction>
}

interface SideNavParams {
sideNavTab: string
}

export const SideNav: FC<SideNavProps> = ({
headless = false,
specs,
spec,
specDispatch,
}) => {
const history = useHistory()
const location = useLocation()
const api = spec.api || ({} as ApiModel)
const specKey = spec.key
const tabNames = ['methods', 'types']
const match = useRouteMatch<SideNavParams>(`/:specKey/:sideNavTab?`)
let defaultIndex = tabNames.indexOf('methods')
if (match && match.params.sideNavTab) {
defaultIndex = tabNames.indexOf(match.params.sideNavTab)
const pathParts = location.pathname.split('/')
const sideNavTab = pathParts[1] === 'diff' ? pathParts[3] : pathParts[2]
let defaultIndex = tabNames.indexOf(sideNavTab)
if (defaultIndex < 0) {
defaultIndex = tabNames.indexOf('methods')
}
const onTabChange = (index: number) => {
const parts = location.pathname.split('/')
if (parts[1] === 'diff') {
if (parts[3] !== tabNames[index]) {
parts[3] = tabNames[index]
history.push(parts.join('/'))
}
} else {
if (parts[2] !== tabNames[index]) {
parts[2] = tabNames[index]
history.push(parts.join('/'))
}
}
}
const tabs = useTabs({ defaultIndex })
const tabs = useTabs({ defaultIndex, onChange: onTabChange })
const { searchSettings, setSearchSettings } = useContext(SearchContext)
const [pattern, setSearchPattern] = useState(searchSettings.pattern)
const debouncedPattern = useDebounce(pattern, 250)
Expand Down Expand Up @@ -120,6 +133,13 @@ export const SideNav: FC<SideNavProps> = ({
setSearchSettings(setPattern(debouncedPattern!))
}, [debouncedPattern, specKey, spec])

useEffect(() => {
const { selectedIndex, onSelectTab } = tabs
if (defaultIndex !== selectedIndex) {
onSelectTab(defaultIndex)
}
}, [defaultIndex, tabs])

const size = useWindowSize()
const headlessOffset = headless ? 200 : 120
const menuH = size.height - 16 * HEADER_REM - headlessOffset
Expand Down
7 changes: 6 additions & 1 deletion packages/api-explorer/src/reducers/spec/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,13 @@ export const initDefaultSpecState = (
location: AbstractLocation
): SpecState => {
const specKey = getSpecKey(location, specList)
// Handle bad spec in the URL. Fall back to 4.0
let spec = specList[specKey]
if (!spec) {
spec = specList['4.0']
}
return {
specList,
spec: specList[specKey],
spec,
}
}
9 changes: 7 additions & 2 deletions packages/api-explorer/src/scenes/DiffScene/DiffScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,16 @@ export interface DiffSceneProps {
toggleNavigation: (target?: boolean) => void
}

const validateParam = (specs: SpecList, specKey = '') => {
return specs[specKey] ? specKey : ''
}

export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
const history = useHistory()
const match = useRouteMatch<{ l: string; r: string }>(`/${diffPath}/:l?/:r?`)
const l = match?.params.l || ''
const r = match?.params.r || ''
const l = validateParam(specs, match?.params.l)
const r = validateParam(specs, match?.params.r)

const options = Object.entries(specs).map(([key, spec]) => ({
value: key,
label: `${key} (${spec.status})`,
Expand Down
24 changes: 15 additions & 9 deletions packages/api-explorer/src/scenes/TagScene/TagScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
*/
import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import { useHistory, useParams } from 'react-router-dom'
import { Grid, ButtonToggle, ButtonItem } from '@looker/components'
import type { ApiModel } from '@looker/sdk-codegen'
import { useParams, useHistory } from 'react-router-dom'
import { ApixSection, DocTitle, DocMethodSummary, Link } from '../../components'
import { buildMethodPath } from '../../utils'
import { getOperations } from './utils'
Expand All @@ -44,21 +44,27 @@ interface TagSceneParams {
export const TagScene: FC<TagSceneProps> = ({ api }) => {
const { specKey, methodTag } = useParams<TagSceneParams>()
const history = useHistory()
if (!(methodTag in api.tags)) {
history.push('/methods')
}
const methods = api.tags[methodTag]
const tag = Object.values(api.spec.tags!).find(
(tag) => tag.name === methodTag
)!
const operations = getOperations(methods)
const [value, setValue] = useState('ALL')

useEffect(() => {
/** Reset ButtonToggle value on route change */
setValue('ALL')
}, [methodTag])

const methods = api.tags[methodTag]
useEffect(() => {
if (!methods) {
history.push(`/${specKey}/methods`)
}
}, [history, methods])
if (!methods) {
return <></>
}
const tag = Object.values(api.spec.tags!).find(
(tag) => tag.name === methodTag
)!
const operations = getOperations(methods)

return (
<ApixSection>
<DocTitle>{`${tag.name}: ${tag.description}`}</DocTitle>
Expand Down

0 comments on commit 52e3ef3

Please sign in to comment.