Skip to content

Commit 4072fb1

Browse files
authored
feat: Open script modal (#5571)
1 parent 1c22a45 commit 4072fb1

File tree

5 files changed

+202
-12
lines changed

5 files changed

+202
-12
lines changed

src/dataExplorer/components/FluxQueryBuilder.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
border-bottom: 1px solid $cf-grey-15;
3232
}
3333

34-
.flux-query-builder__save-button {
34+
.flux-query-builder__action-button {
3535
margin-left: $cf-space-s;
3636
}
3737

src/dataExplorer/components/FluxQueryBuilder.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {isFlagEnabled} from 'src/shared/utils/featureFlag'
3232

3333
export enum OverlayType {
3434
NEW = 'new',
35+
OPEN = 'open',
3536
SAVE = 'save',
3637
}
3738

@@ -70,9 +71,22 @@ const FluxQueryBuilder: FC = () => {
7071
/>
7172
{isFlagEnabled('saveAsScript') && (
7273
<Button
73-
className="flux-query-builder__save-button"
74+
className="flux-query-builder__action-button"
75+
onClick={() => setOverlayType(OverlayType.OPEN)}
76+
text="Open"
77+
icon={IconFont.Export_New}
78+
/>
79+
)}
80+
{isFlagEnabled('saveAsScript') && (
81+
<Button
82+
className="flux-query-builder__action-button"
7483
onClick={() => setOverlayType(OverlayType.SAVE)}
75-
text="Save Script"
84+
status={
85+
query.length === 0
86+
? ComponentStatus.Disabled
87+
: ComponentStatus.Default
88+
}
89+
text="Save"
7690
icon={IconFont.Save}
7791
/>
7892
)}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import React, {FC, useState, useCallback, useEffect} from 'react'
2+
import {
3+
Button,
4+
ComponentColor,
5+
ComponentSize,
6+
ComponentStatus,
7+
IconFont,
8+
Input,
9+
List,
10+
TechnoSpinner,
11+
Overlay,
12+
EmptyState,
13+
} from '@influxdata/clockface'
14+
import {RemoteDataState} from 'src/types'
15+
import './SaveAsScript.scss'
16+
import {CLOUD} from 'src/shared/constants'
17+
import {useHistory} from 'react-router-dom'
18+
import {useSelector} from 'react-redux'
19+
import {getOrg} from 'src/organizations/selectors'
20+
21+
let getScripts
22+
23+
if (CLOUD) {
24+
getScripts = require('src/client/scriptsRoutes').getScripts
25+
}
26+
27+
interface Props {
28+
onClose: () => void
29+
}
30+
31+
const OpenScript: FC<Props> = ({onClose}) => {
32+
const [scripts, setScripts] = useState([])
33+
const [loading, setLoading] = useState(RemoteDataState.NotStarted)
34+
const [searchTerm, setSearchTerm] = useState('')
35+
const [selectedScript, setSelectedScript] = useState<any>({})
36+
const history = useHistory()
37+
const org = useSelector(getOrg)
38+
39+
const handleGetScripts = useCallback(async () => {
40+
try {
41+
if (getScripts) {
42+
setLoading(RemoteDataState.Loading)
43+
const resp = await getScripts({})
44+
45+
if (resp.status !== 200) {
46+
throw new Error(resp.data.message)
47+
}
48+
49+
setScripts(resp.data.scripts)
50+
setLoading(RemoteDataState.Done)
51+
} else {
52+
alert('you are in an supported environment')
53+
}
54+
} catch (error) {
55+
setLoading(RemoteDataState.Error)
56+
console.error({error})
57+
}
58+
}, [getScripts])
59+
60+
const handleOpenScript = () => {
61+
history.replace(
62+
`/orgs/${org.id}/data-explorer/from/script/${selectedScript.id}`
63+
)
64+
onClose()
65+
}
66+
67+
useEffect(() => {
68+
handleGetScripts()
69+
}, [])
70+
71+
if (
72+
loading === RemoteDataState.NotStarted ||
73+
loading === RemoteDataState.Loading
74+
) {
75+
return (
76+
<div className="data-source--list__empty">
77+
<TechnoSpinner strokeWidth={ComponentSize.Small} diameterPixels={32} />
78+
</div>
79+
)
80+
}
81+
82+
if (loading === RemoteDataState.Error) {
83+
return (
84+
<div className="data-source--list__empty">
85+
<p>Could not get scripts</p>
86+
</div>
87+
)
88+
}
89+
90+
if (loading === RemoteDataState.Done) {
91+
const filteredScripts = scripts.filter(script =>
92+
script.name.includes(searchTerm)
93+
)
94+
95+
let list = (
96+
<List>
97+
{filteredScripts.map(script => (
98+
<List.Item
99+
key={script.id}
100+
value={script.name}
101+
onClick={() => setSelectedScript(script)}
102+
selected={script.name === selectedScript?.name}
103+
title={script}
104+
wrapText={true}
105+
>
106+
{script.name}
107+
</List.Item>
108+
))}
109+
</List>
110+
)
111+
if (filteredScripts.length === 0 && searchTerm) {
112+
list = (
113+
<EmptyState className="data-source--list__no-results">
114+
<p>{`No Scripts match "${searchTerm}"`}</p>
115+
</EmptyState>
116+
)
117+
} else if (filteredScripts.length === 0 && !searchTerm) {
118+
list = (
119+
<EmptyState className="data-source--list__no-results">
120+
<p>No Scripts found</p>
121+
</EmptyState>
122+
)
123+
}
124+
return (
125+
<Overlay.Container maxWidth={500}>
126+
<Overlay.Header title="Open Script" onDismiss={onClose} />
127+
<Overlay.Body>
128+
<Input
129+
className="data-source--search"
130+
icon={IconFont.Search_New}
131+
size={ComponentSize.Medium}
132+
value={searchTerm}
133+
placeholder="Search Scripts"
134+
onChange={evt => setSearchTerm(evt.target.value)}
135+
/>
136+
<List>{list}</List>
137+
</Overlay.Body>
138+
<Overlay.Footer>
139+
<Button
140+
color={ComponentColor.Tertiary}
141+
onClick={onClose}
142+
text="Cancel"
143+
/>
144+
{CLOUD && (
145+
<Button
146+
color={ComponentColor.Primary}
147+
status={
148+
scripts.length === 0
149+
? ComponentStatus.Disabled
150+
: ComponentStatus.Default
151+
}
152+
onClick={handleOpenScript}
153+
text="Open"
154+
/>
155+
)}
156+
</Overlay.Footer>
157+
</Overlay.Container>
158+
)
159+
}
160+
161+
return null
162+
}
163+
164+
export default OpenScript

src/dataExplorer/components/SaveAsScript.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
scriptSaveSuccess,
2525
} from 'src/shared/copy/notifications/categories/scripts'
2626
import {getOrg} from 'src/organizations/selectors'
27+
import OpenScript from 'src/dataExplorer/components/OpenScript'
2728

2829
interface Props {
2930
onClose: () => void
@@ -33,7 +34,7 @@ interface Props {
3334
const SaveAsScript: FC<Props> = ({onClose, type}) => {
3435
const dispatch = useDispatch()
3536
const history = useHistory()
36-
const {resource, setResource, save} = useContext(PersistanceContext)
37+
const {query, resource, setResource, save} = useContext(PersistanceContext)
3738
const {cancel} = useContext(QueryContext)
3839
const {setStatus, setResult} = useContext(ResultsContext)
3940
const org = useSelector(getOrg)
@@ -64,8 +65,9 @@ const SaveAsScript: FC<Props> = ({onClose, type}) => {
6465
setResult(null)
6566

6667
history.replace(`/orgs/${org.id}/data-explorer/from/script`)
67-
68-
onClose()
68+
if (type !== OverlayType.OPEN) {
69+
onClose()
70+
}
6971
}, [onClose, setStatus, setResult, cancel, history, org?.id])
7072

7173
const handleSaveScript = () => {
@@ -84,7 +86,9 @@ const SaveAsScript: FC<Props> = ({onClose, type}) => {
8486
)
8587
console.error({error})
8688
} finally {
87-
onClose()
89+
if (type !== OverlayType.OPEN) {
90+
onClose()
91+
}
8892
}
8993
}
9094

@@ -94,15 +98,19 @@ const SaveAsScript: FC<Props> = ({onClose, type}) => {
9498

9599
let overlayTitle = 'Save Script'
96100

97-
if (type === OverlayType.NEW) {
101+
if (type !== OverlayType.SAVE) {
98102
overlayTitle = 'Do you want to save your Script first?'
99103
}
100104

105+
if (query.length === 0) {
106+
return <OpenScript onClose={onClose} />
107+
}
108+
101109
return (
102110
<Overlay.Container maxWidth={500}>
103111
<Overlay.Header title={overlayTitle} onDismiss={onClose} />
104112
<Overlay.Body>
105-
{type === OverlayType.NEW && (
113+
{type !== OverlayType.SAVE && (
106114
<div className="save-script-overlay__warning-text">
107115
"{resource?.data?.name ?? 'Untitled Script'}" will be overwritten by
108116
a new one if you don’t save it.
@@ -134,7 +142,7 @@ const SaveAsScript: FC<Props> = ({onClose, type}) => {
134142
onClick={onClose}
135143
text="Cancel"
136144
/>
137-
{type === OverlayType.NEW && (
145+
{type !== OverlayType.SAVE && (
138146
<Button
139147
color={ComponentColor.Default}
140148
onClick={clear}
@@ -151,7 +159,7 @@ const SaveAsScript: FC<Props> = ({onClose, type}) => {
151159
: ComponentStatus.Default
152160
}
153161
onClick={handleSaveScript}
154-
text={type === OverlayType.NEW ? 'Yes, Save' : 'Save'}
162+
text={type === OverlayType.SAVE ? 'Save' : 'Yes, Save'}
155163
/>
156164
)}
157165
</Overlay.Footer>

src/dataExplorer/context/persistance.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ export const PersistanceProvider: FC = ({children}) => {
9191
'dataExplorer.range',
9292
DEFAULT_CONTEXT.range
9393
)
94-
const [resource, setResource] = useSessionStorage('dataExplorer.resource', {})
94+
const [resource, setResource] = useSessionStorage('dataExplorer.resource', {
95+
type: 'scripts',
96+
flux: '',
97+
data: {},
98+
})
9599
const [selection, setSelection] = useSessionStorage(
96100
'dataExplorer.schema',
97101
JSON.parse(JSON.stringify(DEFAULT_CONTEXT.selection))

0 commit comments

Comments
 (0)