Skip to content

Commit 74b2910

Browse files
authored
feat: add sql dropdown support (#6148)
* wip - need to make this work so that we can cancel and return the previous language selected * feat: complete the sql support dropdown * chore: resolve conflicts * chore: disable sync for sql scripts * feat: clean up state management a bit * chore: remove TODO * chore: unnest the language property
1 parent b57ff5a commit 74b2910

File tree

15 files changed

+190
-53
lines changed

15 files changed

+190
-53
lines changed

cypress/e2e/shared/fluxQueryBuilder.test.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {Organization} from '../../../src/types'
22
const path = require('path')
33

4-
const DEFAULT_EDITOR_TEXT =
4+
const DEFAULT_FLUX_EDITOR_TEXT =
55
'// Start by selecting data from the schema browser or typing flux here'
66

77
describe('Script Builder', () => {
@@ -71,7 +71,10 @@ describe('Script Builder', () => {
7171
cy.getByTestID('flux-query-builder--no-save').click({force: true})
7272
})
7373
cy.getByTestID('flux-editor').within(() => {
74-
cy.get('textarea.inputarea').should('have.value', DEFAULT_EDITOR_TEXT)
74+
cy.get('textarea.inputarea').should(
75+
'have.value',
76+
DEFAULT_FLUX_EDITOR_TEXT
77+
)
7578
})
7679
}
7780
})
@@ -606,7 +609,10 @@ describe('Script Builder', () => {
606609

607610
cy.log('editor text is now empty')
608611
cy.getByTestID('flux-editor').within(() => {
609-
cy.get('textarea.inputarea').should('have.value', DEFAULT_EDITOR_TEXT)
612+
cy.get('textarea.inputarea').should(
613+
'have.value',
614+
DEFAULT_FLUX_EDITOR_TEXT
615+
)
610616
})
611617

612618
cy.log('schema browser has been cleared')
@@ -618,7 +624,10 @@ describe('Script Builder', () => {
618624
it('should not be able to modify the composition when unsynced, yet still modify the saved schema -- which updates the composition when re-synced', () => {
619625
cy.log('start with empty editor text')
620626
cy.getByTestID('flux-editor', {timeout: 30000}).within(() => {
621-
cy.get('textarea.inputarea').should('have.value', DEFAULT_EDITOR_TEXT)
627+
cy.get('textarea.inputarea').should(
628+
'have.value',
629+
DEFAULT_FLUX_EDITOR_TEXT
630+
)
622631
})
623632

624633
cy.log('turn off sync')
@@ -633,7 +642,10 @@ describe('Script Builder', () => {
633642
cy.log('editor text is still empty')
634643
cy.getByTestID('flux-editor').within(() => {
635644
// selecting bucket will empty the editor text
636-
cy.get('textarea.inputarea').should('have.value', DEFAULT_EDITOR_TEXT)
645+
cy.get('textarea.inputarea').should(
646+
'have.value',
647+
DEFAULT_FLUX_EDITOR_TEXT
648+
)
637649
})
638650

639651
cy.log('turn on sync')

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
"cy": "CYPRESS_dexUrl=https://$INGRESS_HOST:$PORT_HTTPS CYPRESS_baseUrl=http://localhost:9999 cypress open",
5353
"cy:dev": "source ../monitor-ci/.env && CYPRESS_dexUrl=CLOUD CYPRESS_baseUrl=https://$INGRESS_HOST:$PORT_HTTPS cypress open --config testFiles='{cloud,shared}/**/*.*'",
5454
"cy:dev-oss": "source ../monitor-ci/.env && CYPRESS_dexUrl=OSS CYPRESS_baseUrl=https://$INGRESS_HOST:$PORT_HTTPS cypress open --config testFiles='{oss,shared}/**/*.*'",
55-
"generate": "export SHA=a570a0fa2a9fea8698250f5436f6eccb89c9061c && export REMOTE=https://raw.githubusercontent.com/influxdata/openapi/${SHA}/ && yarn generate-meta",
55+
"generate": "export SHA=b561645e05716036f071a43df0bf2a81ad32be90 && export REMOTE=https://raw.githubusercontent.com/influxdata/openapi/${SHA}/ && yarn generate-meta",
5656
"generate-local": "export REMOTE=../openapi/ && yarn generate-meta",
5757
"generate-local-cloud": "export REMOTE=../openapi/ && yarn generate-meta-cloud",
5858
"generate-meta": "if [ -z \"${CLOUD_URL}\" ]; then yarn generate-meta-oss; else yarn generate-meta-cloud; fi",

src/dataExplorer/components/FieldSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ const FieldSelector: FC = () => {
8484
</div>
8585
)
8686
} else if (loading === RemoteDataState.Done && fieldsToShow.length) {
87-
if (resource?.data?.language === LanguageType.SQL) {
87+
if (resource?.language === LanguageType.SQL) {
8888
// readOnly
8989
list = fieldsToShow.map(field => (
9090
<dd

src/dataExplorer/components/FluxQueryBuilder.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,10 @@
5454
border-bottom: 2px solid $cf-grey-15;
5555
}
5656
}
57+
58+
.script-dropdown__flux {
59+
text-transform: capitalize;
60+
}
61+
.script-dropdown__sql {
62+
text-transform: uppercase;
63+
}

src/dataExplorer/components/FluxQueryBuilder.tsx

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1-
import React, {FC, useState, useContext} from 'react'
1+
import React, {FC, useCallback, useState, useContext} from 'react'
22
import {useHistory} from 'react-router-dom'
33
import {useSelector} from 'react-redux'
44

55
// Components
66
import {
77
ComponentColor,
88
DraggableResizer,
9+
Dropdown,
910
FlexBox,
1011
FlexDirection,
1112
Orientation,
1213
Button,
14+
Icon,
1315
IconFont,
1416
AlignItems,
1517
JustifyContent,
@@ -24,6 +26,7 @@ import {
2426
PersistanceProvider,
2527
PersistanceContext,
2628
} from 'src/dataExplorer/context/persistance'
29+
import {LanguageType} from 'src/dataExplorer/components/resources'
2730
import ResultsPane from 'src/dataExplorer/components/ResultsPane'
2831
import Sidebar from 'src/dataExplorer/components/Sidebar'
2932
import Schema from 'src/dataExplorer/components/Schema'
@@ -47,27 +50,43 @@ export enum OverlayType {
4750

4851
const FluxQueryBuilder: FC = () => {
4952
const history = useHistory()
50-
const {hasChanged, resource, vertical, setVertical} =
53+
const {resource, hasChanged, vertical, setVertical, setHasChanged} =
5154
useContext(PersistanceContext)
5255
const [overlayType, setOverlayType] = useState<OverlayType | null>(null)
56+
const [selectedLanguage, setSelectedLanguage] = useState(
57+
resource?.language ?? LanguageType.FLUX
58+
)
5359
const [isOverlayVisible, setIsOverlayVisible] = useState(false)
5460
const {cancel} = useContext(QueryContext)
5561
const {setStatus, setResult} = useContext(ResultsContext)
5662
const org = useSelector(getOrg)
5763

58-
const handleClear = () => {
64+
const handleClear = useCallback(() => {
5965
cancel()
6066
setStatus(RemoteDataState.NotStarted)
6167
setResult(null)
6268

63-
history.replace(`/orgs/${org.id}/data-explorer/from/script`)
69+
if (isFlagEnabled('uiSqlSupport')) {
70+
history.replace(
71+
`/orgs/${org.id}/data-explorer/from/script?language=${selectedLanguage}`
72+
)
73+
} else {
74+
history.replace(`/orgs/${org.id}/data-explorer/from/script`)
75+
}
6476

6577
if (!isFlagEnabled('saveAsScript')) {
6678
setIsOverlayVisible(false)
6779
}
80+
}, [cancel, org.id, history, setResult, setStatus, selectedLanguage])
81+
82+
const handleSelectDropdown = (language: LanguageType) => {
83+
// set the language in the state until we can confirm the selection
84+
setSelectedLanguage(language)
85+
setHasChanged(true)
86+
setOverlayType(OverlayType.NEW)
6887
}
6988

70-
const handleNewScript = () => {
89+
const handleNewScript = useCallback(() => {
7190
if (isFlagEnabled('saveAsScript')) {
7291
if (hasChanged) {
7392
setOverlayType(OverlayType.NEW)
@@ -81,7 +100,7 @@ const FluxQueryBuilder: FC = () => {
81100
handleClear()
82101
}
83102
}
84-
}
103+
}, [handleClear, hasChanged])
85104

86105
const handleUserpilot = () => {
87106
if (window.userpilot) {
@@ -95,6 +114,7 @@ const FluxQueryBuilder: FC = () => {
95114
{isFlagEnabled('saveAsScript') ? (
96115
<Overlay visible={overlayType !== null}>
97116
<SaveAsScript
117+
language={selectedLanguage}
98118
type={overlayType}
99119
setOverlayType={setOverlayType}
100120
onClose={() => setOverlayType(null)}
@@ -137,13 +157,43 @@ const FluxQueryBuilder: FC = () => {
137157
direction={FlexDirection.Row}
138158
justifyContent={JustifyContent.SpaceBetween}
139159
>
140-
<div>
141-
<Button
142-
onClick={handleNewScript}
143-
text={isFlagEnabled('saveAsScript') ? 'New Script' : 'Clear'}
144-
icon={IconFont.Plus_New}
145-
testID="flux-query-builder--new-script"
146-
/>
160+
<div style={{display: 'flex'}}>
161+
{isFlagEnabled('uiSqlSupport') ? (
162+
<Dropdown
163+
menu={onCollapse => (
164+
<Dropdown.Menu onCollapse={onCollapse}>
165+
{[LanguageType.FLUX, LanguageType.SQL].map(option => (
166+
<Dropdown.Item
167+
className={`script-dropdown__${option}`}
168+
key={option}
169+
onClick={() => handleSelectDropdown(option)}
170+
selected={resource?.language === option}
171+
>
172+
{option}
173+
</Dropdown.Item>
174+
))}
175+
</Dropdown.Menu>
176+
)}
177+
button={(active, onClick) => (
178+
<Dropdown.Button active={active} onClick={onClick}>
179+
<>
180+
<Icon glyph={IconFont.Plus_New} />
181+
&nbsp;New Script
182+
</>
183+
</Dropdown.Button>
184+
)}
185+
testID="select-option-dropdown"
186+
/>
187+
) : (
188+
<Button
189+
onClick={handleNewScript}
190+
text={
191+
isFlagEnabled('saveAsScript') ? 'New Script' : 'Clear'
192+
}
193+
icon={IconFont.Plus_New}
194+
testID="flux-query-builder--new-script"
195+
/>
196+
)}
147197
{isFlagEnabled('saveAsScript') && (
148198
<Button
149199
className="flux-query-builder__action-button"

src/dataExplorer/components/OpenScript.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {FC, useState, useCallback, useEffect} from 'react'
1+
import React, {FC, useContext, useState, useCallback, useEffect} from 'react'
22
import {
33
Button,
44
ComponentColor,
@@ -17,6 +17,8 @@ import {CLOUD} from 'src/shared/constants'
1717
import {useHistory} from 'react-router-dom'
1818
import {useSelector} from 'react-redux'
1919
import {getOrg} from 'src/organizations/selectors'
20+
import {ResultsContext} from 'src/dataExplorer/components/ResultsContext'
21+
import {QueryContext} from 'src/shared/contexts/query'
2022

2123
let getScripts
2224

@@ -33,6 +35,8 @@ const OpenScript: FC<Props> = ({onCancel, onClose}) => {
3335
const [scripts, setScripts] = useState([])
3436
const [loading, setLoading] = useState(RemoteDataState.NotStarted)
3537
const [searchTerm, setSearchTerm] = useState('')
38+
const {setStatus, setResult} = useContext(ResultsContext)
39+
const {cancel} = useContext(QueryContext)
3640
const [selectedScript, setSelectedScript] = useState<any>({})
3741
const history = useHistory()
3842
const org = useSelector(getOrg)
@@ -59,6 +63,9 @@ const OpenScript: FC<Props> = ({onCancel, onClose}) => {
5963
}, [getScripts])
6064

6165
const handleOpenScript = () => {
66+
setStatus(RemoteDataState.NotStarted)
67+
setResult(null)
68+
cancel()
6269
history.replace(
6370
`/orgs/${org.id}/data-explorer/from/script/${selectedScript.id}`
6471
)
@@ -67,7 +74,7 @@ const OpenScript: FC<Props> = ({onCancel, onClose}) => {
6774

6875
useEffect(() => {
6976
handleGetScripts()
70-
}, [])
77+
}, [handleGetScripts])
7178

7279
if (
7380
loading === RemoteDataState.NotStarted ||

src/dataExplorer/components/SaveAsScript.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,17 @@ import {
2727
import {getOrg} from 'src/organizations/selectors'
2828
import OpenScript from 'src/dataExplorer/components/OpenScript'
2929
import {DeleteScript} from 'src/dataExplorer/components/DeleteScript'
30+
import {LanguageType} from 'src/dataExplorer/components/resources'
31+
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
3032

3133
interface Props {
34+
language: LanguageType
3235
onClose: () => void
3336
setOverlayType: (type: OverlayType) => void
3437
type: OverlayType | null
3538
}
3639

37-
const SaveAsScript: FC<Props> = ({onClose, setOverlayType, type}) => {
40+
const SaveAsScript: FC<Props> = ({language, onClose, setOverlayType, type}) => {
3841
const dispatch = useDispatch()
3942
const history = useHistory()
4043
const {hasChanged, resource, setResource, save} =
@@ -89,14 +92,20 @@ const SaveAsScript: FC<Props> = ({onClose, setOverlayType, type}) => {
8992
setStatus(RemoteDataState.NotStarted)
9093
setResult(null)
9194

92-
history.replace(`/orgs/${org.id}/data-explorer/from/script`)
95+
if (isFlagEnabled('uiSqlSupport')) {
96+
history.replace(
97+
`/orgs/${org.id}/data-explorer/from/script?language=${language}`
98+
)
99+
} else {
100+
history.replace(`/orgs/${org.id}/data-explorer/from/script`)
101+
}
93102
if (type !== OverlayType.OPEN) {
94103
onClose()
95104
}
96105
}, [onClose, setStatus, setResult, cancel, history, org?.id, type])
97106

98107
const handleSaveScript = () => {
99-
save()
108+
save(language)
100109
.then(() => {
101110
setError(null)
102111
dispatch(notify(scriptSaveSuccess(resource?.data?.name ?? '')))

src/dataExplorer/components/SchemaBrowserHeading.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ import {PersistanceContext} from 'src/dataExplorer/context/persistance'
1717
// Utils
1818
import {event} from 'src/cloud/utils/reporting'
1919
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
20+
import {LanguageType} from 'src/dataExplorer/components/resources'
2021

2122
const FLUX_SYNC_DISABLE_TEXT = `Schema Sync is no longer available because the \
2223
code block has been edited.`
2324

2425
const SchemaBrowserHeading: FC = () => {
2526
const {fluxSync, toggleFluxSync} = useContext(FluxQueryBuilderContext)
26-
const {selection} = useContext(PersistanceContext)
27+
const {resource, selection} = useContext(PersistanceContext)
2728

2829
// Disable means diverged, used to not allow turning on or off the toggle
2930
const disableToggle: boolean = selection.composition?.diverged
@@ -52,6 +53,10 @@ const SchemaBrowserHeading: FC = () => {
5253
return null
5354
}
5455

56+
if (resource?.language === LanguageType.SQL) {
57+
return null
58+
}
59+
5560
return (
5661
<FlexBox
5762
className="schema-browser-heading"

src/dataExplorer/components/TagSelector.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const TagValues: FC<TagValuesProps> = ({loading, tagKey, tagValues}) => {
8585
</div>
8686
)
8787
} else if (loading === RemoteDataState.Done && valuesToShow.length) {
88-
if (resource?.data?.language === LanguageType.SQL) {
88+
if (resource?.language === LanguageType.SQL) {
8989
// readOnly
9090
list = valuesToShow.map(value => (
9191
<dd

src/dataExplorer/components/resources/TemplatePage.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import React, {FC, useEffect, useState, useContext} from 'react'
22
import {useSelector} from 'react-redux'
33
import {Switch, Route, useHistory, useParams} from 'react-router-dom'
4-
import {RemoteDataState} from 'src/types'
5-
4+
import {RemoteDataState, ResourceType} from 'src/types'
65
import {getOrg} from 'src/organizations/selectors'
76

87
import {RESOURCES} from 'src/dataExplorer/components/resources'
98
import {
109
PersistanceContext,
1110
PersistanceProvider,
12-
DEFAULT_EDITOR_TEXT,
11+
DEFAULT_FLUX_EDITOR_TEXT,
12+
DEFAULT_SQL_EDITOR_TEXT,
1313
} from 'src/dataExplorer/context/persistance'
14+
import {LanguageType} from 'src/dataExplorer/components/resources'
15+
import {getLanguage} from 'src/dataExplorer/shared/utils'
1416

1517
const Template: FC = () => {
1618
const {setQuery, setHasChanged, setResource, clearCompositionSelection} =
@@ -34,10 +36,22 @@ const Template: FC = () => {
3436
return
3537
}
3638

39+
const language = getLanguage()
40+
let flux = DEFAULT_FLUX_EDITOR_TEXT
41+
42+
if (language === LanguageType.SQL) {
43+
flux = DEFAULT_SQL_EDITOR_TEXT
44+
}
45+
3746
setLoading(RemoteDataState.Loading)
3847
clearCompositionSelection()
39-
setQuery(DEFAULT_EDITOR_TEXT)
40-
setResource(null)
48+
setQuery(flux)
49+
setResource({
50+
type: ResourceType.Scripts,
51+
flux,
52+
language,
53+
data: {},
54+
})
4155

4256
RESOURCES[params[0]].init.apply(this, params.slice(1)).then(data => {
4357
setQuery(data.flux)

0 commit comments

Comments
 (0)