@looker/api-explorer 0.9.33 → 0.9.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/bundle.js +1 -1
- package/dist/bundle.js.map +1 -1
- package/lib/ApiExplorer.js +9 -1
- package/lib/ApiExplorer.js.map +1 -1
- package/lib/components/DocMarkdown/DocMarkdown.js +7 -7
- package/lib/components/DocMarkdown/DocMarkdown.js.map +1 -1
- package/lib/components/SelectorContainer/ApiSpecSelector.js +4 -2
- package/lib/components/SelectorContainer/ApiSpecSelector.js.map +1 -1
- package/lib/components/SideNav/SideNav.js +23 -13
- package/lib/components/SideNav/SideNav.js.map +1 -1
- package/lib/components/SideNav/SideNavMethods.js +8 -6
- package/lib/components/SideNav/SideNavMethods.js.map +1 -1
- package/lib/components/SideNav/SideNavTypes.js +6 -4
- package/lib/components/SideNav/SideNavTypes.js.map +1 -1
- package/lib/esm/ApiExplorer.js +9 -1
- package/lib/esm/ApiExplorer.js.map +1 -1
- package/lib/esm/components/DocMarkdown/DocMarkdown.js +4 -4
- package/lib/esm/components/DocMarkdown/DocMarkdown.js.map +1 -1
- package/lib/esm/components/SelectorContainer/ApiSpecSelector.js +4 -3
- package/lib/esm/components/SelectorContainer/ApiSpecSelector.js.map +1 -1
- package/lib/esm/components/SideNav/SideNav.js +26 -16
- package/lib/esm/components/SideNav/SideNav.js.map +1 -1
- package/lib/esm/components/SideNav/SideNavMethods.js +8 -6
- package/lib/esm/components/SideNav/SideNavMethods.js.map +1 -1
- package/lib/esm/components/SideNav/SideNavTypes.js +8 -6
- package/lib/esm/components/SideNav/SideNavTypes.js.map +1 -1
- package/lib/esm/scenes/DiffScene/DiffScene.js +6 -6
- package/lib/esm/scenes/DiffScene/DiffScene.js.map +1 -1
- package/lib/esm/scenes/DiffScene/DocDiff/DiffItem.js +3 -4
- package/lib/esm/scenes/DiffScene/DocDiff/DiffItem.js.map +1 -1
- package/lib/esm/scenes/MethodScene/MethodScene.js +4 -3
- package/lib/esm/scenes/MethodScene/MethodScene.js.map +1 -1
- package/lib/esm/scenes/MethodTagScene/MethodTagScene.js +3 -2
- package/lib/esm/scenes/MethodTagScene/MethodTagScene.js.map +1 -1
- package/lib/esm/scenes/TypeScene/TypeScene.js +5 -1
- package/lib/esm/scenes/TypeScene/TypeScene.js.map +1 -1
- package/lib/esm/scenes/TypeTagScene/TypeTagScene.js +5 -5
- package/lib/esm/scenes/TypeTagScene/TypeTagScene.js.map +1 -1
- package/lib/esm/utils/hooks.js +26 -0
- package/lib/esm/utils/hooks.js.map +1 -0
- package/lib/esm/utils/index.js +1 -0
- package/lib/esm/utils/index.js.map +1 -1
- package/lib/esm/utils/path.js +2 -2
- package/lib/esm/utils/path.js.map +1 -1
- package/lib/scenes/DiffScene/DiffScene.js +4 -4
- package/lib/scenes/DiffScene/DiffScene.js.map +1 -1
- package/lib/scenes/DiffScene/DocDiff/DiffItem.js +2 -4
- package/lib/scenes/DiffScene/DocDiff/DiffItem.js.map +1 -1
- package/lib/scenes/MethodScene/MethodScene.js +3 -2
- package/lib/scenes/MethodScene/MethodScene.js.map +1 -1
- package/lib/scenes/MethodTagScene/MethodTagScene.js +2 -1
- package/lib/scenes/MethodTagScene/MethodTagScene.js.map +1 -1
- package/lib/scenes/TypeScene/TypeScene.js +6 -1
- package/lib/scenes/TypeScene/TypeScene.js.map +1 -1
- package/lib/scenes/TypeTagScene/TypeTagScene.js +3 -3
- package/lib/scenes/TypeTagScene/TypeTagScene.js.map +1 -1
- package/lib/utils/hooks.d.ts +3 -0
- package/lib/utils/hooks.js +36 -0
- package/lib/utils/hooks.js.map +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +10 -1
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/path.d.ts +2 -2
- package/lib/utils/path.js +2 -2
- package/lib/utils/path.js.map +1 -1
- package/package.json +9 -9
- package/src/ApiExplorer.tsx +7 -1
- package/src/components/DocMarkdown/DocMarkdown.tsx +4 -4
- package/src/components/SelectorContainer/ApiSpecSelector.spec.tsx +5 -2
- package/src/components/SelectorContainer/ApiSpecSelector.tsx +4 -3
- package/src/components/SideNav/SideNav.spec.tsx +39 -5
- package/src/components/SideNav/SideNav.tsx +22 -21
- package/src/components/SideNav/SideNavMethods.spec.tsx +9 -2
- package/src/components/SideNav/SideNavMethods.tsx +15 -8
- package/src/components/SideNav/SideNavTypes.spec.tsx +9 -2
- package/src/components/SideNav/SideNavTypes.tsx +15 -8
- package/src/scenes/DiffScene/DiffScene.tsx +6 -6
- package/src/scenes/DiffScene/DocDiff/DiffItem.spec.tsx +4 -3
- package/src/scenes/DiffScene/DocDiff/DiffItem.tsx +3 -4
- package/src/scenes/MethodScene/MethodScene.tsx +4 -3
- package/src/scenes/MethodTagScene/MethodTagScene.tsx +3 -2
- package/src/scenes/TypeScene/TypeScene.tsx +8 -2
- package/src/scenes/TypeTagScene/TypeTagScene.tsx +5 -5
- package/src/utils/hooks.spec.ts +78 -0
- package/src/utils/hooks.ts +53 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/path.spec.ts +25 -2
- package/src/utils/path.ts +11 -4
package/src/ApiExplorer.tsx
CHANGED
|
@@ -91,7 +91,7 @@ export const ApiExplorer: FC<ApiExplorerProps> = ({
|
|
|
91
91
|
const specs = useSelector(selectSpecs)
|
|
92
92
|
const spec = useSelector(selectCurrentSpec)
|
|
93
93
|
const { initLodesAction } = useLodeActions()
|
|
94
|
-
const { initSettingsAction } = useSettingActions()
|
|
94
|
+
const { initSettingsAction, setSearchPatternAction } = useSettingActions()
|
|
95
95
|
const { initSpecsAction, setCurrentSpecAction } = useSpecActions()
|
|
96
96
|
|
|
97
97
|
const location = useLocation()
|
|
@@ -123,6 +123,12 @@ export const ApiExplorer: FC<ApiExplorerProps> = ({
|
|
|
123
123
|
}
|
|
124
124
|
}, [location.pathname, spec])
|
|
125
125
|
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const searchParams = new URLSearchParams(location.search)
|
|
128
|
+
const searchPattern = searchParams.get('s') || ''
|
|
129
|
+
setSearchPatternAction({ searchPattern: searchPattern! })
|
|
130
|
+
}, [location.search])
|
|
131
|
+
|
|
126
132
|
useEffect(() => {
|
|
127
133
|
if (headless) {
|
|
128
134
|
window.addEventListener('message', hasNavigationToggle)
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
|
|
27
27
|
import type { FC } from 'react'
|
|
28
28
|
import React from 'react'
|
|
29
|
-
import { useHistory } from 'react-router-dom'
|
|
30
29
|
import { Markdown } from '@looker/code-editor'
|
|
31
30
|
import { useSelector } from 'react-redux'
|
|
32
31
|
import { getEnvAdaptor } from '@looker/extension-utils'
|
|
33
32
|
import { selectSearchPattern } from '../../state'
|
|
33
|
+
import { useNavigation } from '../../utils'
|
|
34
34
|
import { transformURL } from './utils'
|
|
35
35
|
|
|
36
36
|
interface DocMarkdownProps {
|
|
@@ -40,13 +40,13 @@ interface DocMarkdownProps {
|
|
|
40
40
|
|
|
41
41
|
export const DocMarkdown: FC<DocMarkdownProps> = ({ source, specKey }) => {
|
|
42
42
|
const searchPattern = useSelector(selectSearchPattern)
|
|
43
|
-
const
|
|
43
|
+
const navigate = useNavigation()
|
|
44
44
|
|
|
45
45
|
const linkClickHandler = (pathname: string, url: string) => {
|
|
46
46
|
if (pathname.startsWith(`/${specKey}`)) {
|
|
47
|
-
|
|
47
|
+
navigate(pathname)
|
|
48
48
|
} else if (url.startsWith(`/${specKey}`)) {
|
|
49
|
-
|
|
49
|
+
navigate(url)
|
|
50
50
|
} else if (url.startsWith('https://')) {
|
|
51
51
|
const adaptor = getEnvAdaptor()
|
|
52
52
|
adaptor.openBrowserWindow(url)
|
|
@@ -41,7 +41,7 @@ jest.mock('react-router-dom', () => {
|
|
|
41
41
|
useLocation: () => ({
|
|
42
42
|
pathname: '/4.0/methods/Dashboard/dashboard',
|
|
43
43
|
}),
|
|
44
|
-
useHistory: jest.fn().mockReturnValue({ push: jest.fn() }),
|
|
44
|
+
useHistory: jest.fn().mockReturnValue({ push: jest.fn(), location }),
|
|
45
45
|
}
|
|
46
46
|
})
|
|
47
47
|
|
|
@@ -83,6 +83,9 @@ describe('ApiSpecSelector', () => {
|
|
|
83
83
|
})
|
|
84
84
|
const button = screen.getByText('3.1')
|
|
85
85
|
userEvent.click(button)
|
|
86
|
-
expect(push).toHaveBeenCalledWith(
|
|
86
|
+
expect(push).toHaveBeenCalledWith({
|
|
87
|
+
pathname: '/3.1/methods/Dashboard/dashboard',
|
|
88
|
+
search: '',
|
|
89
|
+
})
|
|
87
90
|
})
|
|
88
91
|
})
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
import type { FC } from 'react'
|
|
28
28
|
import React from 'react'
|
|
29
29
|
import { Select } from '@looker/components'
|
|
30
|
-
import {
|
|
30
|
+
import { useLocation } from 'react-router-dom'
|
|
31
31
|
import type { SpecItem } from '@looker/sdk-codegen'
|
|
32
32
|
import { useSelector } from 'react-redux'
|
|
33
|
+
import { useNavigation } from '../../utils'
|
|
33
34
|
|
|
34
35
|
import { selectSpecs } from '../../state'
|
|
35
36
|
|
|
@@ -38,8 +39,8 @@ interface ApiSpecSelectorProps {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export const ApiSpecSelector: FC<ApiSpecSelectorProps> = ({ spec }) => {
|
|
41
|
-
const history = useHistory()
|
|
42
42
|
const location = useLocation()
|
|
43
|
+
const navigate = useNavigation()
|
|
43
44
|
const specs = useSelector(selectSpecs)
|
|
44
45
|
const options = Object.entries(specs).map(([key, spec]) => ({
|
|
45
46
|
value: key,
|
|
@@ -49,7 +50,7 @@ export const ApiSpecSelector: FC<ApiSpecSelectorProps> = ({ spec }) => {
|
|
|
49
50
|
|
|
50
51
|
const handleChange = (specKey: string) => {
|
|
51
52
|
const matchPath = location.pathname.replace(`/${spec.key}`, `/${specKey}`)
|
|
52
|
-
|
|
53
|
+
navigate(matchPath)
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
return (
|
|
@@ -29,7 +29,10 @@ import userEvent from '@testing-library/user-event'
|
|
|
29
29
|
import { screen, waitFor } from '@testing-library/react'
|
|
30
30
|
|
|
31
31
|
import { getLoadedSpecs } from '../../test-data'
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
createTestStore,
|
|
34
|
+
renderWithRouterAndReduxProvider,
|
|
35
|
+
} from '../../test-utils'
|
|
33
36
|
import { defaultSettingsState } from '../../state'
|
|
34
37
|
import { SideNav } from './SideNav'
|
|
35
38
|
import { countMethods, countTypes } from './searchUtils'
|
|
@@ -88,14 +91,45 @@ describe('SideNav', () => {
|
|
|
88
91
|
})
|
|
89
92
|
})
|
|
90
93
|
|
|
94
|
+
const mockHistoryPush = jest.fn()
|
|
95
|
+
jest.mock('react-router-dom', () => {
|
|
96
|
+
const ReactRouterDOM = jest.requireActual('react-router-dom')
|
|
97
|
+
return {
|
|
98
|
+
...ReactRouterDOM,
|
|
99
|
+
useHistory: () => ({
|
|
100
|
+
push: mockHistoryPush,
|
|
101
|
+
location,
|
|
102
|
+
}),
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
|
|
91
106
|
describe('Search', () => {
|
|
92
|
-
test('
|
|
93
|
-
renderWithRouterAndReduxProvider(<SideNav spec={spec}
|
|
107
|
+
test('inputting text in search box updates URL', async () => {
|
|
108
|
+
renderWithRouterAndReduxProvider(<SideNav spec={spec} />, ['/3.1/methods'])
|
|
94
109
|
const searchPattern = 'embedsso'
|
|
95
110
|
const input = screen.getByLabelText('Search')
|
|
96
|
-
jest.spyOn(spec.api!, 'search')
|
|
97
|
-
/** Pasting to avoid triggering search multiple times */
|
|
98
111
|
await userEvent.paste(input, searchPattern)
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(mockHistoryPush).toHaveBeenCalledWith({
|
|
114
|
+
pathname: '/3.1/methods',
|
|
115
|
+
search: `s=${searchPattern}`,
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('sets search default value from store on load', async () => {
|
|
121
|
+
const searchPattern = 'embedsso'
|
|
122
|
+
const store = createTestStore({
|
|
123
|
+
settings: { searchPattern: searchPattern },
|
|
124
|
+
})
|
|
125
|
+
jest.spyOn(spec.api!, 'search')
|
|
126
|
+
renderWithRouterAndReduxProvider(
|
|
127
|
+
<SideNav spec={spec} />,
|
|
128
|
+
['/3.1/methods?s=embedsso'],
|
|
129
|
+
store
|
|
130
|
+
)
|
|
131
|
+
const input = screen.getByLabelText('Search')
|
|
132
|
+
expect(input).toHaveValue(searchPattern)
|
|
99
133
|
await waitFor(() => {
|
|
100
134
|
expect(spec.api!.search).toHaveBeenCalledWith(
|
|
101
135
|
searchPattern,
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
import type { FC } from 'react'
|
|
28
28
|
import React, { useEffect, useState } from 'react'
|
|
29
|
-
import {
|
|
29
|
+
import { useLocation } from 'react-router-dom'
|
|
30
30
|
import {
|
|
31
31
|
TabList,
|
|
32
32
|
Tab,
|
|
@@ -44,10 +44,9 @@ import type {
|
|
|
44
44
|
} from '@looker/sdk-codegen'
|
|
45
45
|
import { criteriaToSet, tagTypes } from '@looker/sdk-codegen'
|
|
46
46
|
import { useSelector } from 'react-redux'
|
|
47
|
-
|
|
48
|
-
import { useWindowSize } from '../../utils'
|
|
47
|
+
import { useWindowSize, useNavigation } from '../../utils'
|
|
49
48
|
import { HEADER_REM } from '../Header'
|
|
50
|
-
import { selectSearchCriteria,
|
|
49
|
+
import { selectSearchCriteria, selectSearchPattern } from '../../state'
|
|
51
50
|
import { SideNavMethodTags } from './SideNavMethodTags'
|
|
52
51
|
import { SideNavTypeTags } from './SideNavTypeTags'
|
|
53
52
|
import { useDebounce, countMethods, countTypes } from './searchUtils'
|
|
@@ -68,8 +67,8 @@ interface SideNavProps {
|
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
export const SideNav: FC<SideNavProps> = ({ headless = false, spec }) => {
|
|
71
|
-
const history = useHistory()
|
|
72
70
|
const location = useLocation()
|
|
71
|
+
const navigate = useNavigation()
|
|
73
72
|
const specKey = spec.key
|
|
74
73
|
const tabNames = ['methods', 'types']
|
|
75
74
|
const pathParts = location.pathname.split('/')
|
|
@@ -83,20 +82,19 @@ export const SideNav: FC<SideNavProps> = ({ headless = false, spec }) => {
|
|
|
83
82
|
if (parts[1] === 'diff') {
|
|
84
83
|
if (parts[3] !== tabNames[index]) {
|
|
85
84
|
parts[3] = tabNames[index]
|
|
86
|
-
|
|
85
|
+
navigate(parts.join('/'))
|
|
87
86
|
}
|
|
88
87
|
} else {
|
|
89
88
|
if (parts[2] !== tabNames[index]) {
|
|
90
89
|
parts[2] = tabNames[index]
|
|
91
|
-
|
|
90
|
+
navigate(parts.join('/'))
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
const tabs = useTabs({ defaultIndex, onChange: onTabChange })
|
|
96
95
|
const searchCriteria = useSelector(selectSearchCriteria)
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
const [pattern, setSearchPattern] = useState('')
|
|
96
|
+
const searchPattern = useSelector(selectSearchPattern)
|
|
97
|
+
const [pattern, setSearchPattern] = useState(searchPattern)
|
|
100
98
|
const debouncedPattern = useDebounce(pattern, 250)
|
|
101
99
|
const [sideNavState, setSideNavState] = useState<SideNavState>(() => ({
|
|
102
100
|
tags: spec?.api?.tags || {},
|
|
@@ -111,6 +109,17 @@ export const SideNav: FC<SideNavProps> = ({ headless = false, spec }) => {
|
|
|
111
109
|
setSearchPattern(value)
|
|
112
110
|
}
|
|
113
111
|
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const searchParams = new URLSearchParams(location.search)
|
|
114
|
+
if (debouncedPattern && debouncedPattern !== searchParams.get('s')) {
|
|
115
|
+
searchParams.set('s', debouncedPattern)
|
|
116
|
+
navigate(location.pathname, { search: searchParams.toString() })
|
|
117
|
+
} else if (!debouncedPattern && searchParams.get('s')) {
|
|
118
|
+
searchParams.delete('s')
|
|
119
|
+
navigate(location.pathname, { search: searchParams.toString() })
|
|
120
|
+
}
|
|
121
|
+
}, [location.search, debouncedPattern])
|
|
122
|
+
|
|
114
123
|
useEffect(() => {
|
|
115
124
|
let results
|
|
116
125
|
let newTags
|
|
@@ -118,8 +127,8 @@ export const SideNav: FC<SideNavProps> = ({ headless = false, spec }) => {
|
|
|
118
127
|
let newTypeTags
|
|
119
128
|
const api = spec.api || ({} as ApiModel)
|
|
120
129
|
|
|
121
|
-
if (
|
|
122
|
-
results = api.search(
|
|
130
|
+
if (searchPattern && api.search) {
|
|
131
|
+
results = api.search(searchPattern, criteriaToSet(searchCriteria))
|
|
123
132
|
newTags = results.tags
|
|
124
133
|
newTypes = results.types
|
|
125
134
|
newTypeTags = tagTypes(api, results.types)
|
|
@@ -136,15 +145,7 @@ export const SideNav: FC<SideNavProps> = ({ headless = false, spec }) => {
|
|
|
136
145
|
methodCount: countMethods(newTags),
|
|
137
146
|
searchResults: results,
|
|
138
147
|
})
|
|
139
|
-
|
|
140
|
-
}, [
|
|
141
|
-
debouncedPattern,
|
|
142
|
-
specKey,
|
|
143
|
-
spec,
|
|
144
|
-
setSearchPatternAction,
|
|
145
|
-
pattern,
|
|
146
|
-
searchCriteria,
|
|
147
|
-
])
|
|
148
|
+
}, [searchPattern, specKey, spec, searchCriteria])
|
|
148
149
|
|
|
149
150
|
useEffect(() => {
|
|
150
151
|
const { selectedIndex, onSelectTab } = tabs
|
|
@@ -42,6 +42,7 @@ jest.mock('react-router-dom', () => {
|
|
|
42
42
|
...ReactRouterDOM,
|
|
43
43
|
useHistory: () => ({
|
|
44
44
|
push: mockHistoryPush,
|
|
45
|
+
location,
|
|
45
46
|
}),
|
|
46
47
|
}
|
|
47
48
|
})
|
|
@@ -71,7 +72,10 @@ describe('SideNavMethods', () => {
|
|
|
71
72
|
const firstMethod = Object.values(methods)[0].schema.summary
|
|
72
73
|
expect(screen.queryByText(firstMethod)).not.toBeInTheDocument()
|
|
73
74
|
userEvent.click(screen.getByText(tag))
|
|
74
|
-
expect(mockHistoryPush).toHaveBeenCalledWith(
|
|
75
|
+
expect(mockHistoryPush).toHaveBeenCalledWith({
|
|
76
|
+
pathname: `/${specKey}/methods/${tag}`,
|
|
77
|
+
search: '',
|
|
78
|
+
})
|
|
75
79
|
expect(screen.getByRole('link', { name: firstMethod })).toBeInTheDocument()
|
|
76
80
|
expect(screen.getAllByRole('link')).toHaveLength(
|
|
77
81
|
Object.values(methods).length
|
|
@@ -93,7 +97,10 @@ describe('SideNavMethods', () => {
|
|
|
93
97
|
Object.values(methods).length
|
|
94
98
|
)
|
|
95
99
|
userEvent.click(screen.getByText(tag))
|
|
96
|
-
expect(mockHistoryPush).toHaveBeenCalledWith(
|
|
100
|
+
expect(mockHistoryPush).toHaveBeenCalledWith({
|
|
101
|
+
pathname: `/${specKey}/methods`,
|
|
102
|
+
search: '',
|
|
103
|
+
})
|
|
97
104
|
expect(screen.queryByText(firstMethod)).not.toBeInTheDocument()
|
|
98
105
|
expect(screen.queryByRole('link')).not.toBeInTheDocument()
|
|
99
106
|
})
|
|
@@ -29,10 +29,9 @@ import styled from 'styled-components'
|
|
|
29
29
|
import { Accordion2, Heading } from '@looker/components'
|
|
30
30
|
import type { MethodList } from '@looker/sdk-codegen'
|
|
31
31
|
import { useSelector } from 'react-redux'
|
|
32
|
-
import {
|
|
33
|
-
|
|
32
|
+
import { useLocation, useRouteMatch } from 'react-router-dom'
|
|
33
|
+
import { useNavigation, highlightHTML, buildMethodPath } from '../../utils'
|
|
34
34
|
import { Link } from '../Link'
|
|
35
|
-
import { buildMethodPath, highlightHTML } from '../../utils'
|
|
36
35
|
import { selectSearchPattern } from '../../state'
|
|
37
36
|
|
|
38
37
|
interface MethodsProps {
|
|
@@ -45,20 +44,21 @@ interface MethodsProps {
|
|
|
45
44
|
|
|
46
45
|
export const SideNavMethods = styled(
|
|
47
46
|
({ className, methods, tag, specKey, defaultOpen = false }: MethodsProps) => {
|
|
47
|
+
const location = useLocation()
|
|
48
|
+
const navigate = useNavigation()
|
|
49
|
+
const searchParams = new URLSearchParams(location.search)
|
|
48
50
|
const searchPattern = useSelector(selectSearchPattern)
|
|
49
51
|
const match = useRouteMatch<{ methodTag: string }>(
|
|
50
52
|
`/:specKey/methods/:methodTag/:methodName?`
|
|
51
53
|
)
|
|
52
54
|
const [isOpen, setIsOpen] = useState(defaultOpen)
|
|
53
|
-
const history = useHistory()
|
|
54
|
-
|
|
55
55
|
const handleOpen = () => {
|
|
56
56
|
const _isOpen = !isOpen
|
|
57
57
|
setIsOpen(_isOpen)
|
|
58
58
|
if (_isOpen) {
|
|
59
|
-
|
|
59
|
+
navigate(`/${specKey}/methods/${tag}`)
|
|
60
60
|
} else {
|
|
61
|
-
|
|
61
|
+
navigate(`/${specKey}/methods`)
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -84,7 +84,14 @@ export const SideNavMethods = styled(
|
|
|
84
84
|
<ul>
|
|
85
85
|
{Object.values(methods).map((method) => (
|
|
86
86
|
<li key={method.name}>
|
|
87
|
-
<Link
|
|
87
|
+
<Link
|
|
88
|
+
to={`${buildMethodPath(
|
|
89
|
+
specKey,
|
|
90
|
+
tag,
|
|
91
|
+
method.name,
|
|
92
|
+
searchParams.toString()
|
|
93
|
+
)}`}
|
|
94
|
+
>
|
|
88
95
|
{highlightHTML(searchPattern, method.summary)}
|
|
89
96
|
</Link>
|
|
90
97
|
</li>
|
|
@@ -41,6 +41,7 @@ jest.mock('react-router-dom', () => {
|
|
|
41
41
|
...ReactRouterDOM,
|
|
42
42
|
useHistory: () => ({
|
|
43
43
|
push: mockHistoryPush,
|
|
44
|
+
location,
|
|
44
45
|
}),
|
|
45
46
|
}
|
|
46
47
|
})
|
|
@@ -63,7 +64,10 @@ describe('SideNavTypes', () => {
|
|
|
63
64
|
)
|
|
64
65
|
expect(screen.queryByText(typeTags[0])).not.toBeInTheDocument()
|
|
65
66
|
userEvent.click(screen.getByText(tag))
|
|
66
|
-
expect(mockHistoryPush).toHaveBeenCalledWith(
|
|
67
|
+
expect(mockHistoryPush).toHaveBeenCalledWith({
|
|
68
|
+
pathname: `/${specKey}/types/${tag}`,
|
|
69
|
+
search: '',
|
|
70
|
+
})
|
|
67
71
|
expect(screen.getByRole('link', { name: typeTags[0] })).toBeInTheDocument()
|
|
68
72
|
})
|
|
69
73
|
|
|
@@ -78,7 +82,10 @@ describe('SideNavTypes', () => {
|
|
|
78
82
|
)
|
|
79
83
|
expect(screen.getByRole('link', { name: typeTags[0] })).toBeInTheDocument()
|
|
80
84
|
userEvent.click(screen.getAllByText(tag)[0])
|
|
81
|
-
expect(mockHistoryPush).toHaveBeenCalledWith(
|
|
85
|
+
expect(mockHistoryPush).toHaveBeenCalledWith({
|
|
86
|
+
pathname: `/${specKey}/types`,
|
|
87
|
+
search: '',
|
|
88
|
+
})
|
|
82
89
|
expect(
|
|
83
90
|
screen.queryByRole('link', { name: typeTags[0] })
|
|
84
91
|
).not.toBeInTheDocument()
|
|
@@ -28,11 +28,10 @@ import React, { useEffect, useState } from 'react'
|
|
|
28
28
|
import styled from 'styled-components'
|
|
29
29
|
import { Accordion2, Heading } from '@looker/components'
|
|
30
30
|
import type { TypeList } from '@looker/sdk-codegen'
|
|
31
|
-
import {
|
|
31
|
+
import { useLocation, useRouteMatch } from 'react-router-dom'
|
|
32
32
|
import { useSelector } from 'react-redux'
|
|
33
|
-
|
|
34
33
|
import { Link } from '../Link'
|
|
35
|
-
import {
|
|
34
|
+
import { highlightHTML, useNavigation, buildTypePath } from '../../utils'
|
|
36
35
|
import { selectSearchPattern } from '../../state'
|
|
37
36
|
|
|
38
37
|
interface TypesProps {
|
|
@@ -45,20 +44,21 @@ interface TypesProps {
|
|
|
45
44
|
|
|
46
45
|
export const SideNavTypes = styled(
|
|
47
46
|
({ className, types, tag, specKey, defaultOpen = false }: TypesProps) => {
|
|
47
|
+
const location = useLocation()
|
|
48
|
+
const navigate = useNavigation()
|
|
49
|
+
const searchParams = new URLSearchParams(location.search)
|
|
48
50
|
const searchPattern = useSelector(selectSearchPattern)
|
|
49
51
|
const match = useRouteMatch<{ typeTag: string }>(
|
|
50
52
|
`/:specKey/types/:typeTag/:typeName?`
|
|
51
53
|
)
|
|
52
54
|
const [isOpen, setIsOpen] = useState(defaultOpen)
|
|
53
|
-
const history = useHistory()
|
|
54
|
-
|
|
55
55
|
const handleOpen = () => {
|
|
56
56
|
const _isOpen = !isOpen
|
|
57
57
|
setIsOpen(_isOpen)
|
|
58
58
|
if (_isOpen) {
|
|
59
|
-
|
|
59
|
+
navigate(`/${specKey}/types/${tag}`)
|
|
60
60
|
} else {
|
|
61
|
-
|
|
61
|
+
navigate(`/${specKey}/types`)
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -84,7 +84,14 @@ export const SideNavTypes = styled(
|
|
|
84
84
|
<ul>
|
|
85
85
|
{Object.values(types).map((type) => (
|
|
86
86
|
<li key={type.name}>
|
|
87
|
-
<Link
|
|
87
|
+
<Link
|
|
88
|
+
to={`${buildTypePath(
|
|
89
|
+
specKey,
|
|
90
|
+
tag,
|
|
91
|
+
type.name,
|
|
92
|
+
searchParams.toString()
|
|
93
|
+
)}`}
|
|
94
|
+
>
|
|
88
95
|
{highlightHTML(searchPattern, type.name)}
|
|
89
96
|
</Link>
|
|
90
97
|
</li>
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import type { FC } from 'react'
|
|
28
28
|
import React, { useState, useEffect } from 'react'
|
|
29
29
|
import type { ApiModel, DiffRow, SpecList } from '@looker/sdk-codegen'
|
|
30
|
-
import {
|
|
30
|
+
import { useRouteMatch } from 'react-router-dom'
|
|
31
31
|
import {
|
|
32
32
|
Box,
|
|
33
33
|
Flex,
|
|
@@ -42,7 +42,7 @@ import { useSelector } from 'react-redux'
|
|
|
42
42
|
|
|
43
43
|
import { ApixSection } from '../../components'
|
|
44
44
|
import { selectCurrentSpec } from '../../state'
|
|
45
|
-
import { diffPath, getApixAdaptor } from '../../utils'
|
|
45
|
+
import { diffPath, getApixAdaptor, useNavigation } from '../../utils'
|
|
46
46
|
import { diffSpecs, standardDiffToggles } from './diffUtils'
|
|
47
47
|
import { DocDiff } from './DocDiff'
|
|
48
48
|
|
|
@@ -84,7 +84,7 @@ const validateParam = (specs: SpecList, specKey = '') => {
|
|
|
84
84
|
|
|
85
85
|
export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
|
|
86
86
|
const adaptor = getApixAdaptor()
|
|
87
|
-
const
|
|
87
|
+
const navigate = useNavigation()
|
|
88
88
|
const spec = useSelector(selectCurrentSpec)
|
|
89
89
|
const currentSpecKey = spec.key
|
|
90
90
|
const match = useRouteMatch<{ l: string; r: string }>(`/${diffPath}/:l?/:r?`)
|
|
@@ -123,14 +123,14 @@ export const DiffScene: FC<DiffSceneProps> = ({ specs, toggleNavigation }) => {
|
|
|
123
123
|
const [delta, setDelta] = useState<DiffRow[]>([])
|
|
124
124
|
|
|
125
125
|
const handleLeftChange = (newLeft: string) => {
|
|
126
|
-
|
|
126
|
+
navigate(`/${diffPath}/${newLeft}/${rightKey}`)
|
|
127
127
|
}
|
|
128
128
|
const handleRightChange = (newRight: string) => {
|
|
129
|
-
|
|
129
|
+
navigate(`/${diffPath}/${leftKey}/${newRight}`)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
const handleSwitch = () => {
|
|
133
|
-
|
|
133
|
+
navigate(`/${diffPath}/${rightKey}/${leftKey}`)
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
useEffect(() => {
|
|
@@ -51,9 +51,10 @@ describe('DiffMethodLink', () => {
|
|
|
51
51
|
const link = screen.getByRole('link')
|
|
52
52
|
expect(link).toHaveTextContent(`${method.name} for ${specKey}`)
|
|
53
53
|
fireEvent.click(link)
|
|
54
|
-
expect(pushSpy).toHaveBeenCalledWith(
|
|
55
|
-
`/${specKey}/methods/${method.schema.tags[0]}/${method.name}
|
|
56
|
-
|
|
54
|
+
expect(pushSpy).toHaveBeenCalledWith({
|
|
55
|
+
pathname: `/${specKey}/methods/${method.schema.tags[0]}/${method.name}`,
|
|
56
|
+
search: '',
|
|
57
|
+
})
|
|
57
58
|
})
|
|
58
59
|
|
|
59
60
|
test('it renders missing method and does not navigate on click', () => {
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import type { FC } from 'react'
|
|
27
27
|
import React, { useState, useEffect } from 'react'
|
|
28
|
-
import { useHistory } from 'react-router'
|
|
29
28
|
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer'
|
|
30
29
|
import styled from 'styled-components'
|
|
31
30
|
import { Accordion2, Box, Card, Grid, Heading, Link } from '@looker/components'
|
|
@@ -33,7 +32,7 @@ import type { DiffRow } from '@looker/sdk-codegen/src'
|
|
|
33
32
|
import type { ApiModel, IMethod } from '@looker/sdk-codegen'
|
|
34
33
|
import { useSelector } from 'react-redux'
|
|
35
34
|
import { selectSdkLanguage } from '../../../state'
|
|
36
|
-
import { buildMethodPath } from '../../../utils'
|
|
35
|
+
import { buildMethodPath, useNavigation } from '../../../utils'
|
|
37
36
|
import { DiffBanner } from './DiffBanner'
|
|
38
37
|
import { differ } from './docDiffUtils'
|
|
39
38
|
|
|
@@ -60,7 +59,7 @@ export const DiffMethodLink: FC<DiffMethodLinkProps> = ({
|
|
|
60
59
|
method,
|
|
61
60
|
specKey,
|
|
62
61
|
}) => {
|
|
63
|
-
const
|
|
62
|
+
const navigate = useNavigation()
|
|
64
63
|
|
|
65
64
|
if (!method) return <Heading as="h4">{`Missing in ${specKey}`}</Heading>
|
|
66
65
|
|
|
@@ -71,7 +70,7 @@ export const DiffMethodLink: FC<DiffMethodLinkProps> = ({
|
|
|
71
70
|
<DiffLink
|
|
72
71
|
role="link"
|
|
73
72
|
onClick={() => {
|
|
74
|
-
|
|
73
|
+
navigate(path)
|
|
75
74
|
}}
|
|
76
75
|
>{`${method.name} for ${specKey}`}</DiffLink>
|
|
77
76
|
)
|
|
@@ -42,7 +42,7 @@ import { typeRefs } from '@looker/sdk-codegen'
|
|
|
42
42
|
import { useSelector } from 'react-redux'
|
|
43
43
|
import type { IEnvironmentAdaptor } from '@looker/extension-utils'
|
|
44
44
|
|
|
45
|
-
import { getApixAdaptor } from '../../utils'
|
|
45
|
+
import { getApixAdaptor, useNavigation } from '../../utils'
|
|
46
46
|
import {
|
|
47
47
|
ApixSection,
|
|
48
48
|
DocActivityType,
|
|
@@ -78,6 +78,7 @@ const showRunIt = async (adaptor: IEnvironmentAdaptor) => {
|
|
|
78
78
|
export const MethodScene: FC<MethodSceneProps> = ({ api }) => {
|
|
79
79
|
const adaptor = getApixAdaptor()
|
|
80
80
|
const history = useHistory()
|
|
81
|
+
const navigate = useNavigation()
|
|
81
82
|
const sdkLanguage = useSelector(selectSdkLanguage)
|
|
82
83
|
const { specKey, methodTag, methodName } = useParams<MethodSceneParams>()
|
|
83
84
|
const { value, toggle, setOn } = useToggle()
|
|
@@ -94,9 +95,9 @@ export const MethodScene: FC<MethodSceneProps> = ({ api }) => {
|
|
|
94
95
|
// Invalid method
|
|
95
96
|
if (api.tags[methodTag]) {
|
|
96
97
|
// Found tag though
|
|
97
|
-
|
|
98
|
+
navigate(`/${specKey}/methods/${methodTag}`)
|
|
98
99
|
} else {
|
|
99
|
-
|
|
100
|
+
navigate(`/${specKey}/methods`)
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
}, [api, history, methodName, methodTag, specKey])
|
|
@@ -29,7 +29,7 @@ import { useHistory, useParams } from 'react-router-dom'
|
|
|
29
29
|
import { Grid, ButtonToggle, ButtonItem } from '@looker/components'
|
|
30
30
|
import type { ApiModel } from '@looker/sdk-codegen'
|
|
31
31
|
import { ApixSection, DocTitle, DocMethodSummary, Link } from '../../components'
|
|
32
|
-
import { buildMethodPath } from '../../utils'
|
|
32
|
+
import { buildMethodPath, useNavigation } from '../../utils'
|
|
33
33
|
import { getOperations } from './utils'
|
|
34
34
|
|
|
35
35
|
interface MethodTagSceneProps {
|
|
@@ -44,6 +44,7 @@ interface MethodTagSceneParams {
|
|
|
44
44
|
export const MethodTagScene: FC<MethodTagSceneProps> = ({ api }) => {
|
|
45
45
|
const { specKey, methodTag } = useParams<MethodTagSceneParams>()
|
|
46
46
|
const history = useHistory()
|
|
47
|
+
const navigate = useNavigation()
|
|
47
48
|
const [value, setValue] = useState('ALL')
|
|
48
49
|
|
|
49
50
|
useEffect(() => {
|
|
@@ -54,7 +55,7 @@ export const MethodTagScene: FC<MethodTagSceneProps> = ({ api }) => {
|
|
|
54
55
|
const methods = api.tags[methodTag]
|
|
55
56
|
useEffect(() => {
|
|
56
57
|
if (!methods) {
|
|
57
|
-
|
|
58
|
+
navigate(`/${specKey}/methods`)
|
|
58
59
|
}
|
|
59
60
|
}, [history, methods])
|
|
60
61
|
if (!methods) {
|
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
ExploreType,
|
|
41
41
|
DocSchema,
|
|
42
42
|
} from '../../components'
|
|
43
|
+
import { useNavigation } from '../../utils'
|
|
43
44
|
|
|
44
45
|
interface DocTypeProps {
|
|
45
46
|
api: ApiModel
|
|
@@ -47,19 +48,24 @@ interface DocTypeProps {
|
|
|
47
48
|
|
|
48
49
|
interface DocTypeParams {
|
|
49
50
|
specKey: string
|
|
51
|
+
typeTag: string
|
|
50
52
|
typeName: string
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export const TypeScene: FC<DocTypeProps> = ({ api }) => {
|
|
54
|
-
const { specKey, typeName } = useParams<DocTypeParams>()
|
|
56
|
+
const { specKey, typeTag, typeName } = useParams<DocTypeParams>()
|
|
55
57
|
const type = api.types[typeName]
|
|
56
58
|
const history = useHistory()
|
|
59
|
+
const navigate = useNavigation()
|
|
57
60
|
const typesUsed = typeRefs(api, type?.customTypes)
|
|
58
61
|
const methodsUsedBy = methodRefs(api, type?.methodRefs)
|
|
59
62
|
const typesUsedBy = typeRefs(api, type?.parentTypes)
|
|
60
63
|
useEffect(() => {
|
|
61
64
|
if (!type) {
|
|
62
|
-
|
|
65
|
+
const route = api.typeTags[typeTag]
|
|
66
|
+
? `/${specKey}/types/${typeTag}`
|
|
67
|
+
: `/${specKey}/types`
|
|
68
|
+
navigate(route)
|
|
63
69
|
}
|
|
64
70
|
}, [history, specKey, type])
|
|
65
71
|
|
|
@@ -27,9 +27,9 @@ import type { FC } from 'react'
|
|
|
27
27
|
import React, { useEffect, useState } from 'react'
|
|
28
28
|
import { Grid, ButtonToggle, ButtonItem } from '@looker/components'
|
|
29
29
|
import type { ApiModel } from '@looker/sdk-codegen'
|
|
30
|
-
import { useParams
|
|
30
|
+
import { useParams } from 'react-router-dom'
|
|
31
31
|
import { ApixSection, DocTitle, DocTypeSummary, Link } from '../../components'
|
|
32
|
-
import { buildTypePath } from '../../utils'
|
|
32
|
+
import { buildTypePath, useNavigation } from '../../utils'
|
|
33
33
|
import { getMetaTypes } from './utils'
|
|
34
34
|
|
|
35
35
|
interface TypeTagSceneProps {
|
|
@@ -43,7 +43,7 @@ interface TypeTagSceneParams {
|
|
|
43
43
|
|
|
44
44
|
export const TypeTagScene: FC<TypeTagSceneProps> = ({ api }) => {
|
|
45
45
|
const { specKey, typeTag } = useParams<TypeTagSceneParams>()
|
|
46
|
-
const
|
|
46
|
+
const navigate = useNavigation()
|
|
47
47
|
const [value, setValue] = useState('ALL')
|
|
48
48
|
|
|
49
49
|
useEffect(() => {
|
|
@@ -54,9 +54,9 @@ export const TypeTagScene: FC<TypeTagSceneProps> = ({ api }) => {
|
|
|
54
54
|
const types = api.typeTags[typeTag]
|
|
55
55
|
useEffect(() => {
|
|
56
56
|
if (!types) {
|
|
57
|
-
|
|
57
|
+
navigate(`/${specKey}/types`)
|
|
58
58
|
}
|
|
59
|
-
}, [
|
|
59
|
+
}, [types])
|
|
60
60
|
|
|
61
61
|
if (!types) {
|
|
62
62
|
return <></>
|