Skip to content

Commit 4747846

Browse files
authored
fix(flux-4720): temporary fix to hardcode top20 examples, plus add cursor awarenss in function injection (#4595)
* hardcode top 20 functions used, and move all special-cased function handling to the same file * have timeMachine flux editor use the common position calculations * enable LSP suggestions when inserting functions, (based on cursor awareness) * leave in extra space if have suggested args, if not then remove extra space
1 parent a929f89 commit 4747846

File tree

8 files changed

+251
-184
lines changed

8 files changed

+251
-184
lines changed

cypress/e2e/shared/explorerVisualizations.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ describe('visualizations', () => {
8989
cy.log('check to see if new aggregate rate is at the bottom')
9090
cy.get('.view-line')
9191
.last()
92+
.prev()
9293
.contains('aggregate.')
9394
cy.getByTestID('flux-editor').should('exist')
9495
cy.getByTestID('flux-editor').monacoType(`yoyoyoyoyo`)

src/flows/context/editor.tsx

Lines changed: 25 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,32 @@ import React, {
77
} from 'react'
88
import {EditorType} from 'src/types'
99
import {PipeContext} from 'src/flows/context/pipe'
10-
11-
export enum InjectionType {
12-
OnOwnLine = 'onOwnLine',
13-
SameLine = 'sameLine',
14-
}
15-
16-
interface InjectionPosition {
17-
row: number
18-
column: number
19-
shouldStartWithNewLine: boolean
20-
shouldEndInNewLine: boolean
21-
}
10+
import {
11+
InjectionType,
12+
calcInjectionPosition,
13+
moveCursorAndTriggerSuggest,
14+
} from 'src/shared/utils/fluxFunctions'
15+
export {InjectionType, InjectionPosition} from 'src/shared/utils/fluxFunctions'
16+
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
2217

2318
export interface InjectionOptions {
2419
header?: string | null
2520
text: string
2621
type: InjectionType
22+
triggerSuggest?: boolean
2723
}
2824

2925
export interface EditorContextType {
3026
editor: EditorType | null
3127
setEditor: (editor: EditorType) => void
3228
inject: (options: InjectionOptions) => void
33-
calcInjectiontPosition: (type: InjectionType) => Partial<InjectionPosition>
3429
updateText: (t: string) => void
3530
}
3631

3732
const DEFAULT_CONTEXT: EditorContextType = {
3833
editor: null,
3934
setEditor: _ => {},
4035
inject: _ => {},
41-
calcInjectiontPosition: _ => ({}),
4236
updateText: _ => {},
4337
}
4438

@@ -62,88 +56,25 @@ export const EditorProvider: FC = ({children}) => {
6256
[queries, activeQuery]
6357
)
6458

65-
const calcInjectiontPosition = useCallback(
66-
(type: InjectionType): Partial<InjectionPosition> => {
67-
if (!editor) {
68-
return {}
69-
}
70-
const {lineNumber, column: col} = editor.getPosition()
71-
let row = lineNumber
72-
let column = col
73-
74-
const queryText = editor.getModel().getValue()
75-
const split = queryText.split('\n')
76-
const getCurrentLineText = () => {
77-
// row is not zero indexed in monaco editor. 1..N
78-
return (split[row - 1] || split[split.length - 1]).trimEnd()
79-
}
80-
81-
let currentLineText = getCurrentLineText()
82-
// column is not zero indexed in monnao editor. 1..N
83-
let textAheadOfCursor = currentLineText.slice(0, column - 1).trim()
84-
let textBehindCursor = currentLineText.slice(column - 1).trim()
85-
86-
// if cursor has text in front of it, and should be onOwnRow
87-
if (type == InjectionType.OnOwnLine && textAheadOfCursor) {
88-
row++
89-
column = 1
90-
}
91-
// edge case for when user toggles to the script editor
92-
// this defaults the cursor to the initial position (top-left, 1:1 position)
93-
const [currentRange] = editor.getVisibleRanges()
94-
if (row === 1 && column === 1) {
95-
row = currentRange.endLineNumber + 1
96-
}
97-
98-
if (row !== lineNumber) {
99-
currentLineText = getCurrentLineText()
100-
textAheadOfCursor = currentLineText.slice(0, column - 1).trim()
101-
textBehindCursor = currentLineText.slice(column - 1).trim()
102-
}
103-
104-
let shouldEndInNewLine = false
105-
// if cursor has text behind it, and should be onOwnRow
106-
if (type == InjectionType.OnOwnLine && textBehindCursor) {
107-
shouldEndInNewLine = true
108-
}
109-
110-
const cursorInMiddleOfText = textAheadOfCursor && textBehindCursor
111-
if (type == InjectionType.OnOwnLine && cursorInMiddleOfText) {
112-
row++
113-
column = 1
114-
shouldEndInNewLine = true
115-
}
116-
117-
// if we asked to insert on a row out-of-range
118-
// then need to manually append newline to front of row
119-
const shouldStartWithNewLine = row > currentRange.endLineNumber
120-
121-
return {row, column, shouldStartWithNewLine, shouldEndInNewLine}
122-
},
123-
[editor]
124-
)
125-
12659
const inject = useCallback(
12760
(options: InjectionOptions) => {
12861
if (!editor) {
12962
return {}
13063
}
13164

132-
const {header, text: initT, type} = options
65+
const {header, text: initT, type, triggerSuggest} = options
66+
const injectionPosition = calcInjectionPosition(editor, type)
13367
const {
13468
row,
13569
column: initC,
13670
shouldStartWithNewLine,
13771
shouldEndInNewLine,
138-
} = calcInjectiontPosition(type)
139-
let text = ''
72+
} = injectionPosition
14073

74+
let text = initT.trimRight()
14175
if (shouldStartWithNewLine) {
142-
text = `\n${initT}`
143-
} else {
144-
text = initT
76+
text = `\n${text}`
14577
}
146-
14778
if (shouldEndInNewLine) {
14879
text = `${text}\n`
14980
}
@@ -157,13 +88,13 @@ export const EditorProvider: FC = ({children}) => {
15788
},
15889
]
15990

160-
if (
91+
const addHeader =
16192
header &&
16293
!editor
16394
.getModel()
16495
.getValue()
16596
.includes(header)
166-
) {
97+
if (addHeader) {
16798
edits.unshift({
16899
range: new monaco.Range(1, 1, 1, 1),
169100
text: `${header}\n`,
@@ -172,8 +103,17 @@ export const EditorProvider: FC = ({children}) => {
172103

173104
editor.executeEdits('', edits)
174105
updateText(editor.getValue())
106+
107+
if (isFlagEnabled('fluxDynamicDocs') && triggerSuggest) {
108+
moveCursorAndTriggerSuggest(
109+
editor,
110+
injectionPosition,
111+
addHeader,
112+
text.length
113+
)
114+
}
175115
},
176-
[editor, calcInjectiontPosition, updateText]
116+
[editor, updateText]
177117
)
178118

179119
return (
@@ -182,7 +122,6 @@ export const EditorProvider: FC = ({children}) => {
182122
editor,
183123
setEditor,
184124
inject,
185-
calcInjectiontPosition,
186125
updateText,
187126
}}
188127
>

src/flows/pipes/RawFluxEditor/view.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ import DynamicFunctions from 'src/flows/pipes/RawFluxEditor/FunctionsList/Dynami
3838
import 'src/flows/pipes/RawFluxEditor/style.scss'
3939

4040
// Utils
41+
import {
42+
isPipeTransformation,
43+
functionRequiresNewLine,
44+
} from 'src/shared/utils/fluxFunctions'
4145
import {event} from 'src/cloud/utils/reporting'
4246
import {CLOUD} from 'src/shared/constants'
4347
import {isFlagEnabled} from 'src/shared/utils/featureFlag'
@@ -75,19 +79,9 @@ const Query: FC<PipeProp> = ({Context}) => {
7579

7680
const injectIntoEditor = useCallback(
7781
(fn): void => {
78-
let text = ''
79-
if (CLOUD && isFlagEnabled('fluxDynamicDocs')) {
80-
// only fluxTypes with <- sign require a pipe forward sign
81-
text = fn.fluxType.startsWith('<-', 1)
82-
? ` |> ${fn.example}`
83-
: `${fn.example}`
84-
} else {
85-
if (fn.name === 'from' || fn.name === 'union') {
86-
text = `${fn.example}`
87-
} else {
88-
text = ` |> ${fn.example}`
89-
}
90-
}
82+
const text = isPipeTransformation(fn)
83+
? ` |> ${fn.example}`
84+
: `${fn.example}`
9185

9286
const getHeader = fn => {
9387
let importStatement = null
@@ -106,10 +100,16 @@ const Query: FC<PipeProp> = ({Context}) => {
106100
return importStatement
107101
}
108102

103+
const type =
104+
isPipeTransformation(fn) || functionRequiresNewLine(fn)
105+
? InjectionType.OnOwnLine
106+
: InjectionType.SameLine
107+
109108
const options = {
110109
text,
111-
type: InjectionType.OnOwnLine,
110+
type,
112111
header: getHeader(fn),
112+
triggerSuggest: true,
113113
}
114114
inject(options)
115115
},

src/shared/utils/fluxExample.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ describe('Flux example functions and values', () => {
6262
}
6363

6464
expect(getFluxExample(exampleFunc).example).toEqual(
65-
`${exampleFunc.package}.${exampleFunc.name}( )`
65+
`${exampleFunc.package}.${exampleFunc.name}()`
6666
)
6767
})
6868

src/shared/utils/fluxExample.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
11
import {FluxFunction} from 'src/types/shared'
22

3+
// temporary solution, for the top 20 functions
4+
// longterm solution requires changes in the payload from the backend (flux docs)
5+
const TOP_20 = {
6+
'universe.filter': 'filter(fn: (r) => r._measurement == "cpu")',
7+
'universe.range': 'range(start: -15m, stop: now())',
8+
'universe.sort': 'sort(columns: ["_value"], desc: false)',
9+
'universe.keep': 'keep(columns: ["col1", "col2"])',
10+
'universe.yield': 'yield(name: "custom-name")',
11+
'universe.map': 'map(fn: (r) => ({ r with _value: r._value * r._value }))',
12+
'universe.pivot':
13+
'pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")',
14+
'universe.last': 'last()',
15+
'universe.fill': 'fill(column: "_value", usePrevious: true)',
16+
'universe.time': 'time(v: r._value)',
17+
'universe.union': 'union(tables: [table1, table2])',
18+
'universe.int': 'int(v: r._value)',
19+
'events.duration': `events.duration(
20+
unit: 1ns,
21+
columnName: "duration",
22+
timeColumn: "_time",
23+
stopColumn: "_stop",
24+
stop: 2020-01-01T00:00:00Z
25+
)`,
26+
'universe.group': 'group(columns: ["host", "_measurement"], mode:"by")',
27+
'universe.aggregateWindow':
28+
'aggregateWindow(every: v.windowPeriod, fn: mean)',
29+
'universe.limit': 'limit(n:10, offset: 0)',
30+
'universe.now': 'now()',
31+
'universe.distinct': 'distinct(column: "host")',
32+
'universe.sum': 'sum(column: "_value")',
33+
}
34+
335
export const getFluxExample = (func: FluxFunction) => {
436
const {fluxParameters = [], kind, name, package: packageName} = func
537

638
let example = `${packageName}.${name}`
39+
40+
if (!!TOP_20[example]) {
41+
return {...func, example: TOP_20[example]}
42+
}
43+
744
if (kind.toLowerCase() === 'function') {
845
let injectedParameters = ''
946
for (const parameter of fluxParameters) {
@@ -17,6 +54,9 @@ export const getFluxExample = (func: FluxFunction) => {
1754
injectedParameters = `${injectedParameters} `
1855
}
1956
}
57+
injectedParameters = injectedParameters.trim().length
58+
? injectedParameters.trimLeft()
59+
: injectedParameters.trim()
2060
example =
2161
packageName === 'universe'
2262
? `${name}(${injectedParameters})`

0 commit comments

Comments
 (0)