Merge pull request #3730 from influxdata/fix/script-yield-before-range-filter

Fix unable to toggle yields
pull/10616/head
Delmer 2018-06-20 15:29:02 -04:00 committed by GitHub
commit 10af172b32
9 changed files with 78 additions and 120 deletions

View File

@ -3,7 +3,10 @@ import _ from 'lodash'
import AJAX from 'src/utils/ajax' import AJAX from 'src/utils/ajax'
import {Service, FluxTable} from 'src/types' import {Service, FluxTable} from 'src/types'
import {updateService} from 'src/shared/apis' import {updateService} from 'src/shared/apis'
import {parseResponse} from 'src/shared/parsing/flux/response' import {
parseResponse,
parseResponseError,
} from 'src/shared/parsing/flux/response'
import {MAX_RESPONSE_BYTES} from 'src/flux/constants' import {MAX_RESPONSE_BYTES} from 'src/flux/constants'
export const getSuggestions = async (url: string) => { export const getSuggestions = async (url: string) => {
@ -56,6 +59,9 @@ export const getTimeSeries = async (
service.links.proxy service.links.proxy
}?path=/v1/query${mark}orgName=defaulorgname${and}q=${garbage}` }?path=/v1/query${mark}orgName=defaulorgname${and}q=${garbage}`
let responseBody: string
let responseByteLength: number
try { try {
// We are using the `fetch` API here since the `AJAX` utility lacks support // We are using the `fetch` API here since the `AJAX` utility lacks support
// for limiting response size. The `AJAX` utility depends on // for limiting response size. The `AJAX` utility depends on
@ -66,16 +72,28 @@ export const getTimeSeries = async (
const resp = await fetch(url, {method: 'POST'}) const resp = await fetch(url, {method: 'POST'})
const {body, byteLength} = await decodeFluxRespWithLimit(resp) const {body, byteLength} = await decodeFluxRespWithLimit(resp)
return { responseBody = body
tables: parseResponse(body), responseByteLength = byteLength
didTruncate: byteLength >= MAX_RESPONSE_BYTES,
}
} catch (error) { } catch (error) {
console.error('Problem fetching data', error) console.error('Problem fetching data', error)
throw _.get(error, 'headers.x-influx-error', false) || throw _.get(error, 'headers.x-influx-error', false) ||
_.get(error, 'data.message', 'unknown error 🤷') _.get(error, 'data.message', 'unknown error 🤷')
} }
try {
return {
tables: parseResponse(responseBody),
didTruncate: responseByteLength >= MAX_RESPONSE_BYTES,
}
} catch (error) {
console.error('Could not parse response body', error)
return {
tables: parseResponseError(responseBody),
didTruncate: false,
}
}
} }
export const updateScript = async (service: Service, script: string) => { export const updateScript = async (service: Service, script: string) => {

View File

@ -1,12 +1,12 @@
import React, {PureComponent, Fragment} from 'react' import React, {PureComponent, Fragment} from 'react'
import _ from 'lodash'
import {FluxContext} from 'src/flux/containers/FluxPage' import {FluxContext} from 'src/flux/containers/FluxPage'
import FuncSelector from 'src/flux/components/FuncSelector' import FuncSelector from 'src/flux/components/FuncSelector'
import FuncNode from 'src/flux/components/FuncNode' import FuncNode from 'src/flux/components/FuncNode'
import YieldFuncNode from 'src/flux/components/YieldFuncNode' import YieldFuncNode from 'src/flux/components/YieldFuncNode'
import {getDeep} from 'src/utils/wrappers'
import {Func} from 'src/types/flux' import {Func, Context} from 'src/types/flux'
interface Props { interface Props {
funcNames: any[] funcNames: any[]
@ -22,7 +22,6 @@ interface State {
nonYieldableIndexesToggled: { nonYieldableIndexesToggled: {
[x: number]: boolean [x: number]: boolean
} }
isImplicitYieldToggled: boolean
} }
// an Expression is a group of one or more functions // an Expression is a group of one or more functions
@ -32,7 +31,6 @@ class ExpressionNode extends PureComponent<Props, State> {
this.state = { this.state = {
nonYieldableIndexesToggled: {}, nonYieldableIndexesToggled: {},
isImplicitYieldToggled: this.isImplicitYieldToggled,
} }
} }
@ -59,13 +57,17 @@ class ExpressionNode extends PureComponent<Props, State> {
service, service,
data, data,
scriptUpToYield, scriptUpToYield,
}) => { }: Context) => {
let isAfterRange = false let isAfterRange = false
let isAfterFilter = false let isAfterFilter = false
return ( return (
<> <>
{funcs.map((func, i) => { {funcs.map((func, i) => {
if (func.name === 'yield') {
return null
}
if (func.name === 'range') { if (func.name === 'range') {
isAfterRange = true isAfterRange = true
} }
@ -74,22 +76,7 @@ class ExpressionNode extends PureComponent<Props, State> {
isAfterFilter = true isAfterFilter = true
} }
if (func.name === 'yield') { const isYieldable = isAfterFilter && isAfterRange
const script = scriptUpToYield(bodyID, declarationID, i, true)
return (
<YieldFuncNode
index={i}
key={i}
func={func}
data={data}
script={script}
bodyID={bodyID}
service={service}
declarationID={declarationID}
/>
)
}
const funcNode = ( const funcNode = (
<FuncNode <FuncNode
@ -102,8 +89,9 @@ class ExpressionNode extends PureComponent<Props, State> {
onChangeArg={onChangeArg} onChangeArg={onChangeArg}
onDelete={onDeleteFuncNode} onDelete={onDeleteFuncNode}
onToggleYield={onToggleYield} onToggleYield={onToggleYield}
isYieldable={isAfterFilter && isAfterRange} isYieldable={isYieldable}
isYielding={this.isBeforeFuncYield(i)} isYielding={this.isBeforeYielding(i)}
isYieldedInScript={this.isYieldNodeIndex(i + 1)}
declarationID={declarationID} declarationID={declarationID}
onGenerateScript={onGenerateScript} onGenerateScript={onGenerateScript}
declarationsFromBody={declarationsFromBody} declarationsFromBody={declarationsFromBody}
@ -112,12 +100,15 @@ class ExpressionNode extends PureComponent<Props, State> {
/> />
) )
if (nonYieldableIndexesToggled[i]) { if (
const script = scriptUpToYield( nonYieldableIndexesToggled[i] ||
this.isYieldNodeIndex(i + 1)
) {
const script: string = scriptUpToYield(
bodyID, bodyID,
declarationID, declarationID,
i, i,
false isYieldable
) )
return ( return (
@ -134,43 +125,9 @@ class ExpressionNode extends PureComponent<Props, State> {
/> />
</Fragment> </Fragment>
) )
} else if (this.isEndOfScript(i)) {
const script = scriptUpToYield(bodyID, declarationID, i, true)
return (
<Fragment key={`${i}-notInScript`}>
<FuncNode
key={i}
index={i}
func={func}
funcs={funcs}
bodyID={bodyID}
service={service}
onChangeArg={onChangeArg}
onDelete={onDeleteFuncNode}
onToggleYield={this.handleHideImplicitYield}
isYieldable={isAfterFilter && isAfterRange}
isYielding={this.isBeforeFuncYield(i)}
declarationID={declarationID}
onGenerateScript={onGenerateScript}
declarationsFromBody={declarationsFromBody}
onToggleYieldWithLast={this.handleToggleYieldWithLast}
onDeleteBody={onDeleteBody}
/>
<YieldFuncNode
index={i}
func={func}
data={data}
script={script}
bodyID={bodyID}
service={service}
declarationID={declarationID}
/>
</Fragment>
)
} else {
return funcNode
} }
return funcNode
})} })}
<FuncSelector <FuncSelector
bodyID={bodyID} bodyID={bodyID}
@ -185,45 +142,26 @@ class ExpressionNode extends PureComponent<Props, State> {
) )
} }
private isBeforeFuncYield(funcIndex: number): boolean { private isBeforeYielding(funcIndex: number): boolean {
const {funcs, isLastBody} = this.props const {nonYieldableIndexesToggled} = this.state
const {isImplicitYieldToggled} = this.state const beforeToggledLastYield = !!nonYieldableIndexesToggled[funcIndex]
if ( if (beforeToggledLastYield) {
funcIndex === funcs.length - 1 &&
isLastBody &&
isImplicitYieldToggled
) {
return true return true
} }
if (funcIndex === funcs.length - 1) { return this.isYieldNodeIndex(funcIndex + 1)
return false
} }
const nextFunc = funcs[funcIndex + 1] private isYieldNodeIndex(funcIndex: number): boolean {
if (nextFunc.name === 'yield') {
return true
}
return false
}
private get isImplicitYieldToggled(): boolean {
const {isLastBody} = this.props
return isLastBody && this.isLastFuncYield
}
private get isLastFuncYield(): boolean {
const {funcs} = this.props const {funcs} = this.props
const funcName = getDeep<string>(funcs, `${funcIndex}.name`, '')
return _.get(funcs, `${funcs.length - 1}.name`) !== 'yield' return funcName === 'yield'
} }
// if funcNode is not yieldable, add last before yield() // if funcNode is not yieldable, add last before yield()
private handleToggleYieldWithLast = (funcNodeIndex: number) => { private handleToggleYieldWithLast = (funcNodeIndex: number): void => {
this.setState(({nonYieldableIndexesToggled}) => { this.setState(({nonYieldableIndexesToggled}) => {
const isFuncYieldToggled = !!nonYieldableIndexesToggled[funcNodeIndex] const isFuncYieldToggled = !!nonYieldableIndexesToggled[funcNodeIndex]
@ -235,20 +173,6 @@ class ExpressionNode extends PureComponent<Props, State> {
} }
}) })
} }
private handleHideImplicitYield = () => {
this.setState(() => ({
isImplicitYieldToggled: false,
}))
}
private isEndOfScript(index: number): boolean {
const {isLastBody, funcs} = this.props
const {isImplicitYieldToggled} = this.state
const isLastScriptFunc = isLastBody && index === funcs.length - 1
return isLastScriptFunc && isImplicitYieldToggled
}
} }
export default ExpressionNode export default ExpressionNode

View File

@ -8,7 +8,7 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
import FromDatabaseDropdown from 'src/flux/components/FromDatabaseDropdown' import FromDatabaseDropdown from 'src/flux/components/FromDatabaseDropdown'
import {funcNames, argTypes} from 'src/flux/constants' import {funcNames, argTypes} from 'src/flux/constants'
import {OnChangeArg, Arg} from 'src/types/flux' import {OnChangeArg, Arg, OnGenerateScript} from 'src/types/flux'
import {Service} from 'src/types' import {Service} from 'src/types'
interface Props { interface Props {
@ -22,7 +22,7 @@ interface Props {
bodyID: string bodyID: string
declarationID: string declarationID: string
onChangeArg: OnChangeArg onChangeArg: OnChangeArg
onGenerateScript: () => void onGenerateScript: OnGenerateScript
} }
@ErrorHandling @ErrorHandling

View File

@ -1,6 +1,6 @@
import React, {PureComponent, ChangeEvent, KeyboardEvent} from 'react' import React, {PureComponent, ChangeEvent, KeyboardEvent} from 'react'
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
import {OnChangeArg} from 'src/types/flux' import {OnChangeArg, OnGenerateScript} from 'src/types/flux'
interface Props { interface Props {
funcID: string funcID: string
@ -10,7 +10,7 @@ interface Props {
bodyID: string bodyID: string
declarationID: string declarationID: string
onChangeArg: OnChangeArg onChangeArg: OnChangeArg
onGenerateScript: () => void onGenerateScript: OnGenerateScript
autoFocus?: boolean autoFocus?: boolean
} }

View File

@ -2,7 +2,7 @@ import React, {PureComponent, ReactElement, MouseEvent} from 'react'
import FuncArg from 'src/flux/components/FuncArg' import FuncArg from 'src/flux/components/FuncArg'
import {OnChangeArg} from 'src/types/flux' import {OnChangeArg} from 'src/types/flux'
import {ErrorHandling} from 'src/shared/decorators/errors' import {ErrorHandling} from 'src/shared/decorators/errors'
import {Func} from 'src/types/flux' import {Func, OnGenerateScript} from 'src/types/flux'
import {funcNames} from 'src/flux/constants' import {funcNames} from 'src/flux/constants'
import JoinArgs from 'src/flux/components/JoinArgs' import JoinArgs from 'src/flux/components/JoinArgs'
import FilterArgs from 'src/flux/components/FilterArgs' import FilterArgs from 'src/flux/components/FilterArgs'
@ -15,7 +15,7 @@ interface Props {
bodyID: string bodyID: string
onChangeArg: OnChangeArg onChangeArg: OnChangeArg
declarationID: string declarationID: string
onGenerateScript: () => void onGenerateScript: OnGenerateScript
declarationsFromBody: string[] declarationsFromBody: string[]
onStopPropagation: (e: MouseEvent<HTMLElement>) => void onStopPropagation: (e: MouseEvent<HTMLElement>) => void
} }

View File

@ -6,6 +6,7 @@ import BodyDelete from 'src/flux/components/BodyDelete'
import FuncArgs from 'src/flux/components/FuncArgs' import FuncArgs from 'src/flux/components/FuncArgs'
import FuncArgsPreview from 'src/flux/components/FuncArgsPreview' import FuncArgsPreview from 'src/flux/components/FuncArgsPreview'
import { import {
OnGenerateScript,
OnDeleteFuncNode, OnDeleteFuncNode,
OnChangeArg, OnChangeArg,
OnToggleYield, OnToggleYield,
@ -24,12 +25,13 @@ interface Props {
onDelete: OnDeleteFuncNode onDelete: OnDeleteFuncNode
onToggleYield: OnToggleYield onToggleYield: OnToggleYield
onChangeArg: OnChangeArg onChangeArg: OnChangeArg
onGenerateScript: () => void onGenerateScript: OnGenerateScript
onToggleYieldWithLast: (funcNodeIndex: number) => void onToggleYieldWithLast: (funcNodeIndex: number) => void
declarationsFromBody: string[] declarationsFromBody: string[]
isYielding: boolean isYielding: boolean
isYieldable: boolean isYieldable: boolean
onDeleteBody: (bodyID: string) => void onDeleteBody: (bodyID: string) => void
isYieldedInScript: boolean
} }
interface State { interface State {
@ -182,11 +184,12 @@ export default class FuncNode extends PureComponent<Props, State> {
index, index,
bodyID, bodyID,
declarationID, declarationID,
isYieldable,
onToggleYieldWithLast, onToggleYieldWithLast,
isYieldable,
isYieldedInScript,
} = this.props } = this.props
if (isYieldable) { if (isYieldedInScript || isYieldable) {
onToggleYield(bodyID, declarationID, index) onToggleYield(bodyID, declarationID, index)
} else { } else {
onToggleYieldWithLast(index) onToggleYieldWithLast(index)

View File

@ -344,7 +344,7 @@ export class FluxPage extends PureComponent<Props, State> {
declarationID: string, declarationID: string,
funcNodeIndex: number, funcNodeIndex: number,
isYieldable: boolean isYieldable: boolean
) => { ): string => {
const {body: bodies} = this.state const {body: bodies} = this.state
const bodyIndex = bodies.findIndex(b => b.id === bodyID) const bodyIndex = bodies.findIndex(b => b.id === bodyID)

View File

@ -4,6 +4,19 @@ import uuid from 'uuid'
import {FluxTable} from 'src/types' import {FluxTable} from 'src/types'
export const parseResponseError = (response: string): FluxTable[] => {
const data = Papa.parse(response.trim()).data as string[][]
return [
{
id: uuid.v4(),
name: 'Error',
partitionKey: {},
data,
},
]
}
export const parseResponse = (response: string): FluxTable[] => { export const parseResponse = (response: string): FluxTable[] => {
const trimmedReponse = response.trim() const trimmedReponse = response.trim()

View File

@ -12,7 +12,7 @@ export type OnToggleYield = (
declarationID: string, declarationID: string,
funcNodeIndex: number funcNodeIndex: number
) => void ) => void
export type OnGenerateScript = (script: string) => void export type OnGenerateScript = () => void
export type OnChangeScript = (script: string) => void export type OnChangeScript = (script: string) => void
export type OnSubmitScript = () => void export type OnSubmitScript = () => void
export type ScriptUpToYield = ( export type ScriptUpToYield = (