@looker/api-explorer 0.9.26 → 0.9.27
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 +47 -1
- package/e2e/e2e.spec.ts +1 -1
- package/lib/ApiExplorer.d.ts +2 -6
- package/lib/ApiExplorer.js +53 -74
- package/lib/ApiExplorer.js.map +1 -1
- package/lib/StandaloneApiExplorer.js +35 -47
- package/lib/StandaloneApiExplorer.js.map +1 -1
- package/lib/components/Banner/Banner.d.ts +8 -0
- package/lib/components/Banner/Banner.js +70 -0
- package/lib/components/Banner/Banner.js.map +1 -0
- package/lib/components/Banner/index.d.ts +1 -0
- package/lib/components/Banner/index.js +14 -0
- package/lib/components/Banner/index.js.map +1 -0
- package/lib/components/DocSDKs/DocSDKs.js +3 -3
- package/lib/components/DocSDKs/DocSDKs.js.map +1 -1
- package/lib/components/ExploreType/ExploreType.js +3 -5
- package/lib/components/ExploreType/ExploreType.js.map +1 -1
- package/lib/components/Header/Header.d.ts +2 -5
- package/lib/components/Header/Header.js +1 -5
- package/lib/components/Header/Header.js.map +1 -1
- package/lib/components/SelectorContainer/ApiSpecSelector.d.ts +2 -5
- package/lib/components/SelectorContainer/ApiSpecSelector.js +5 -5
- package/lib/components/SelectorContainer/ApiSpecSelector.js.map +1 -1
- package/lib/components/SelectorContainer/SelectorContainer.d.ts +2 -5
- package/lib/components/SelectorContainer/SelectorContainer.js +3 -7
- package/lib/components/SelectorContainer/SelectorContainer.js.map +1 -1
- package/lib/components/SideNav/SideNav.d.ts +2 -5
- package/lib/components/SideNav/SideNav.js.map +1 -1
- package/lib/components/index.d.ts +1 -0
- package/lib/components/index.js +8 -0
- package/lib/components/index.js.map +1 -1
- package/lib/esm/ApiExplorer.js +54 -74
- package/lib/esm/ApiExplorer.js.map +1 -1
- package/lib/esm/StandaloneApiExplorer.js +34 -48
- package/lib/esm/StandaloneApiExplorer.js.map +1 -1
- package/lib/esm/components/Banner/Banner.js +54 -0
- package/lib/esm/components/Banner/Banner.js.map +1 -0
- package/lib/esm/components/Banner/index.js +2 -0
- package/lib/esm/components/Banner/index.js.map +1 -0
- package/lib/esm/components/DocSDKs/DocSDKs.js +2 -2
- package/lib/esm/components/DocSDKs/DocSDKs.js.map +1 -1
- package/lib/esm/components/ExploreType/ExploreType.js +3 -4
- package/lib/esm/components/ExploreType/ExploreType.js.map +1 -1
- package/lib/esm/components/Header/Header.js +1 -5
- package/lib/esm/components/Header/Header.js.map +1 -1
- package/lib/esm/components/SelectorContainer/ApiSpecSelector.js +4 -5
- package/lib/esm/components/SelectorContainer/ApiSpecSelector.js.map +1 -1
- package/lib/esm/components/SelectorContainer/SelectorContainer.js +3 -7
- package/lib/esm/components/SelectorContainer/SelectorContainer.js.map +1 -1
- package/lib/esm/components/SideNav/SideNav.js.map +1 -1
- package/lib/esm/components/index.js +1 -0
- package/lib/esm/components/index.js.map +1 -1
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/routes/AppRouter.js +3 -7
- package/lib/esm/routes/AppRouter.js.map +1 -1
- package/lib/esm/scenes/DiffScene/DiffScene.js +43 -99
- package/lib/esm/scenes/DiffScene/DiffScene.js.map +1 -1
- package/lib/esm/scenes/DiffScene/DocDiff/DiffItem.js +9 -13
- package/lib/esm/scenes/DiffScene/DocDiff/DiffItem.js.map +1 -1
- package/lib/esm/scenes/DiffScene/DocDiff/DocDiff.js +2 -2
- package/lib/esm/scenes/DiffScene/DocDiff/DocDiff.js.map +1 -1
- package/lib/esm/scenes/MethodScene/MethodScene.js +4 -5
- package/lib/esm/scenes/MethodScene/MethodScene.js.map +1 -1
- package/lib/esm/state/index.js +1 -0
- package/lib/esm/state/index.js.map +1 -1
- package/lib/esm/state/specs/index.js +3 -0
- package/lib/esm/state/specs/index.js.map +1 -0
- package/lib/esm/state/specs/sagas.js +58 -0
- package/lib/esm/state/specs/sagas.js.map +1 -0
- package/lib/esm/state/specs/selectors.js +8 -0
- package/lib/esm/state/specs/selectors.js.map +1 -0
- package/lib/esm/state/specs/slice.js +55 -0
- package/lib/esm/state/specs/slice.js.map +1 -0
- package/lib/esm/state/store.js +53 -2
- package/lib/esm/state/store.js.map +1 -1
- package/lib/esm/test-utils/redux.js +9 -5
- package/lib/esm/test-utils/redux.js.map +1 -1
- package/lib/esm/utils/adaptorUtils.js +101 -0
- package/lib/esm/utils/adaptorUtils.js.map +1 -0
- package/lib/esm/utils/apixAdaptor.js +48 -0
- package/lib/esm/utils/apixAdaptor.js.map +1 -0
- package/lib/esm/utils/index.js +3 -1
- package/lib/esm/utils/index.js.map +1 -1
- package/lib/esm/utils/path.js +27 -2
- package/lib/esm/utils/path.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -1
- package/lib/routes/AppRouter.d.ts +1 -5
- package/lib/routes/AppRouter.js +3 -7
- package/lib/routes/AppRouter.js.map +1 -1
- package/lib/scenes/DiffScene/DiffScene.js +45 -100
- package/lib/scenes/DiffScene/DiffScene.js.map +1 -1
- package/lib/scenes/DiffScene/DocDiff/DiffItem.js +9 -13
- package/lib/scenes/DiffScene/DocDiff/DiffItem.js.map +1 -1
- package/lib/scenes/DiffScene/DocDiff/DocDiff.js +2 -2
- package/lib/scenes/DiffScene/DocDiff/DocDiff.js.map +1 -1
- package/lib/scenes/MethodScene/MethodScene.d.ts +0 -4
- package/lib/scenes/MethodScene/MethodScene.js +5 -5
- package/lib/scenes/MethodScene/MethodScene.js.map +1 -1
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +13 -0
- package/lib/state/index.js.map +1 -1
- package/lib/state/settings/selectors.d.ts +1 -1
- package/lib/state/settings/slice.d.ts +1 -1
- package/lib/state/specs/index.d.ts +2 -0
- package/lib/state/specs/index.js +32 -0
- package/lib/state/specs/index.js.map +1 -0
- package/lib/state/specs/sagas.d.ts +1 -0
- package/lib/state/specs/sagas.js +67 -0
- package/lib/state/specs/sagas.js.map +1 -0
- package/lib/state/specs/selectors.d.ts +4 -0
- package/lib/state/specs/selectors.js +20 -0
- package/lib/state/specs/selectors.js.map +1 -0
- package/lib/state/specs/slice.d.ts +49 -0
- package/lib/state/specs/slice.js +70 -0
- package/lib/state/specs/slice.js.map +1 -0
- package/lib/state/store.d.ts +3 -0
- package/lib/state/store.js +56 -2
- package/lib/state/store.js.map +1 -1
- package/lib/test-data/declarations.d.ts +2 -0
- package/lib/test-data/examples.d.ts +2 -0
- package/lib/test-data/index.d.ts +3 -0
- package/lib/test-data/index.js +12 -42
- package/lib/test-data/index.js.map +1 -1
- package/lib/test-data/specs.d.ts +10 -0
- package/lib/test-data/specs.js +6 -6
- package/lib/test-data/specs.js.map +1 -1
- package/lib/test-utils/redux.d.ts +2 -1
- package/lib/test-utils/redux.js +9 -4
- package/lib/test-utils/redux.js.map +1 -1
- package/lib/utils/adaptorUtils.d.ts +30 -0
- package/lib/utils/adaptorUtils.js +124 -0
- package/lib/utils/adaptorUtils.js.map +1 -0
- package/lib/utils/apixAdaptor.d.ts +15 -0
- package/lib/utils/apixAdaptor.js +67 -0
- package/lib/utils/apixAdaptor.js.map +1 -0
- package/lib/utils/index.d.ts +3 -1
- package/lib/utils/index.js +45 -30
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/path.d.ts +3 -0
- package/lib/utils/path.js +32 -2
- package/lib/utils/path.js.map +1 -1
- package/package.json +10 -10
- package/src/ApiExplorer.tsx +47 -74
- package/src/StandaloneApiExplorer.tsx +37 -52
- package/src/components/Banner/Banner.spec.tsx +99 -0
- package/src/components/Banner/Banner.tsx +87 -0
- package/src/{reducers → components/Banner}/index.ts +1 -1
- package/src/components/DocSDKs/DocSDKs.tsx +4 -5
- package/src/components/ExploreType/ExploreType.spec.tsx +0 -23
- package/src/components/ExploreType/ExploreType.tsx +5 -6
- package/src/components/ExploreType/exploreUtils.spec.tsx +1 -1
- package/src/components/Header/Header.spec.tsx +9 -30
- package/src/components/Header/Header.tsx +3 -10
- package/src/components/SelectorContainer/ApiSpecSelector.spec.tsx +31 -44
- package/src/components/SelectorContainer/ApiSpecSelector.tsx +6 -12
- package/src/components/SelectorContainer/SelectorContainer.spec.tsx +7 -26
- package/src/components/SelectorContainer/SelectorContainer.tsx +4 -10
- package/src/components/SideNav/SideNav.spec.tsx +12 -45
- package/src/components/SideNav/SideNav.tsx +1 -7
- package/src/components/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/routes/AppRouter.tsx +25 -37
- package/src/scenes/DiffScene/DiffScene.tsx +47 -84
- package/src/scenes/DiffScene/DocDiff/DiffItem.spec.tsx +9 -16
- package/src/scenes/DiffScene/DocDiff/DiffItem.tsx +11 -12
- package/src/scenes/DiffScene/DocDiff/DocDiff.tsx +2 -2
- package/src/scenes/MethodScene/MethodScene.tsx +4 -10
- package/src/state/index.ts +1 -0
- package/src/{reducers/spec → state/specs}/index.ts +2 -3
- package/src/state/specs/sagas.spec.ts +135 -0
- package/src/state/specs/sagas.ts +81 -0
- package/src/{reducers/spec/actions.spec.ts → state/specs/selectors.ts} +12 -11
- package/src/state/specs/slice.ts +109 -0
- package/src/state/store.ts +58 -0
- package/src/test-data/index.ts +1 -8
- package/src/test-data/specs.ts +6 -6
- package/src/test-utils/redux.tsx +15 -4
- package/src/utils/adaptorUtils.ts +181 -0
- package/src/utils/apixAdaptor.ts +72 -0
- package/src/utils/index.ts +3 -7
- package/src/utils/path.ts +25 -2
- package/lib/esm/reducers/index.js +0 -2
- package/lib/esm/reducers/index.js.map +0 -1
- package/lib/esm/reducers/spec/actions.js +0 -19
- package/lib/esm/reducers/spec/actions.js.map +0 -1
- package/lib/esm/reducers/spec/index.js +0 -4
- package/lib/esm/reducers/spec/index.js.map +0 -1
- package/lib/esm/reducers/spec/reducer.js +0 -62
- package/lib/esm/reducers/spec/reducer.js.map +0 -1
- package/lib/esm/reducers/spec/utils.js +0 -74
- package/lib/esm/reducers/spec/utils.js.map +0 -1
- package/lib/reducers/index.d.ts +0 -1
- package/lib/reducers/index.js +0 -19
- package/lib/reducers/index.js.map +0 -1
- package/lib/reducers/spec/actions.d.ts +0 -20
- package/lib/reducers/spec/actions.js +0 -31
- package/lib/reducers/spec/actions.js.map +0 -1
- package/lib/reducers/spec/index.d.ts +0 -3
- package/lib/reducers/spec/index.js +0 -45
- package/lib/reducers/spec/index.js.map +0 -1
- package/lib/reducers/spec/reducer.d.ts +0 -7
- package/lib/reducers/spec/reducer.js +0 -73
- package/lib/reducers/spec/reducer.js.map +0 -1
- package/lib/reducers/spec/utils.d.ts +0 -7
- package/lib/reducers/spec/utils.js +0 -91
- package/lib/reducers/spec/utils.js.map +0 -1
- package/src/reducers/spec/actions.ts +0 -62
- package/src/reducers/spec/reducer.spec.ts +0 -44
- package/src/reducers/spec/reducer.ts +0 -69
- package/src/reducers/spec/utils.spec.ts +0 -138
- package/src/reducers/spec/utils.ts +0 -123
|
@@ -26,19 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
import type { FC } from 'react'
|
|
28
28
|
import React, { useEffect, useState } from 'react'
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
RunItConfigKey,
|
|
33
|
-
RunItNoConfig,
|
|
34
|
-
initRunItSdk,
|
|
35
|
-
} from '@looker/run-it'
|
|
36
|
-
import type { SpecList } from '@looker/sdk-codegen'
|
|
29
|
+
import { initRunItSdk, RunItProvider } from '@looker/run-it'
|
|
30
|
+
import type { OAuthConfigProvider } from '@looker/extension-utils'
|
|
31
|
+
import { OAuthScene } from '@looker/extension-utils'
|
|
37
32
|
import { Provider } from 'react-redux'
|
|
38
|
-
import {
|
|
33
|
+
import { useLocation } from 'react-router'
|
|
39
34
|
|
|
40
35
|
import { ApiExplorer } from './ApiExplorer'
|
|
41
36
|
import { store } from './state'
|
|
37
|
+
import { oAuthPath, ApixAdaptor } from './utils'
|
|
42
38
|
import { Loader } from './components'
|
|
43
39
|
|
|
44
40
|
export interface StandaloneApiExplorerProps {
|
|
@@ -46,59 +42,48 @@ export interface StandaloneApiExplorerProps {
|
|
|
46
42
|
versionsUrl: string
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
const browserAdaptor = new BrowserAdaptor(initRunItSdk())
|
|
50
|
-
|
|
51
|
-
const loadVersions = async (current: string) => {
|
|
52
|
-
const data = await browserAdaptor.localStorageGetItem(RunItConfigKey)
|
|
53
|
-
const config = data ? JSON.parse(data) : RunItNoConfig
|
|
54
|
-
let url = config.base_url ? `${config.base_url}/versions` : current
|
|
55
|
-
let response = await loadSpecsFromVersions(url)
|
|
56
|
-
if (response.fetchResult) {
|
|
57
|
-
console.error(
|
|
58
|
-
`Reverting to ${current} due to ${url} error: ${response.fetchResult}`
|
|
59
|
-
)
|
|
60
|
-
// The stored server location has an error so default to current
|
|
61
|
-
url = current
|
|
62
|
-
response = await loadSpecsFromVersions(url)
|
|
63
|
-
}
|
|
64
|
-
return { url, response }
|
|
65
|
-
}
|
|
66
|
-
|
|
67
45
|
export const StandaloneApiExplorer: FC<StandaloneApiExplorerProps> = ({
|
|
68
46
|
headless = false,
|
|
69
|
-
versionsUrl = '',
|
|
70
47
|
}) => {
|
|
71
|
-
const [
|
|
72
|
-
|
|
73
|
-
|
|
48
|
+
const [browserAdaptor] = useState(
|
|
49
|
+
new ApixAdaptor(initRunItSdk(), window.origin)
|
|
50
|
+
)
|
|
51
|
+
const location = useLocation()
|
|
52
|
+
const oauthReturn = location.pathname === `/${oAuthPath}`
|
|
53
|
+
const sdk = browserAdaptor.sdk
|
|
54
|
+
const canLogin =
|
|
55
|
+
(sdk.authSession.settings as OAuthConfigProvider).authIsConfigured() &&
|
|
56
|
+
!sdk.authSession.isAuthenticated() &&
|
|
57
|
+
!oauthReturn
|
|
74
58
|
|
|
75
59
|
useEffect(() => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const response = result.response
|
|
80
|
-
setSpecs(response.specs)
|
|
81
|
-
})
|
|
82
|
-
} else {
|
|
83
|
-
setSpecs(undefined)
|
|
60
|
+
const login = async () => await browserAdaptor.login()
|
|
61
|
+
if (canLogin) {
|
|
62
|
+
login()
|
|
84
63
|
}
|
|
85
|
-
}, [
|
|
64
|
+
}, [])
|
|
65
|
+
|
|
66
|
+
const { looker_url } = (
|
|
67
|
+
sdk.authSession.settings as OAuthConfigProvider
|
|
68
|
+
).getStoredConfig()
|
|
86
69
|
|
|
87
70
|
return (
|
|
88
71
|
<Provider store={store}>
|
|
89
72
|
<RunItProvider basePath="/api/4.0">
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
73
|
+
{canLogin ? (
|
|
74
|
+
<Loader
|
|
75
|
+
themeOverrides={browserAdaptor.themeOverrides()}
|
|
76
|
+
message={`Configuration found. Logging into ${looker_url}`}
|
|
77
|
+
/>
|
|
78
|
+
) : (
|
|
79
|
+
<>
|
|
80
|
+
{oauthReturn ? (
|
|
81
|
+
<OAuthScene adaptor={browserAdaptor} />
|
|
82
|
+
) : (
|
|
83
|
+
<ApiExplorer adaptor={browserAdaptor} headless={headless} />
|
|
84
|
+
)}
|
|
85
|
+
</>
|
|
86
|
+
)}
|
|
102
87
|
</RunItProvider>
|
|
103
88
|
</Provider>
|
|
104
89
|
)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2021 Looker Data Sciences, Inc.
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
24
|
+
|
|
25
|
+
*/
|
|
26
|
+
import React from 'react'
|
|
27
|
+
import { renderWithTheme } from '@looker/components-test-utils'
|
|
28
|
+
import { screen, fireEvent, waitFor } from '@testing-library/react'
|
|
29
|
+
import type { IEnvironmentAdaptor } from '@looker/extension-utils'
|
|
30
|
+
import type { SpecList } from '@looker/sdk-codegen'
|
|
31
|
+
import { Banner } from './Banner'
|
|
32
|
+
|
|
33
|
+
describe('Banner', () => {
|
|
34
|
+
const specs: any = {
|
|
35
|
+
'3.1': {
|
|
36
|
+
status: 'current',
|
|
37
|
+
},
|
|
38
|
+
'4.0': {
|
|
39
|
+
status: 'beta',
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
test('renders with button that opens api 4.0 dev portal link in new page', async () => {
|
|
44
|
+
const adaptor: any = {
|
|
45
|
+
localStorageGetItem: jest.fn().mockReturnValue(Promise.resolve(null)),
|
|
46
|
+
isExtension: jest.fn().mockReturnValue(true),
|
|
47
|
+
}
|
|
48
|
+
renderWithTheme(
|
|
49
|
+
<Banner
|
|
50
|
+
adaptor={adaptor as IEnvironmentAdaptor}
|
|
51
|
+
specs={specs as SpecList}
|
|
52
|
+
/>
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(
|
|
57
|
+
screen.getByText('API 4.0 moves from Beta', { exact: false })
|
|
58
|
+
).toBeInTheDocument()
|
|
59
|
+
const link = screen.getByText('Announcement').closest('a')
|
|
60
|
+
expect(link).toHaveAttribute(
|
|
61
|
+
'href',
|
|
62
|
+
'https://developers.looker.com/api/advanced-usage/version-4-ga'
|
|
63
|
+
)
|
|
64
|
+
expect(link).toHaveAttribute('target', '_blank')
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('sets local storage value and unrenders on close button click', async () => {
|
|
69
|
+
const adaptor: any = {
|
|
70
|
+
localStorageGetItem: jest.fn().mockReturnValue(Promise.resolve(null)),
|
|
71
|
+
localStorageSetItem: jest.fn(),
|
|
72
|
+
isExtension: jest.fn().mockReturnValue(true),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
renderWithTheme(
|
|
76
|
+
<Banner
|
|
77
|
+
adaptor={adaptor as IEnvironmentAdaptor}
|
|
78
|
+
specs={specs as SpecList}
|
|
79
|
+
/>
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
await waitFor(() => {
|
|
83
|
+
expect(
|
|
84
|
+
screen.getByText('API 4.0 moves from Beta', { exact: false })
|
|
85
|
+
).toBeInTheDocument()
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const closeButton = screen.getByText('Dismiss Inform').closest('button')
|
|
89
|
+
fireEvent.click(closeButton as HTMLButtonElement)
|
|
90
|
+
|
|
91
|
+
expect(
|
|
92
|
+
screen.queryByText('API 4.0 moves from Beta', { exact: false })
|
|
93
|
+
).not.toBeInTheDocument()
|
|
94
|
+
expect(adaptor.localStorageSetItem).toHaveBeenCalledWith(
|
|
95
|
+
'api-40-ga-apix-banner',
|
|
96
|
+
'dismissed'
|
|
97
|
+
)
|
|
98
|
+
})
|
|
99
|
+
})
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2021 Looker Data Sciences, Inc.
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
24
|
+
|
|
25
|
+
*/
|
|
26
|
+
import { ButtonOutline, Link, MessageBar } from '@looker/components'
|
|
27
|
+
import type { IEnvironmentAdaptor } from '@looker/extension-utils'
|
|
28
|
+
import type { SpecList } from '@looker/sdk-codegen'
|
|
29
|
+
import type { FC } from 'react'
|
|
30
|
+
import React, { useState, useEffect } from 'react'
|
|
31
|
+
|
|
32
|
+
const LOCAL_STORAGE_KEY = 'api-40-ga-apix-banner'
|
|
33
|
+
const LOCAL_STORAGE_VALUE = 'dismissed'
|
|
34
|
+
|
|
35
|
+
export interface BannerProps {
|
|
36
|
+
adaptor: IEnvironmentAdaptor
|
|
37
|
+
specs: SpecList
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const Banner: FC<BannerProps> = ({ adaptor, specs }) => {
|
|
41
|
+
const [isOpen, setOpen] = useState(false)
|
|
42
|
+
useEffect(onLoad, [])
|
|
43
|
+
|
|
44
|
+
if (isOpen) {
|
|
45
|
+
return (
|
|
46
|
+
<MessageBar
|
|
47
|
+
intent="inform"
|
|
48
|
+
onPrimaryClick={onClose}
|
|
49
|
+
secondaryAction={
|
|
50
|
+
<Link
|
|
51
|
+
href="https://developers.looker.com/api/advanced-usage/version-4-ga"
|
|
52
|
+
target="_blank"
|
|
53
|
+
>
|
|
54
|
+
<ButtonOutline size="small">Announcement</ButtonOutline>
|
|
55
|
+
</Link>
|
|
56
|
+
}
|
|
57
|
+
>
|
|
58
|
+
API 4.0 moves from Beta to General Availability in Looker 22.4 with
|
|
59
|
+
additions and possible breaking changes. Read the announcement to see
|
|
60
|
+
how this affects you.
|
|
61
|
+
</MessageBar>
|
|
62
|
+
)
|
|
63
|
+
} else {
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function onLoad() {
|
|
68
|
+
// Following best practice with inner async function
|
|
69
|
+
// https://github.com/facebook/react/issues/14326
|
|
70
|
+
async function innerOnLoad() {
|
|
71
|
+
// 4.0 is stable in Looker 22.4+. 4.0 is default or `current` in 22.4+.
|
|
72
|
+
// Still check for `stable` just in case new version comes along.
|
|
73
|
+
const is40Stable =
|
|
74
|
+
specs['4.0'].status === 'stable' || specs['4.0'].status === 'current'
|
|
75
|
+
const wasDismissed =
|
|
76
|
+
(await adaptor.localStorageGetItem(LOCAL_STORAGE_KEY)) ===
|
|
77
|
+
LOCAL_STORAGE_VALUE
|
|
78
|
+
setOpen(!is40Stable && !wasDismissed && adaptor.isExtension())
|
|
79
|
+
}
|
|
80
|
+
innerOnLoad()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function onClose() {
|
|
84
|
+
adaptor.localStorageSetItem(LOCAL_STORAGE_KEY, LOCAL_STORAGE_VALUE)
|
|
85
|
+
setOpen(false)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -34,11 +34,11 @@ import type {
|
|
|
34
34
|
KeyedCollection,
|
|
35
35
|
CodeGen,
|
|
36
36
|
} from '@looker/sdk-codegen'
|
|
37
|
-
import { Method } from '@looker/sdk-codegen'
|
|
38
37
|
import { CollapserCard, getGenerators } from '@looker/run-it'
|
|
39
38
|
|
|
40
39
|
import { DocCode } from '../DocCode'
|
|
41
40
|
import { selectSdkLanguage } from '../../state'
|
|
41
|
+
import { isMethod } from '../../utils/path'
|
|
42
42
|
import { noComment } from './utils'
|
|
43
43
|
import { DocDeclarations } from './DocDeclarations'
|
|
44
44
|
|
|
@@ -59,10 +59,9 @@ const getDeclarations = (
|
|
|
59
59
|
const declarations: KeyedCollection<string> = {}
|
|
60
60
|
Object.entries(generators).forEach(([language, gen]) => {
|
|
61
61
|
if (sdkLanguage === 'All' || language === sdkLanguage) {
|
|
62
|
-
const code =
|
|
63
|
-
item
|
|
64
|
-
|
|
65
|
-
: gen.declareType('', item as IType)
|
|
62
|
+
const code = isMethod(item)
|
|
63
|
+
? gen.declareMethod('', item as IMethod)
|
|
64
|
+
: gen.declareType('', item as IType)
|
|
66
65
|
declarations[language] = code
|
|
67
66
|
}
|
|
68
67
|
})
|
|
@@ -100,28 +100,5 @@ describe('ExploreType', () => {
|
|
|
100
100
|
`http://localhost/${specKey}/types/ColorCollection/${targetType.jsonName}`
|
|
101
101
|
)
|
|
102
102
|
})
|
|
103
|
-
test('recognizes anything', () => {
|
|
104
|
-
const specKey = 'anything'
|
|
105
|
-
const path = `/${specKey}/methods/foo`
|
|
106
|
-
renderWithRouter(<ExploreTypeLink api={api} type={targetType} />, [path])
|
|
107
|
-
|
|
108
|
-
const actual = screen.getByText(targetType.jsonName)
|
|
109
|
-
expect(actual).toBeInTheDocument()
|
|
110
|
-
expect(actual).toHaveProperty(
|
|
111
|
-
'href',
|
|
112
|
-
`http://localhost/${specKey}/types/ColorCollection/${targetType.jsonName}`
|
|
113
|
-
)
|
|
114
|
-
})
|
|
115
|
-
test('ignores oauth path', () => {
|
|
116
|
-
const specKey = 'oauth'
|
|
117
|
-
const path = `/${specKey}/methods/foo`
|
|
118
|
-
renderWithRouter(<ExploreTypeLink api={api} type={targetType} />, [path])
|
|
119
|
-
const actual = screen.getByText(targetType.jsonName)
|
|
120
|
-
expect(actual).toBeInTheDocument()
|
|
121
|
-
expect(actual).toHaveProperty(
|
|
122
|
-
'href',
|
|
123
|
-
`http://types/ColorCollection/${targetType.jsonName}`
|
|
124
|
-
)
|
|
125
|
-
})
|
|
126
103
|
})
|
|
127
104
|
})
|
|
@@ -29,9 +29,9 @@ import React from 'react'
|
|
|
29
29
|
import { Code, Tree, TreeItem } from '@looker/components'
|
|
30
30
|
import type { IType, ApiModel } from '@looker/sdk-codegen'
|
|
31
31
|
import { TypeOfType, typeOfType } from '@looker/sdk-codegen'
|
|
32
|
-
import {
|
|
32
|
+
import { useRouteMatch } from 'react-router-dom'
|
|
33
|
+
|
|
33
34
|
import { Link } from '../Link'
|
|
34
|
-
import { getSpecKey } from '../../reducers'
|
|
35
35
|
import { buildPath } from '../../utils'
|
|
36
36
|
import {
|
|
37
37
|
ExploreProperty,
|
|
@@ -48,7 +48,8 @@ interface ExploreTypeLinkProps {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const ExploreTypeLink: FC<ExploreTypeLinkProps> = ({ type, api }) => {
|
|
51
|
-
const
|
|
51
|
+
const match = useRouteMatch<{ specKey: string }>('/:specKey')
|
|
52
|
+
const specKey = match?.params.specKey
|
|
52
53
|
const picked = pickType(type)
|
|
53
54
|
const name = picked.name
|
|
54
55
|
const prefix = typeLinkPrefix(type)
|
|
@@ -56,12 +57,10 @@ export const ExploreTypeLink: FC<ExploreTypeLinkProps> = ({ type, api }) => {
|
|
|
56
57
|
const typed = typeOfType(picked)
|
|
57
58
|
if (typed === TypeOfType.Intrinsic)
|
|
58
59
|
return <Code fontSize="small">{type.jsonName}</Code>
|
|
59
|
-
|
|
60
|
-
const specKey = getSpecKey(location)
|
|
61
60
|
return (
|
|
62
61
|
<>
|
|
63
62
|
{prefix}
|
|
64
|
-
<Link key={type.fullName} to={buildPath(api, type, specKey)}>
|
|
63
|
+
<Link key={type.fullName} to={buildPath(api, type, specKey!)}>
|
|
65
64
|
{name}
|
|
66
65
|
</Link>
|
|
67
66
|
{suffix}
|
|
@@ -42,7 +42,7 @@ describe('exploreUtils', () => {
|
|
|
42
42
|
const props = pickTypeProps(responseType)
|
|
43
43
|
expect(props).toBeDefined()
|
|
44
44
|
const names = Object.keys(props)
|
|
45
|
-
expect(names).toEqual(['name', 'is_default', 'tables'])
|
|
45
|
+
expect(names).toEqual(['name', 'is_default', 'tables', 'table_limit_hit'])
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
test('iconType', () => {
|
|
@@ -28,46 +28,35 @@ import { act, screen, waitFor } from '@testing-library/react'
|
|
|
28
28
|
import { codeGenerators } from '@looker/sdk-codegen'
|
|
29
29
|
import userEvent from '@testing-library/user-event'
|
|
30
30
|
|
|
31
|
-
import {
|
|
31
|
+
import { getLoadedSpecs, specs } from '../../test-data'
|
|
32
32
|
import { renderWithRouterAndReduxProvider } from '../../test-utils'
|
|
33
33
|
import { defaultSettingsState } from '../../state'
|
|
34
34
|
import { Header } from './Header'
|
|
35
35
|
|
|
36
36
|
describe('Header', () => {
|
|
37
|
-
const specDispatch = jest.fn()
|
|
38
37
|
const hasNavigation = true
|
|
39
38
|
const toggleNavigation = () => !hasNavigation
|
|
40
|
-
|
|
39
|
+
const spec = getLoadedSpecs()['4.0']
|
|
41
40
|
beforeAll(() => {
|
|
42
41
|
window.HTMLElement.prototype.scrollIntoView = jest.fn()
|
|
43
42
|
})
|
|
44
43
|
|
|
45
44
|
test('it renders a title', () => {
|
|
46
45
|
renderWithRouterAndReduxProvider(
|
|
47
|
-
<Header
|
|
48
|
-
specs={specs}
|
|
49
|
-
spec={specState.spec}
|
|
50
|
-
specDispatch={specDispatch}
|
|
51
|
-
toggleNavigation={toggleNavigation}
|
|
52
|
-
/>
|
|
46
|
+
<Header spec={spec} toggleNavigation={toggleNavigation} />
|
|
53
47
|
)
|
|
54
48
|
expect(screen.getByText('API Explorer').closest('a')).toHaveAttribute(
|
|
55
49
|
'href',
|
|
56
|
-
`/${
|
|
50
|
+
`/${spec.key}`
|
|
57
51
|
)
|
|
58
52
|
})
|
|
59
53
|
|
|
60
54
|
test('it renders a spec selector with the correct default value and options', async () => {
|
|
61
55
|
renderWithRouterAndReduxProvider(
|
|
62
|
-
<Header
|
|
63
|
-
specs={specs}
|
|
64
|
-
spec={specState.spec}
|
|
65
|
-
specDispatch={specDispatch}
|
|
66
|
-
toggleNavigation={toggleNavigation}
|
|
67
|
-
/>
|
|
56
|
+
<Header spec={spec} toggleNavigation={toggleNavigation} />
|
|
68
57
|
)
|
|
69
58
|
const selector = screen.getByLabelText('spec selector')
|
|
70
|
-
expect(selector).toHaveValue(`${
|
|
59
|
+
expect(selector).toHaveValue(`${spec.key}`)
|
|
71
60
|
await act(async () => {
|
|
72
61
|
await userEvent.click(selector)
|
|
73
62
|
await waitFor(() => {
|
|
@@ -80,12 +69,7 @@ describe('Header', () => {
|
|
|
80
69
|
|
|
81
70
|
test('it renders an sdk language selector with the correct value and options', async () => {
|
|
82
71
|
renderWithRouterAndReduxProvider(
|
|
83
|
-
<Header
|
|
84
|
-
specs={specs}
|
|
85
|
-
spec={specState.spec}
|
|
86
|
-
specDispatch={specDispatch}
|
|
87
|
-
toggleNavigation={toggleNavigation}
|
|
88
|
-
/>
|
|
72
|
+
<Header spec={spec} toggleNavigation={toggleNavigation} />
|
|
89
73
|
)
|
|
90
74
|
const selector = screen.getByLabelText('sdk language selector')
|
|
91
75
|
expect(selector).toHaveValue(defaultSettingsState.sdkLanguage)
|
|
@@ -101,12 +85,7 @@ describe('Header', () => {
|
|
|
101
85
|
|
|
102
86
|
test('it renders an icon button for the differ', () => {
|
|
103
87
|
renderWithRouterAndReduxProvider(
|
|
104
|
-
<Header
|
|
105
|
-
specs={specs}
|
|
106
|
-
spec={specState.spec}
|
|
107
|
-
specDispatch={specDispatch}
|
|
108
|
-
toggleNavigation={toggleNavigation}
|
|
109
|
-
/>
|
|
88
|
+
<Header spec={spec} toggleNavigation={toggleNavigation} />
|
|
110
89
|
)
|
|
111
90
|
expect(
|
|
112
91
|
screen
|
|
@@ -114,6 +93,6 @@ describe('Header', () => {
|
|
|
114
93
|
name: 'Compare Specifications',
|
|
115
94
|
})
|
|
116
95
|
.closest('a')
|
|
117
|
-
).toHaveAttribute('href', `/diff/${
|
|
96
|
+
).toHaveAttribute('href', `/diff/${spec.key}/`)
|
|
118
97
|
})
|
|
119
98
|
})
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import type { FC
|
|
27
|
+
import type { FC } from 'react'
|
|
28
28
|
import React from 'react'
|
|
29
29
|
import styled from 'styled-components'
|
|
30
30
|
import {
|
|
@@ -36,19 +36,14 @@ import {
|
|
|
36
36
|
} from '@looker/components'
|
|
37
37
|
import { LookerLogo } from '@looker/icons'
|
|
38
38
|
import { Menu } from '@styled-icons/material/Menu'
|
|
39
|
-
import type {
|
|
39
|
+
import type { SpecItem } from '@looker/sdk-codegen'
|
|
40
40
|
|
|
41
41
|
import { Link } from '../Link'
|
|
42
|
-
import type { SpecAction } from '../../reducers'
|
|
43
42
|
import { SelectorContainer } from '../SelectorContainer'
|
|
44
43
|
|
|
45
44
|
interface HeaderProps {
|
|
46
|
-
/** Specs to choose from */
|
|
47
|
-
specs: SpecList
|
|
48
45
|
/** Current selected spec */
|
|
49
46
|
spec: SpecItem
|
|
50
|
-
/** Spec state setter */
|
|
51
|
-
specDispatch: Dispatch<SpecAction>
|
|
52
47
|
/** Nav state setter */
|
|
53
48
|
toggleNavigation: (target?: boolean) => void
|
|
54
49
|
className?: string
|
|
@@ -63,9 +58,7 @@ export const HEADER_TOGGLE_LABEL = 'Toggle Navigation'
|
|
|
63
58
|
*/
|
|
64
59
|
export const HeaderLayout: FC<HeaderProps> = ({
|
|
65
60
|
className,
|
|
66
|
-
specs,
|
|
67
61
|
spec,
|
|
68
|
-
specDispatch,
|
|
69
62
|
toggleNavigation,
|
|
70
63
|
}) => (
|
|
71
64
|
<SemanticHeader
|
|
@@ -95,7 +88,7 @@ export const HeaderLayout: FC<HeaderProps> = ({
|
|
|
95
88
|
</Space>
|
|
96
89
|
</Link>
|
|
97
90
|
</Space>
|
|
98
|
-
<SelectorContainer
|
|
91
|
+
<SelectorContainer spec={spec} />
|
|
99
92
|
</SemanticHeader>
|
|
100
93
|
)
|
|
101
94
|
|
|
@@ -24,16 +24,16 @@
|
|
|
24
24
|
|
|
25
25
|
*/
|
|
26
26
|
import React from 'react'
|
|
27
|
-
import {
|
|
28
|
-
import { renderWithTheme } from '@looker/components-test-utils'
|
|
27
|
+
import { screen, waitFor } from '@testing-library/react'
|
|
29
28
|
import userEvent from '@testing-library/user-event'
|
|
30
|
-
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
29
|
+
import { useHistory } from 'react-router-dom'
|
|
30
|
+
import { getLoadedSpecs, specs } from '../../test-data'
|
|
31
|
+
import {
|
|
32
|
+
renderWithReduxProvider,
|
|
33
|
+
renderWithRouterAndReduxProvider,
|
|
34
|
+
} from '../../test-utils'
|
|
33
35
|
import { ApiSpecSelector } from './ApiSpecSelector'
|
|
34
36
|
|
|
35
|
-
const specState = getLoadedSpecState()
|
|
36
|
-
|
|
37
37
|
jest.mock('react-router-dom', () => {
|
|
38
38
|
const ReactRouterDOM = jest.requireActual('react-router-dom')
|
|
39
39
|
return {
|
|
@@ -41,34 +41,29 @@ 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
45
|
}
|
|
45
46
|
})
|
|
46
47
|
|
|
48
|
+
// jest.mock('../../state/specs', () => ({
|
|
49
|
+
// ...(jest.requireActual('../../state/specs') as Record<string, unknown>),
|
|
50
|
+
// useSpecActions: jest
|
|
51
|
+
// .fn()
|
|
52
|
+
// .mockReturnValue({ setCurrentSpecAction: jest.fn() }),
|
|
53
|
+
// }))
|
|
54
|
+
|
|
47
55
|
describe('ApiSpecSelector', () => {
|
|
48
|
-
const specDispatch = jest.fn()
|
|
49
56
|
Element.prototype.scrollIntoView = jest.fn()
|
|
57
|
+
const spec = getLoadedSpecs()['4.0']
|
|
50
58
|
|
|
51
|
-
test('the
|
|
52
|
-
|
|
53
|
-
<ApiSpecSelector
|
|
54
|
-
specs={specs}
|
|
55
|
-
spec={specState.spec}
|
|
56
|
-
specDispatch={specDispatch}
|
|
57
|
-
/>
|
|
58
|
-
)
|
|
59
|
-
|
|
59
|
+
test('the base spec is selected by default', () => {
|
|
60
|
+
renderWithReduxProvider(<ApiSpecSelector spec={spec} />)
|
|
60
61
|
const selector = screen.getByRole('textbox')
|
|
61
|
-
expect(selector).toHaveValue(`${
|
|
62
|
+
expect(selector).toHaveValue(`${spec.key}`)
|
|
62
63
|
})
|
|
63
64
|
|
|
64
65
|
test('it lists all available specs', async () => {
|
|
65
|
-
|
|
66
|
-
<ApiSpecSelector
|
|
67
|
-
specs={specs}
|
|
68
|
-
spec={specState.spec}
|
|
69
|
-
specDispatch={specDispatch}
|
|
70
|
-
/>
|
|
71
|
-
)
|
|
66
|
+
renderWithReduxProvider(<ApiSpecSelector spec={spec} />)
|
|
72
67
|
userEvent.click(screen.getByRole('textbox'))
|
|
73
68
|
await waitFor(() => {
|
|
74
69
|
expect(screen.getAllByRole('option')).toHaveLength(
|
|
@@ -77,25 +72,17 @@ describe('ApiSpecSelector', () => {
|
|
|
77
72
|
})
|
|
78
73
|
})
|
|
79
74
|
|
|
80
|
-
test('
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
await act(async () => {
|
|
90
|
-
await userEvent.click(screen.getByRole('textbox'))
|
|
91
|
-
await userEvent.click(screen.getByRole('option', { name: '3.1 current' }))
|
|
92
|
-
await waitFor(() => {
|
|
93
|
-
expect(specDispatch).toHaveBeenCalledTimes(1)
|
|
94
|
-
expect(specDispatch).toHaveBeenCalledWith({
|
|
95
|
-
type: 'SELECT_SPEC',
|
|
96
|
-
payload: '3.1',
|
|
97
|
-
})
|
|
98
|
-
})
|
|
75
|
+
test('requests selected spec', async () => {
|
|
76
|
+
const { push } = useHistory()
|
|
77
|
+
renderWithRouterAndReduxProvider(<ApiSpecSelector spec={spec} />)
|
|
78
|
+
userEvent.click(screen.getByRole('textbox'))
|
|
79
|
+
await waitFor(() => {
|
|
80
|
+
expect(screen.getAllByRole('option')).toHaveLength(
|
|
81
|
+
Object.keys(specs).length
|
|
82
|
+
)
|
|
99
83
|
})
|
|
84
|
+
const button = screen.getByText('3.1')
|
|
85
|
+
userEvent.click(button)
|
|
86
|
+
expect(push).toHaveBeenCalledWith('/3.1/methods/Dashboard/dashboard')
|
|
100
87
|
})
|
|
101
88
|
})
|