Merge pull request #5895 from influxdata/5890/builder_warns_before_overwrite

feat(ui/flux): warn before overriding the existing Flux Editor script
1.9.x
Pavel Závora 2022-03-21 18:25:49 +01:00 committed by GitHub
commit 37c8f425b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 202 additions and 26 deletions

View File

@ -15,6 +15,7 @@
1. [#5856](https://github.com/influxdata/chronograf/pull/5856): Add alert rule options to not send alert on state recovery and send regardless of state change.
1. [#5893](https://github.com/influxdata/chronograf/pull/5893): Make aggregation function selection optional.
1. [#5894](https://github.com/influxdata/chronograf/pull/5894): Autocomplete builtin `v` object in Flux editor.
1. [#5895](https://github.com/influxdata/chronograf/pull/5895): Warn before overriding the existing Flux Editor script.
### Bug Fixes

View File

@ -172,6 +172,7 @@ class FluxQueryMaker extends PureComponent<Props, State> {
return (
<FluxQueryBuilder
script={draftScript}
source={source}
timeRange={timeRange}
onSubmit={this.handleSubmitBuilderScript}

View File

@ -185,6 +185,9 @@ $flux-form-control-checkbox-gap: 20px;
margin-right: 4px;
&:last-child {
flex-grow: 1;
.fqb--submit {
width: 100%;
}
}
}
}
@ -208,3 +211,42 @@ button.flux-query-builder--add-card-button {
font-size: 13px;
margin-left: 4px;
}
.fqb--confirm-popup {
position: fixed;
align-items: center;
width: 350px;
user-select: none;
padding: 8px;
background-color: #202028;
border-color: #ff8564;
border-style: solid;
border-width: 2px;
border-radius: 6px;
box-shadow: 0 0 5px 0 #dc4e58;
font-size: 1.1em;
display: flex;
z-index: 5000;
.fqb--confirm-label {
margin: 0 8px
}
> button {
color: #fff;
background: #bf3d5e;
background-image: linear-gradient(45deg, rgb(191, 61, 94) 0%, rgb(249, 95, 83) 100%)
}
}
.fqb--confirm-caret {
content: "";
width: 0;
height: 0;
position: fixed;
border-top: 6px solid transparent;
border-bottom: 6px solid #ff8564;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
margin-top: -12px;
margin-left: -3px;
z-index: 9999;
}

View File

@ -9,7 +9,6 @@ import FancyScrollbar from '../../FancyScrollbar'
import {
Button,
ButtonShape,
ComponentColor,
ComponentSize,
ComponentStatus,
IconFont,
@ -18,7 +17,6 @@ import AggregationSelector from './AggregationSelector'
import TagSelector from './TagSelector'
import {notify as notifyActionCreator} from 'src/shared/actions/notifications'
import {
fluxWizardError,
notifyCopyToClipboardFailed,
notifyCopyToClipboardSuccess,
} from 'src/shared/copy/notifications'
@ -28,11 +26,12 @@ import timeRangeWindowPeriod from './util/timeRangeWindowPeriod'
import {RemoteDataState, TimeZones} from 'src/types'
import {buildQuery} from './util/generateFlux'
import {timeRangeLabel} from '../../TimeRangeLabel'
import FluxQueryBuilderSubmit from './FluxQueryBuilderSubmit'
interface OwnProps extends TimeMachineQueryProps {
onSubmit: (script: string) => void
onShowEditor: () => void
isRunnable: boolean
script: string
}
type Props = OwnProps & typeof mdtp & ReturnType<typeof mstp>
@ -48,6 +47,7 @@ const FluxQueryBuilder = ({
onSubmit,
onShowEditor,
onAddTagSelector,
script: editorScript,
}: Props) => {
const [defaultPeriod, timeRangeText] = useMemo(
() => [
@ -97,7 +97,7 @@ const FluxQueryBuilder = ({
<Button
shape={ButtonShape.Square}
size={ComponentSize.ExtraSmall}
titleText="Copy builder query to clipboard"
titleText="Copy builder script to clipboard"
icon={IconFont.Duplicate}
status={
isRunnable ? ComponentStatus.Default : ComponentStatus.Disabled
@ -115,12 +115,12 @@ const FluxQueryBuilder = ({
success
? notifyCopyToClipboardSuccess(
null,
'Query builder flux script has been copied to clipboard.',
'Builder script has been copied to clipboard.',
''
)
: notifyCopyToClipboardFailed(
null,
'Query builder flux script was not copied to clipboard.',
'Builder script was not copied to clipboard.',
''
)
)
@ -128,26 +128,12 @@ const FluxQueryBuilder = ({
e.preventDefault()
}}
/>
<Button
size={ComponentSize.ExtraSmall}
color={ComponentColor.Primary}
onClick={() => {
try {
const script = buildQuery(builderState)
onSubmit(script)
} catch (ex) {
console.error(ex)
notify(
fluxWizardError(
'Unable to build flux script: ' + ex.message
)
)
}
}}
status={
isRunnable ? ComponentStatus.Default : ComponentStatus.Disabled
}
text="Submit"
<FluxQueryBuilderSubmit
isRunnable={isRunnable}
builderState={builderState}
editorScript={editorScript}
notify={notify}
onSubmit={onSubmit}
/>
</div>
</AggregationSelector>

View File

@ -0,0 +1,146 @@
// Libraries
import React, {useMemo, useRef, useState} from 'react'
import {
Button,
ComponentColor,
ComponentSize,
ComponentStatus,
} from 'src/reusable_ui'
import {fluxWizardError} from 'src/shared/copy/notifications'
import {PublishNotificationActionCreator} from 'src/types/actions/notifications'
import {ClickOutside} from '../../ClickOutside'
import {QueryBuilderState} from './types'
import {buildQuery} from './util/generateFlux'
interface Props {
isRunnable: boolean
onSubmit: (s: string) => void
editorScript: string
builderState: QueryBuilderState
notify: PublishNotificationActionCreator
}
const EMPTY_FN = () => {}
const FluxQueryBuilderSubmit = ({
builderState,
isRunnable,
editorScript,
onSubmit,
notify,
}: Props) => {
if (!isRunnable) {
return (
<Button
size={ComponentSize.ExtraSmall}
color={ComponentColor.Primary}
onClick={EMPTY_FN}
status={ComponentStatus.Disabled}
text="Submit"
customClass="fqb--submit"
/>
)
}
const [showConfirm, setShowConfirm] = useState(false)
const buttonRef = useRef<HTMLDivElement>()
const lastConfirmedBuilderState = useMemo(() => {
return builderState
}, [editorScript])
return (
<div ref={buttonRef}>
{!showConfirm ? (
<Button
size={ComponentSize.ExtraSmall}
color={ComponentColor.Primary}
onClick={() => {
try {
const script = buildQuery(builderState)
const lastScript = buildQuery(lastConfirmedBuilderState)
// submit directly if editor is empty, the generated query is the same as the editor query
// or if the builder was used to generate the new script
if (
!editorScript ||
script === editorScript ||
editorScript === lastScript
) {
onSubmit(script)
} else {
setShowConfirm(true)
}
} catch (ex) {
console.error(ex)
notify(
fluxWizardError('Unable to build flux script: ' + ex.message)
)
}
}}
status={ComponentStatus.Default}
text="Submit"
customClass="fqb--submit"
/>
) : (
<>
<Button
size={ComponentSize.ExtraSmall}
color={ComponentColor.Primary}
onClick={EMPTY_FN}
status={
isRunnable ? ComponentStatus.Default : ComponentStatus.Disabled
}
text="Submit"
customClass="fqb--submit"
/>
<div
className="fqb--confirm-popup"
style={{
left: `${
buttonRef.current.getBoundingClientRect().right - 350
}px`,
}}
>
<span className="fqb--confirm-label">
Submitting the Script Builder will overwrite the existing Flux
script, any changes you have made using Flux will be discarded.
This cannot be recovered.
</span>
<ClickOutside onClickOutside={() => setShowConfirm(false)}>
<Button
size={ComponentSize.ExtraSmall}
color={ComponentColor.Danger}
onClick={() => {
try {
const script = buildQuery(builderState)
setShowConfirm(false)
onSubmit(script)
} catch (ex) {
console.error(ex)
notify(
fluxWizardError(
'Unable to build flux script: ' + ex.message
)
)
}
}}
status={ComponentStatus.Default}
text="OK"
/>
</ClickOutside>
</div>
<span
className="fqb--confirm-caret"
style={{
left: `${
buttonRef.current.getBoundingClientRect().left +
buttonRef.current.getBoundingClientRect().width / 2
}px`,
top: `${buttonRef.current.getBoundingClientRect().bottom}px`,
}}
/>
</>
)}
</div>
)
}
export default FluxQueryBuilderSubmit