Skip to content

Commit c59b5d4

Browse files
authored
feat: Added 4.0 GA stable banner to api explorer (#956)
* fix: Added 4.0 GA stable banner to api explorer - Shows banner containing information on API 4.0 GA and a link to dev portal documentation - Displays close button that hides the banner and sets localstorage to not show in the future - Banner is only shown if it has not been hidden before and the instance's 4.0 spec is not stable or current.
1 parent 45a9a69 commit c59b5d4

File tree

5 files changed

+215
-0
lines changed

5 files changed

+215
-0
lines changed

packages/api-explorer/src/ApiExplorer.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
Loader,
5858
SelectorContainer,
5959
HEADER_TOGGLE_LABEL,
60+
Banner,
6061
} from './components'
6162
import { specReducer, initDefaultSpecState, updateSpecApi } from './reducers'
6263
import { AppRouter } from './routes'
@@ -160,6 +161,7 @@ export const ApiExplorer: FC<ApiExplorerProps> = ({
160161
<Loader message="Initializing" themeOverrides={themeOverrides} />
161162
) : (
162163
<ErrorBoundary logError={adaptor.logError.bind(adaptor)}>
164+
<Banner adaptor={adaptor} specs={specs} />
163165
<Page style={{ overflow: 'hidden' }}>
164166
{!headless && (
165167
<Header
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
})
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
export { Banner } from './Banner'

packages/api-explorer/src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ export { DocTypeSummary } from './DocTypeSummary'
4545
export { Link } from './Link'
4646
export { ErrorBoundary } from './ErrorBoundary'
4747
export { SelectorContainer } from './SelectorContainer'
48+
export { Banner } from './Banner'

0 commit comments

Comments
 (0)