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

feat: closest path match for API Explorer #811

Merged
merged 12 commits into from
Sep 3, 2021
39 changes: 29 additions & 10 deletions packages/api-explorer/src/ApiExplorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,24 @@ import { useLocation } from 'react-router'
import styled, { createGlobalStyle } from 'styled-components'
import { Aside, ComponentsProvider, Layout, Page } from '@looker/components'
import { SpecList } from '@looker/sdk-codegen'
import { loadSpecApi, RunItSetter } from '@looker/run-it'
import {
RunItSetter,
funFetch,
fallbackFetch,
OAuthScene,
} from '@looker/run-it'
import {
SearchContext,
LodeContext,
defaultLodeContextValue,
EnvAdaptorContext,
} from './context'
import { EnvAdaptorConstants, getLoded, IApixEnvAdaptor } from './utils'
import {
EnvAdaptorConstants,
getLoded,
IApixEnvAdaptor,
oAuthPath,
} from './utils'
import { Header, SideNav, ErrorBoundary } from './components'
import {
specReducer,
Expand Down Expand Up @@ -70,6 +80,7 @@ const ApiExplorer: FC<ApiExplorerProps> = ({
}) => {
const location = useLocation()
const { setSdkLanguageAction } = useActions()
const oauthReturn = location.pathname === `/${oAuthPath}`

const [specState, specDispatch] = useReducer(
specReducer,
Expand Down Expand Up @@ -102,20 +113,27 @@ const ApiExplorer: FC<ApiExplorerProps> = ({
window.removeEventListener('message', hasNavigationToggle)
}
}
}, [])
}, [headless, hasNavigationToggle])

useEffect(() => {
const loadSpec = async () => {
if (!spec.api) {
const newSpec = { ...spec }
const api = await loadSpecApi(newSpec)
if (api) {
specDispatch(updateSpecApi(spec.key, api))
try {
const newSpec = { ...spec }
const api = await fallbackFetch(newSpec, funFetch)
if (api) {
spec.api = api
specDispatch(updateSpecApi(spec.key, api))
}
} catch (error) {
console.error(error)
}
}
}
loadSpec()
}, [spec])
if (!oauthReturn) {
loadSpec()
}
}, [spec, location])

useEffect(() => {
getLoded(exampleLodeUrl, declarationsLodeUrl).then((resp) => setLode(resp))
Expand Down Expand Up @@ -167,7 +185,8 @@ const ApiExplorer: FC<ApiExplorerProps> = ({
/>
</AsideBorder>
)}
{spec.api && (
{oauthReturn && <OAuthScene />}
{!oauthReturn && spec.api && (
<AppRouter
api={spec.api}
specKey={spec.key}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ import { ApiSpecSelector } from './ApiSpecSelector'

const specState = getLoadedSpecState()

jest.mock('react-router-dom', () => {
const ReactRouterDOM = jest.requireActual('react-router-dom')
Copy link
Collaborator

Choose a reason for hiding this comment

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

I like 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.

awesome. that means I can quit for the week! 😃

return {
...ReactRouterDOM,
useLocation: () => ({
pathname: '/4.0/methods/Dashboard/dashboard',
}),
}
})

describe('ApiSpecSelector', () => {
const specDispatch = jest.fn()
Element.prototype.scrollIntoView = jest.fn()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

import React, { FC, Dispatch } from 'react'
import { Select } from '@looker/components'
import { useHistory } from 'react-router-dom'
import { useHistory, useLocation } from 'react-router-dom'

import { SpecList, SpecItem } from '@looker/sdk-codegen'
import { SpecAction, selectSpec } from '../../reducers'
Expand All @@ -43,6 +43,7 @@ export const ApiSpecSelector: FC<ApiSpecSelectorProps> = ({
specDispatch,
}) => {
const history = useHistory()
const location = useLocation()
const options = Object.entries(specs).map(([key, spec]) => ({
value: key,
label: key,
Expand All @@ -51,7 +52,8 @@ export const ApiSpecSelector: FC<ApiSpecSelectorProps> = ({

const handleChange = (specKey: string) => {
specDispatch(selectSpec(specKey))
history.push(`/${specKey}`)
const matchPath = location.pathname.replace(`/${spec.key}`, `/${specKey}`)
history.push(matchPath)
}

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/api-explorer/src/components/SideNav/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export const SideNav: FC<SideNavProps> = ({
let results
let newTags
let newTypes
if (debouncedPattern) {
if (debouncedPattern && api.search) {
results = api.search(pattern, searchCriteria)
newTags = results.tags
newTypes = results.types
Expand Down
13 changes: 3 additions & 10 deletions packages/api-explorer/src/routes/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@
SOFTWARE.

*/
import React, { FC, useContext } from 'react'
import React, { FC } from 'react'
import { Redirect, Route, Switch } from 'react-router-dom'
import { ApiModel, SpecList } from '@looker/sdk-codegen'
import { OAuthScene, RunItSetter, RunItContext } from '@looker/run-it'
import { RunItSetter } from '@looker/run-it'

import { HomeScene, MethodScene, TagScene, TypeScene } from '../scenes'
import { DiffScene } from '../scenes/DiffScene'
import { diffPath, IApixEnvAdaptor, oAuthPath } from '../utils'
import { diffPath, IApixEnvAdaptor } from '../utils'

interface AppRouterProps {
api: ApiModel
Expand All @@ -49,16 +49,9 @@ export const AppRouter: FC<AppRouterProps> = ({
envAdaptor,
setVersionsUrl,
}) => {
const { sdk } = useContext(RunItContext)
const maybeOauth = sdk && sdk.apiVersion === '4.0'
return (
<Switch>
<Redirect from="/" to={`/${specKey}/`} exact />
{maybeOauth && (
<Route path={`/${oAuthPath}`}>
<OAuthScene />
</Route>
)}
<Route path={`/${diffPath}/:l?/:r?`}>
<DiffScene specs={specs} toggleNavigation={toggleNavigation} />
</Route>
Expand Down
45 changes: 35 additions & 10 deletions packages/api-explorer/src/scenes/DiffScene/DiffScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/

import React, { FC, useState, useEffect } from 'react'
import { ApiModel, DiffRow, SpecList } from '@looker/sdk-codegen'
import { ApiModel, DiffRow, SpecList, SpecItem } from '@looker/sdk-codegen'
import { useHistory, useRouteMatch } from 'react-router-dom'
import {
Box,
Expand All @@ -37,17 +37,13 @@ import {
SelectMulti,
} from '@looker/components'
import { SyncAlt } from '@styled-icons/material/SyncAlt'
import { fallbackFetch, funFetch } from '@looker/run-it'
import { getDefaultSpecKey } from '../../reducers/spec/utils'
import { diffPath } from '../../utils'
import { ApixSection } from '../../components'
import { diffSpecs, standardDiffToggles } from './diffUtils'
import { DocDiff } from './DocDiff'

export interface DiffSceneProps {
specs: SpecList
toggleNavigation: (target?: boolean) => void
}

/**
* Pick the left key, or default spec
* @param specs to pick from
Expand Down Expand Up @@ -97,6 +93,11 @@ const diffToggles = [
},
]

export interface DiffSceneProps {
specs: SpecList
toggleNavigation: (target?: boolean) => void
}

export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
const history = useHistory()
const match = useRouteMatch<{ l: string; r: string }>(`/${diffPath}/:l?/:r?`)
Expand All @@ -120,7 +121,7 @@ export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
}, [])

const computeDelta = (left: string, right: string, toggles: string[]) => {
if (left && right) {
if (left && right && specs[left].api && specs[right].api) {
return diffSpecs(specs[left].api!, specs[right].api!, toggles)
}
return []
Expand All @@ -129,12 +130,36 @@ export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
computeDelta(leftKey, rightKey, toggles)
)

const compareKeys = (left: string, right: string) => {
const loadSpec = async (
specs: SpecList,
key: string,
setter: (spec: SpecItem) => void
) => {
const spec = specs[key]
if (!spec.api) {
try {
const newSpec = { ...spec }
const api = await fallbackFetch(newSpec, funFetch)
if (api) {
spec.api = api
setter(spec)
}
} catch (error) {
console.error(error)
}
}
}

const compareKeys = async (left: string, right: string) => {
if (left !== leftKey || right !== rightKey) {
history.push(`/${diffPath}/${left}/${right}`)
}
setLeftApi(specs[left].api!)
setRightApi(specs[right].api!)
if (!specs[left].api) {
await loadSpec(specs, leftKey, (spec) => setLeftApi(spec.api!))
}
if (!specs[right].api) {
await loadSpec(specs, rightKey, (spec) => setRightApi(spec.api!))
}
setDelta([...computeDelta(left, right, toggles)])
}

Expand Down
69 changes: 42 additions & 27 deletions packages/api-explorer/src/scenes/MethodScene/MethodScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
ExtendComponentsThemeProvider,
} from '@looker/components'
import { Beaker } from '@looker/icons'
import { useParams } from 'react-router-dom'
import { useHistory, useParams } from 'react-router-dom'
import { RunIt, RunItSetter, RunItContext, RunItFormKey } from '@looker/run-it'
import { ApiModel, typeRefs } from '@looker/sdk-codegen'
import { useSelector } from 'react-redux'
Expand Down Expand Up @@ -66,6 +66,7 @@ interface MethodSceneProps {

interface MethodSceneParams {
methodName: string
methodTag: string
specKey: string
}

Expand All @@ -79,25 +80,37 @@ export const MethodScene: FC<MethodSceneProps> = ({
envAdaptor,
setVersionsUrl,
}) => {
const history = useHistory()
const { sdk } = useContext(RunItContext)
const sdkLanguage = useSelector(getSelectedSdkLanguage)
const { methodName, specKey } = useParams<MethodSceneParams>()
const { specKey, methodTag, methodName } = useParams<MethodSceneParams>()
const { value, toggle, setOn } = useToggle()
const [method, setMethod] = useState(api.methods[methodName])
const seeTypes = typeRefs(api, method.customTypes)
const seeTypes = typeRefs(api, method?.customTypes)

const RunItButton = value ? Button : ButtonOutline

useEffect(() => {
setMethod(api.methods[methodName])
}, [api, methodName])
const foundMethod = api.methods[methodName]
if (foundMethod) {
setMethod(api.methods[methodName])
} else {
// Invalid method
if (api.tags[methodTag]) {
// Found tag though
history.push(`/${specKey}/methods/${methodTag}`)
} else {
history.push(`/${specKey}/methods`)
}
}
}, [api, history, methodName, specKey])

useEffect(() => {
const checkRunIt = async () => {
const show = await showRunIt(envAdaptor)
if (show) setOn()
}
checkRunIt()
checkRunIt().catch((error) => console.error(error))
}, [envAdaptor, setOn])

const runItToggle = (
Expand All @@ -112,28 +125,30 @@ export const MethodScene: FC<MethodSceneProps> = ({

return (
<>
<ApixSection>
<Space between>
<Space>
<DocTitle>{method.summary}</DocTitle>
<DocSource method={method} />
{method && (
<ApixSection>
<Space between>
<Space>
<DocTitle>{method.summary}</DocTitle>
<DocSource method={method} />
</Space>
{runItToggle}
</Space>
<Space mb="large" gap="small">
<DocStatus method={method} />
<DocActivityType method={method} />
<DocRateLimited method={method} />
</Space>
{runItToggle}
</Space>
<Space mb="large" gap="small">
<DocStatus method={method} />
<DocActivityType method={method} />
<DocRateLimited method={method} />
</Space>
<DocOperation method={method} />
<DocMarkdown source={method.description} specKey={specKey} />
<DocSDKs api={api} method={method} />
<DocRequestBody method={method} />
<DocSdkUsage method={method} />
<DocReferences typesUsed={seeTypes} api={api} specKey={specKey} />
<DocResponses responses={method.responses} />
<DocSchema object={method.schema} />
</ApixSection>
<DocOperation method={method} />
<DocMarkdown source={method.description} specKey={specKey} />
<DocSDKs api={api} method={method} />
<DocRequestBody method={method} />
<DocSdkUsage method={method} />
<DocReferences typesUsed={seeTypes} api={api} specKey={specKey} />
<DocResponses responses={method.responses} />
<DocSchema object={method.schema} />
</ApixSection>
)}
{sdk && value && (
<Aside width="50rem">
<ExtendComponentsThemeProvider
Expand Down
Loading