Merge pull request #12663 from influxdata/feat/flux--insert-function
feat(ui): Update flux functions insertion from toolbar to add to current line or belowpull/12665/head
commit
009e5130e8
|
@ -1,6 +1,7 @@
|
|||
## v2.0.0-alpha.7 [unreleased]
|
||||
|
||||
### Features
|
||||
1. [12663](https://github.com/influxdata/influxdb/pull/12663): Insert flux function near cursor in flux editor
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {Controlled as ReactCodeMirror, IInstance} from 'react-codemirror2'
|
||||
import {EditorChange, LineWidget} from 'codemirror'
|
||||
import {EditorChange, LineWidget, Position} from 'codemirror'
|
||||
import {ShowHintOptions} from 'src/types/codemirror'
|
||||
import 'src/external/codemirror'
|
||||
|
||||
|
@ -34,6 +34,7 @@ interface Props {
|
|||
onSubmitScript?: () => void
|
||||
suggestions: Suggestion[]
|
||||
visibility?: string
|
||||
onCursorChange?: (position: Position) => void
|
||||
}
|
||||
|
||||
interface Widget extends LineWidget {
|
||||
|
@ -108,11 +109,20 @@ class FluxEditor extends PureComponent<Props, State> {
|
|||
onTouchStart={this.onTouchStart}
|
||||
editorDidMount={this.handleMount}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onCursor={this.handleCursorChange}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private handleCursorChange = (__: IInstance, position: Position) => {
|
||||
const {onCursorChange} = this.props
|
||||
|
||||
if (onCursorChange) {
|
||||
onCursorChange(position)
|
||||
}
|
||||
}
|
||||
|
||||
private makeError(): void {
|
||||
this.editor.clearGutter('error-gutter')
|
||||
const lineNumbers = this.statusLine
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {Position} from 'codemirror'
|
||||
|
||||
// Components
|
||||
import FluxEditor from 'src/shared/components/FluxEditor'
|
||||
|
@ -15,6 +16,7 @@ import {saveAndExecuteQueries} from 'src/timeMachine/actions/queries'
|
|||
|
||||
// Utils
|
||||
import {getActiveQuery} from 'src/timeMachine/selectors'
|
||||
import {insertFluxFunction} from 'src/timeMachine/utils/scriptInsertion'
|
||||
|
||||
// Constants
|
||||
import {HANDLE_VERTICAL, HANDLE_NONE} from 'src/shared/constants'
|
||||
|
@ -42,6 +44,8 @@ interface State {
|
|||
type Props = StateProps & DispatchProps
|
||||
|
||||
class TimeMachineFluxEditor extends PureComponent<Props, State> {
|
||||
private cursorPosition: Position = {line: 0, ch: 0}
|
||||
|
||||
public state: State = {
|
||||
displayFluxFunctions: true,
|
||||
}
|
||||
|
@ -60,6 +64,7 @@ class TimeMachineFluxEditor extends PureComponent<Props, State> {
|
|||
onChangeScript={onSetActiveQueryText}
|
||||
onSubmitScript={onSubmitQueries}
|
||||
suggestions={[]}
|
||||
onCursorChange={this.handleCursorPosition}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
@ -102,12 +107,38 @@ class TimeMachineFluxEditor extends PureComponent<Props, State> {
|
|||
const {displayFluxFunctions} = this.state
|
||||
|
||||
if (displayFluxFunctions) {
|
||||
return <FluxFunctionsToolbar />
|
||||
return (
|
||||
<FluxFunctionsToolbar
|
||||
onInsertFluxFunction={this.handleInsertFluxFunction}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return <VariablesToolbar />
|
||||
}
|
||||
|
||||
private handleCursorPosition = (position: Position): void => {
|
||||
this.cursorPosition = position
|
||||
}
|
||||
|
||||
private handleInsertFluxFunction = async (
|
||||
functionName: string,
|
||||
fluxFunction: string
|
||||
): Promise<void> => {
|
||||
const {activeQueryText} = this.props
|
||||
const {line} = this.cursorPosition
|
||||
|
||||
const {updatedScript, cursorPosition} = insertFluxFunction(
|
||||
line,
|
||||
activeQueryText,
|
||||
functionName,
|
||||
fluxFunction
|
||||
)
|
||||
await this.props.onSetActiveQueryText(updatedScript)
|
||||
|
||||
this.handleCursorPosition(cursorPosition)
|
||||
}
|
||||
|
||||
private showFluxFunctions = () => {
|
||||
this.setState({displayFluxFunctions: true})
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import {setActiveQueryText} from 'src/timeMachine/actions'
|
|||
import {getActiveQuery} from 'src/timeMachine/selectors'
|
||||
|
||||
// Constants
|
||||
import {FLUX_FUNCTIONS, FROM, UNION} from 'src/shared/constants/fluxFunctions'
|
||||
import {FLUX_FUNCTIONS} from 'src/shared/constants/fluxFunctions'
|
||||
|
||||
// Styles
|
||||
import 'src/timeMachine/components/fluxFunctionsToolbar/FluxFunctionsToolbar.scss'
|
||||
|
@ -24,6 +24,10 @@ import 'src/timeMachine/components/fluxFunctionsToolbar/FluxFunctionsToolbar.scs
|
|||
// Types
|
||||
import {AppState} from 'src/types/v2'
|
||||
|
||||
interface OwnProps {
|
||||
onInsertFluxFunction: (functionName: string, text: string) => void
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
activeQueryText: string
|
||||
}
|
||||
|
@ -32,7 +36,7 @@ interface DispatchProps {
|
|||
onSetActiveQueryText: (script: string) => void
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps
|
||||
type Props = OwnProps & StateProps & DispatchProps
|
||||
|
||||
interface State {
|
||||
searchTerm: string
|
||||
|
@ -59,7 +63,7 @@ class FluxFunctionsToolbar extends PureComponent<Props, State> {
|
|||
key={category}
|
||||
category={category}
|
||||
funcs={funcs}
|
||||
onClickFunction={this.handleUpdateScript}
|
||||
onClickFunction={this.handleClickFunction}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
@ -74,21 +78,8 @@ class FluxFunctionsToolbar extends PureComponent<Props, State> {
|
|||
this.setState({searchTerm})
|
||||
}
|
||||
|
||||
private handleUpdateScript = (funcName: string, funcExample: string) => {
|
||||
const {activeQueryText, onSetActiveQueryText} = this.props
|
||||
|
||||
switch (funcName) {
|
||||
case FROM.name: {
|
||||
onSetActiveQueryText(`${activeQueryText}\n${funcExample}`)
|
||||
return
|
||||
}
|
||||
case UNION.name: {
|
||||
onSetActiveQueryText(`${activeQueryText.trimRight()}\n\n${funcExample}`)
|
||||
return
|
||||
}
|
||||
default:
|
||||
onSetActiveQueryText(`${activeQueryText}\n |> ${funcExample}`)
|
||||
}
|
||||
private handleClickFunction = (funcName: string, funcExample: string) => {
|
||||
this.props.onInsertFluxFunction(funcName, funcExample)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import {Position} from 'codemirror'
|
||||
|
||||
// Constants
|
||||
import {FROM, UNION} from 'src/shared/constants/fluxFunctions'
|
||||
|
||||
const rejoinScript = (scriptLines: string[]): string => {
|
||||
return scriptLines.join('\n')
|
||||
}
|
||||
|
||||
const insertAtLine = (
|
||||
lineNumber: number,
|
||||
scriptLines: string[],
|
||||
textToInsert: string,
|
||||
insertOnSameLine?: boolean
|
||||
): string => {
|
||||
const front = scriptLines.slice(0, lineNumber)
|
||||
|
||||
const backStartIndex = insertOnSameLine ? lineNumber + 1 : lineNumber
|
||||
const back = scriptLines.slice(backStartIndex)
|
||||
|
||||
const updated = [...front, textToInsert, ...back]
|
||||
|
||||
return rejoinScript(updated)
|
||||
}
|
||||
|
||||
const getInsertLineNumber = (
|
||||
currentLineNumber: number,
|
||||
scriptLines: string[]
|
||||
): number => {
|
||||
const currentLine = scriptLines[currentLineNumber]
|
||||
|
||||
// Insert on the current line if its an empty line
|
||||
if (!currentLine.trim()) {
|
||||
return currentLineNumber
|
||||
}
|
||||
|
||||
return currentLineNumber + 1
|
||||
}
|
||||
|
||||
const functionRequiresNewLine = (funcName: string): boolean => {
|
||||
switch (funcName) {
|
||||
case FROM.name:
|
||||
case UNION.name: {
|
||||
return true
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
const formatFunctionForInsert = (funcName: string, fluxFunction: string) => {
|
||||
if (functionRequiresNewLine(funcName)) {
|
||||
return `\n${fluxFunction}`
|
||||
}
|
||||
|
||||
return ` |> ${fluxFunction}`
|
||||
}
|
||||
|
||||
const getCursorPosition = (
|
||||
insertLineNumber,
|
||||
formattedFunction,
|
||||
funcName
|
||||
): Position => {
|
||||
const ch = formattedFunction.length - 1
|
||||
const line = functionRequiresNewLine(funcName)
|
||||
? insertLineNumber + 1
|
||||
: insertLineNumber
|
||||
|
||||
return {line, ch}
|
||||
}
|
||||
|
||||
export const insertFluxFunction = (
|
||||
currentLineNumber: number,
|
||||
currentScript: string,
|
||||
functionName: string,
|
||||
fluxFunction: string
|
||||
): {updatedScript: string; cursorPosition: Position} => {
|
||||
const scriptLines = currentScript.split('\n')
|
||||
const insertLineNumber = getInsertLineNumber(currentLineNumber, scriptLines)
|
||||
const insertOnSameLine = currentLineNumber === insertLineNumber
|
||||
|
||||
const formattedFunction = formatFunctionForInsert(functionName, fluxFunction)
|
||||
|
||||
const updatedScript = insertAtLine(
|
||||
insertLineNumber,
|
||||
scriptLines,
|
||||
formattedFunction,
|
||||
insertOnSameLine
|
||||
)
|
||||
|
||||
const updatedCursorPosition = getCursorPosition(
|
||||
insertLineNumber,
|
||||
formattedFunction,
|
||||
functionName
|
||||
)
|
||||
|
||||
return {updatedScript, cursorPosition: updatedCursorPosition}
|
||||
}
|
Loading…
Reference in New Issue