Merge branch 'master' into polish/snip-snip
commit
deec4952e8
|
@ -11,6 +11,8 @@
|
|||
1. [#3474](https://github.com/influxdata/chronograf/pull/3474): Sort task table on Manage Alert page alphabetically
|
||||
1. [#3590](https://github.com/influxdata/chronograf/pull/3590): Redesign icons in side navigation
|
||||
1. [#3671](https://github.com/influxdata/chronograf/pull/3671): Remove Snip functionality in hover legend
|
||||
1. [#3659](https://github.com/influxdata/chronograf/pull/3659): Upgrade Data Explorer query text field with syntax highlighting and partial multi-line support
|
||||
1. [#3663](https://github.com/influxdata/chronograf/pull/3663): Truncate message preview in Alert Rules table
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import React, {PureComponent, KeyboardEvent} from 'react'
|
||||
import React, {PureComponent} from 'react'
|
||||
|
||||
import {Controlled as ReactCodeMirror, IInstance} from 'react-codemirror2'
|
||||
import {EditorChange} from 'codemirror'
|
||||
import Dropdown from 'src/shared/components/Dropdown'
|
||||
import classnames from 'classnames'
|
||||
import {QUERY_TEMPLATES, QueryTemplate} from 'src/data_explorer/constants'
|
||||
import QueryStatus from 'src/shared/components/QueryStatus'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {QueryConfig} from 'src/types'
|
||||
import 'src/external/codemirror'
|
||||
|
||||
interface Props {
|
||||
query: string
|
||||
|
@ -14,19 +18,17 @@ interface Props {
|
|||
|
||||
interface State {
|
||||
value: string
|
||||
focused: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class QueryEditor extends PureComponent<Props, State> {
|
||||
private editor: React.RefObject<HTMLTextAreaElement>
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
value: this.props.query,
|
||||
focused: false,
|
||||
}
|
||||
|
||||
this.editor = React.createRef<HTMLTextAreaElement>()
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
|
@ -41,21 +43,34 @@ class QueryEditor extends PureComponent<Props, State> {
|
|||
} = this.props
|
||||
const {value} = this.state
|
||||
|
||||
const options = {
|
||||
tabIndex: 1,
|
||||
mode: 'influxQL',
|
||||
readonly: false,
|
||||
lineNumbers: false,
|
||||
autoRefresh: true,
|
||||
theme: 'influxql',
|
||||
completeSingle: false,
|
||||
lineWrapping: true,
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="query-editor">
|
||||
<textarea
|
||||
className="query-editor--field"
|
||||
ref={this.editor}
|
||||
value={value}
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
onBlur={this.handleUpdate}
|
||||
onChange={this.handleChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
data-test="query-editor-field"
|
||||
placeholder="Enter a query or select database, measurement, and field below and have us build one for you..."
|
||||
/>
|
||||
<div className="varmoji">
|
||||
<div className={this.queryCodeClassName}>
|
||||
<ReactCodeMirror
|
||||
autoFocus={true}
|
||||
autoCursor={true}
|
||||
value={value}
|
||||
options={options}
|
||||
onBeforeChange={this.updateCode}
|
||||
onChange={this.handleChange}
|
||||
onTouchStart={this.onTouchStart}
|
||||
onBlur={this.handleBlur}
|
||||
onFocus={this.handleFocus}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
/>
|
||||
</div>
|
||||
<div className={this.varmojiClassName}>
|
||||
<div className="varmoji-container">
|
||||
<div className="varmoji-front">
|
||||
<QueryStatus status={status}>
|
||||
|
@ -66,6 +81,12 @@ class QueryEditor extends PureComponent<Props, State> {
|
|||
className="dropdown-140 query-editor--templates"
|
||||
buttonSize="btn-xs"
|
||||
/>
|
||||
<button
|
||||
className="btn btn-xs btn-primary query-editor--submit"
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
Submit Query
|
||||
</button>
|
||||
</QueryStatus>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -74,32 +95,54 @@ class QueryEditor extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>): void => {
|
||||
const {value} = this.state
|
||||
|
||||
if (e.key === 'Escape') {
|
||||
e.preventDefault()
|
||||
this.setState({value})
|
||||
}
|
||||
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault()
|
||||
this.handleUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private handleChange = (): void => {
|
||||
const value = this.editor.current.value
|
||||
this.setState({value})
|
||||
}
|
||||
|
||||
private handleUpdate = (): void => {
|
||||
private handleSubmit = (): void => {
|
||||
this.props.onUpdate(this.state.value)
|
||||
}
|
||||
|
||||
private get queryCodeClassName(): string {
|
||||
const {focused} = this.state
|
||||
|
||||
return classnames('query-editor--code', {focus: focused})
|
||||
}
|
||||
|
||||
private get varmojiClassName(): string {
|
||||
const {focused} = this.state
|
||||
|
||||
return classnames('varmoji', {focus: focused})
|
||||
}
|
||||
|
||||
private onTouchStart = () => {}
|
||||
|
||||
private handleChange = (): void => {}
|
||||
|
||||
private handleBlur = (): void => {
|
||||
this.setState({focused: false})
|
||||
this.handleSubmit()
|
||||
}
|
||||
|
||||
private handleFocus = (): void => {
|
||||
this.setState({focused: true})
|
||||
}
|
||||
|
||||
private handleChooseMetaQuery = (template: QueryTemplate): void => {
|
||||
this.setState({value: template.query})
|
||||
}
|
||||
|
||||
private handleKeyUp = (__, e: KeyboardEvent) => {
|
||||
const {ctrlKey, metaKey, key} = e
|
||||
|
||||
if (key === 'Enter' && (ctrlKey || metaKey)) {
|
||||
this.handleSubmit()
|
||||
}
|
||||
}
|
||||
|
||||
private updateCode = (
|
||||
_: IInstance,
|
||||
__: EditorChange,
|
||||
value: string
|
||||
): void => {
|
||||
this.setState({value})
|
||||
}
|
||||
}
|
||||
|
||||
export default QueryEditor
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import {modeFlux, modeTickscript} from 'src/shared/constants/codeMirrorModes'
|
||||
import {
|
||||
modeFlux,
|
||||
modeTickscript,
|
||||
modeInfluxQL,
|
||||
} from 'src/shared/constants/codeMirrorModes'
|
||||
import 'codemirror/addon/hint/show-hint'
|
||||
|
||||
/* eslint-disable */
|
||||
|
@ -314,4 +318,5 @@ function indentFunction(states, meta) {
|
|||
|
||||
// Modes
|
||||
CodeMirror.defineSimpleMode('flux', modeFlux)
|
||||
CodeMirror.defineSimpleMode('tickscript', modeTickscript)
|
||||
CodeMirror.defineSimpleMode('tickscript', modeTickscript)
|
||||
CodeMirror.defineSimpleMode('influxQL', modeInfluxQL)
|
|
@ -94,13 +94,14 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
key={i}
|
||||
index={i}
|
||||
func={func}
|
||||
funcs={funcs}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onToggleYield={onToggleYield}
|
||||
isYieldable={isAfterFilter && isAfterRange}
|
||||
isYielding={this.isNextFuncYield(i)}
|
||||
isYielding={this.isBeforeFuncYield(i)}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
|
@ -139,13 +140,14 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
key={i}
|
||||
index={i}
|
||||
func={func}
|
||||
funcs={funcs}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
onDelete={onDeleteFuncNode}
|
||||
onToggleYield={this.handleHideImplicitYield}
|
||||
isYieldable={isAfterFilter && isAfterRange}
|
||||
isYielding={this.isNextFuncYield(i)}
|
||||
isYielding={this.isBeforeFuncYield(i)}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
|
@ -179,7 +181,7 @@ class ExpressionNode extends PureComponent<Props, State> {
|
|||
)
|
||||
}
|
||||
|
||||
private isNextFuncYield(funcIndex: number): boolean {
|
||||
private isBeforeFuncYield(funcIndex: number): boolean {
|
||||
const {funcs, isLastBody} = this.props
|
||||
const {isImplicitYieldToggled} = this.state
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
|
||||
import FuncArgInput from 'src/flux/components/FuncArgInput'
|
||||
import FuncArgTextArea from 'src/flux/components/FuncArgTextArea'
|
||||
|
@ -7,7 +8,7 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
|
|||
import FromDatabaseDropdown from 'src/flux/components/FromDatabaseDropdown'
|
||||
|
||||
import {funcNames, argTypes} from 'src/flux/constants'
|
||||
import {OnChangeArg} from 'src/types/flux'
|
||||
import {OnChangeArg, Arg} from 'src/types/flux'
|
||||
import {Service} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
|
@ -15,6 +16,7 @@ interface Props {
|
|||
funcName: string
|
||||
funcID: string
|
||||
argKey: string
|
||||
args: Arg[]
|
||||
value: string | boolean | {[x: string]: string}
|
||||
type: string
|
||||
bodyID: string
|
||||
|
@ -73,6 +75,7 @@ class FuncArg extends PureComponent<Props> {
|
|||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
autoFocus={this.isFirstArg}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -131,6 +134,14 @@ class FuncArg extends PureComponent<Props> {
|
|||
private get boolValue(): boolean {
|
||||
return this.props.value === true
|
||||
}
|
||||
|
||||
private get isFirstArg(): boolean {
|
||||
const {args, argKey} = this.props
|
||||
|
||||
const firstArg = _.first(args)
|
||||
|
||||
return firstArg.key === argKey
|
||||
}
|
||||
}
|
||||
|
||||
export default FuncArg
|
||||
|
|
|
@ -11,12 +11,13 @@ interface Props {
|
|||
declarationID: string
|
||||
onChangeArg: OnChangeArg
|
||||
onGenerateScript: () => void
|
||||
autoFocus?: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class FuncArgInput extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {argKey, value, type} = this.props
|
||||
const {argKey, value, type, autoFocus} = this.props
|
||||
|
||||
return (
|
||||
<div className="func-arg">
|
||||
|
@ -34,6 +35,7 @@ class FuncArgInput extends PureComponent<Props> {
|
|||
className="form-control input-sm"
|
||||
spellCheck={false}
|
||||
autoComplete="off"
|
||||
autoFocus={autoFocus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,6 @@ interface Props {
|
|||
onChangeArg: OnChangeArg
|
||||
declarationID: string
|
||||
onGenerateScript: () => void
|
||||
onDeleteFunc: (e: MouseEvent<HTMLElement>) => void
|
||||
declarationsFromBody: string[]
|
||||
onStopPropagation: (e: MouseEvent<HTMLElement>) => void
|
||||
}
|
||||
|
@ -24,20 +23,13 @@ interface Props {
|
|||
@ErrorHandling
|
||||
export default class FuncArgs extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {onDeleteFunc, onStopPropagation} = this.props
|
||||
const {onStopPropagation} = this.props
|
||||
|
||||
return (
|
||||
<div className="func-node--tooltip" onClick={onStopPropagation}>
|
||||
<div className="func-node--editor" onClick={onStopPropagation}>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-args">{this.renderArguments}</div>
|
||||
<div className="func-arg--buttons">
|
||||
<div
|
||||
className="btn btn-sm btn-danger btn-square"
|
||||
onClick={onDeleteFunc}
|
||||
>
|
||||
<span className="icon trash" />
|
||||
</div>
|
||||
{this.build}
|
||||
</div>
|
||||
<div className="func-arg--buttons">{this.build}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -67,11 +59,12 @@ export default class FuncArgs extends PureComponent<Props> {
|
|||
onGenerateScript,
|
||||
} = this.props
|
||||
|
||||
const {name: funcName, id: funcID} = func
|
||||
const {name: funcName, id: funcID, args} = func
|
||||
|
||||
return func.args.map(({key, value, type}) => (
|
||||
return args.map(({key, value, type}) => (
|
||||
<FuncArg
|
||||
key={key}
|
||||
args={args}
|
||||
type={type}
|
||||
argKey={key}
|
||||
value={value}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, {PureComponent, MouseEvent} from 'react'
|
||||
import classnames from 'classnames'
|
||||
import _ from 'lodash'
|
||||
|
||||
import FuncArgs from 'src/flux/components/FuncArgs'
|
||||
import FuncArgsPreview from 'src/flux/components/FuncArgsPreview'
|
||||
|
@ -14,6 +15,7 @@ import {Service} from 'src/types'
|
|||
|
||||
interface Props {
|
||||
func: Func
|
||||
funcs: Func[]
|
||||
service: Service
|
||||
bodyID: string
|
||||
index: number
|
||||
|
@ -29,7 +31,7 @@ interface Props {
|
|||
}
|
||||
|
||||
interface State {
|
||||
isExpanded: boolean
|
||||
editing: boolean
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
|
@ -42,53 +44,107 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
super(props)
|
||||
|
||||
this.state = {
|
||||
isExpanded: false,
|
||||
editing: this.isLast,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {func} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onClick={this.handleToggleEdit}
|
||||
title="Edit function arguments"
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
{this.funcMenu}
|
||||
</div>
|
||||
{this.funcArgs}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get funcArgs(): JSX.Element {
|
||||
const {
|
||||
func,
|
||||
bodyID,
|
||||
service,
|
||||
isYielding,
|
||||
onChangeArg,
|
||||
declarationID,
|
||||
onGenerateScript,
|
||||
declarationsFromBody,
|
||||
} = this.props
|
||||
const {isExpanded} = this.state
|
||||
const {editing} = this.state
|
||||
|
||||
if (!editing || isYielding) {
|
||||
return
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={this.nodeClassName}
|
||||
onMouseEnter={this.handleMouseEnter}
|
||||
onMouseLeave={this.handleMouseLeave}
|
||||
onClick={this.handleClick}
|
||||
>
|
||||
<div className="func-node--connector" />
|
||||
<div className="func-node--name">{func.name}</div>
|
||||
<FuncArgsPreview func={func} />
|
||||
<FuncArgs
|
||||
func={func}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onStopPropagation={this.handleClickArgs}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{isExpanded && (
|
||||
<FuncArgs
|
||||
func={func}
|
||||
bodyID={bodyID}
|
||||
service={service}
|
||||
onChangeArg={onChangeArg}
|
||||
declarationID={declarationID}
|
||||
onGenerateScript={onGenerateScript}
|
||||
onDeleteFunc={this.handleDelete}
|
||||
declarationsFromBody={declarationsFromBody}
|
||||
onStopPropagation={this.handleClickArgs}
|
||||
/>
|
||||
)}
|
||||
private get funcMenu(): JSX.Element {
|
||||
return (
|
||||
<div className="func-node--menu">
|
||||
{this.yieldToggleButton}
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-danger"
|
||||
onClick={this.handleDelete}
|
||||
title="Delete this Function"
|
||||
>
|
||||
<span className="icon trash" />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get yieldToggleButton(): JSX.Element {
|
||||
const {isYielding} = this.props
|
||||
|
||||
if (isYielding) {
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-warning"
|
||||
onClick={this.handleToggleYield}
|
||||
title="Hide Data Table"
|
||||
>
|
||||
<span className="icon eye-closed" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
className="btn btn-sm btn-square btn-warning"
|
||||
onClick={this.handleToggleYield}
|
||||
title="See Data Table returned by this Function"
|
||||
>
|
||||
<span className="icon eye-open" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
private get nodeClassName(): string {
|
||||
const {isYielding} = this.props
|
||||
return classnames('func-node', {active: isYielding})
|
||||
const {editing} = this.state
|
||||
|
||||
return classnames('func-node', {active: isYielding || editing})
|
||||
}
|
||||
|
||||
private handleDelete = (e: MouseEvent<HTMLElement>): void => {
|
||||
|
@ -98,19 +154,11 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
this.props.onDelete({funcID: func.id, bodyID, declarationID})
|
||||
}
|
||||
|
||||
private handleMouseEnter = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
this.setState({isExpanded: true})
|
||||
private handleToggleEdit = (): void => {
|
||||
this.setState({editing: !this.state.editing})
|
||||
}
|
||||
|
||||
private handleMouseLeave = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
this.setState({isExpanded: false})
|
||||
}
|
||||
|
||||
private handleClick = (e: MouseEvent<HTMLElement>): void => {
|
||||
private handleToggleYield = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
|
||||
const {
|
||||
|
@ -128,7 +176,16 @@ export default class FuncNode extends PureComponent<Props, State> {
|
|||
onToggleYieldWithLast(index)
|
||||
}
|
||||
}
|
||||
|
||||
private handleClickArgs = (e: MouseEvent<HTMLElement>): void => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
private get isLast(): boolean {
|
||||
const {funcs, func} = this.props
|
||||
|
||||
const lastFunc = _.last(funcs)
|
||||
|
||||
return lastFunc.id === func.id
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ interface Props {
|
|||
onSubmitScript: OnSubmitScript
|
||||
onAppendFrom: () => void
|
||||
onAppendJoin: () => void
|
||||
onAnalyze: () => void
|
||||
onValidate: () => void
|
||||
}
|
||||
|
||||
interface Body extends FlatBody {
|
||||
|
@ -87,7 +87,7 @@ class TimeMachine extends PureComponent<Props> {
|
|||
script,
|
||||
status,
|
||||
service,
|
||||
onAnalyze,
|
||||
onValidate,
|
||||
suggestions,
|
||||
onChangeScript,
|
||||
onSubmitScript,
|
||||
|
@ -96,14 +96,15 @@ class TimeMachine extends PureComponent<Props> {
|
|||
return [
|
||||
{
|
||||
name: 'Script',
|
||||
handlePixels: 44,
|
||||
headerOrientation: HANDLE_VERTICAL,
|
||||
headerButtons: [
|
||||
<div
|
||||
key="analyze"
|
||||
className="btn btn-default btn-xs analyze--button"
|
||||
onClick={onAnalyze}
|
||||
key="validate"
|
||||
className="btn btn-default btn-xs validate--button"
|
||||
onClick={onValidate}
|
||||
>
|
||||
Analyze
|
||||
Validate
|
||||
</div>,
|
||||
],
|
||||
menuOptions: [],
|
||||
|
@ -120,6 +121,7 @@ class TimeMachine extends PureComponent<Props> {
|
|||
},
|
||||
{
|
||||
name: 'Explore',
|
||||
handlePixels: 44,
|
||||
headerButtons: [],
|
||||
menuOptions: [],
|
||||
render: () => <SchemaExplorer service={service} />,
|
||||
|
|
|
@ -54,7 +54,7 @@ class TimeMachineVis extends PureComponent<Props, State> {
|
|||
currentView={visType}
|
||||
onToggleView={this.selectVisType}
|
||||
/>
|
||||
<span>{yieldName}</span>
|
||||
<div className="yield-node--name">{`"${yieldName}"`}</div>
|
||||
</div>
|
||||
<div className="yield-node--visualization">{this.vis}</div>
|
||||
</>
|
||||
|
|
|
@ -7,7 +7,7 @@ import {ErrorHandling} from 'src/shared/decorators/errors'
|
|||
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
|
||||
|
||||
import {
|
||||
analyzeSuccess,
|
||||
validateSuccess,
|
||||
fluxTimeSeriesError,
|
||||
fluxResponseTruncatedError,
|
||||
} from 'src/shared/copy/notifications'
|
||||
|
@ -109,7 +109,7 @@ export class FluxPage extends PureComponent<Props, State> {
|
|||
status={status}
|
||||
service={this.service}
|
||||
suggestions={suggestions}
|
||||
onAnalyze={this.handleAnalyze}
|
||||
onValidate={this.handleValidate}
|
||||
onAppendFrom={this.handleAppendFrom}
|
||||
onAppendJoin={this.handleAppendJoin}
|
||||
onChangeScript={this.handleChangeScript}
|
||||
|
@ -581,14 +581,14 @@ export class FluxPage extends PureComponent<Props, State> {
|
|||
}, '')
|
||||
}
|
||||
|
||||
private handleAnalyze = async () => {
|
||||
private handleValidate = async () => {
|
||||
const {links, notify, script} = this.props
|
||||
|
||||
try {
|
||||
const ast = await getAST({url: links.ast, body: script})
|
||||
const body = bodyNodes(ast, this.state.suggestions)
|
||||
const status = {type: 'success', text: ''}
|
||||
notify(analyzeSuccess)
|
||||
notify(validateSuccess())
|
||||
|
||||
this.setState({ast, body, status})
|
||||
} catch (error) {
|
||||
|
|
|
@ -102,7 +102,11 @@ export class RuleRow extends PureComponent<RuleRowProps> {
|
|||
<td style={{width: colTrigger, textTransform: 'capitalize'}}>
|
||||
{rule.trigger}
|
||||
</td>
|
||||
<td style={{width: colMessage}}>{rule.message}</td>
|
||||
<td style={{width: colMessage}}>
|
||||
<span className="text-ellipsis" style={{maxWidth: colMessage}}>
|
||||
{rule.message}
|
||||
</span>
|
||||
</td>
|
||||
<td style={{width: colAlerts}}>{parseAlertNodeList(rule)}</td>
|
||||
<td style={{width: colEnabled}} className="text-center">
|
||||
<div className="dark-checkbox">
|
||||
|
|
|
@ -8,7 +8,11 @@ import classnames from 'classnames'
|
|||
import calculateSize from 'calculate-size'
|
||||
|
||||
import DivisionHeader from 'src/shared/components/threesizer/DivisionHeader'
|
||||
import {HANDLE_VERTICAL, HANDLE_HORIZONTAL} from 'src/shared/constants/index'
|
||||
import {
|
||||
HANDLE_VERTICAL,
|
||||
HANDLE_HORIZONTAL,
|
||||
MIN_HANDLE_PIXELS,
|
||||
} from 'src/shared/constants/index'
|
||||
import {MenuItem} from 'src/shared/components/threesizer/DivisionMenu'
|
||||
|
||||
const NOOP = () => {}
|
||||
|
@ -67,38 +71,41 @@ class Division extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {name, render, draggable, menuOptions, headerButtons} = this.props
|
||||
const {render} = this.props
|
||||
return (
|
||||
<div
|
||||
className={this.containerClass}
|
||||
style={this.containerStyle}
|
||||
ref={this.ref}
|
||||
>
|
||||
<div
|
||||
style={this.handleStyle}
|
||||
title={this.title}
|
||||
draggable={draggable}
|
||||
onDragStart={this.drag}
|
||||
className={this.handleClass}
|
||||
onDoubleClick={this.handleDoubleClick}
|
||||
>
|
||||
<div className={this.titleClass}>{name}</div>
|
||||
</div>
|
||||
{this.renderDragHandle}
|
||||
<div className={this.contentsClass} style={this.contentStyle}>
|
||||
{name && (
|
||||
<DivisionHeader
|
||||
buttons={headerButtons}
|
||||
menuOptions={menuOptions}
|
||||
onMinimize={this.handleMinimize}
|
||||
onMaximize={this.handleMaximize}
|
||||
/>
|
||||
)}
|
||||
{this.renderHeader}
|
||||
<div className="threesizer--body">{render(this.visibility)}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get renderHeader(): JSX.Element {
|
||||
const {name, headerButtons, menuOptions, orientation} = this.props
|
||||
|
||||
if (!name) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (orientation === HANDLE_VERTICAL) {
|
||||
return (
|
||||
<DivisionHeader
|
||||
buttons={headerButtons}
|
||||
menuOptions={menuOptions}
|
||||
onMinimize={this.handleMinimize}
|
||||
onMaximize={this.handleMaximize}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private get visibility(): string {
|
||||
if (this.props.size === 0) {
|
||||
return 'hidden'
|
||||
|
@ -123,6 +130,56 @@ class Division extends PureComponent<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
private get renderDragHandle(): JSX.Element {
|
||||
const {draggable} = this.props
|
||||
|
||||
return (
|
||||
<div
|
||||
style={this.handleStyle}
|
||||
title={this.title}
|
||||
draggable={draggable}
|
||||
onDragStart={this.drag}
|
||||
className={this.handleClass}
|
||||
onDoubleClick={this.handleDoubleClick}
|
||||
>
|
||||
{this.renderDragHandleContents}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get renderDragHandleContents(): JSX.Element {
|
||||
const {
|
||||
name,
|
||||
handlePixels,
|
||||
orientation,
|
||||
headerButtons,
|
||||
menuOptions,
|
||||
} = this.props
|
||||
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
|
||||
if (
|
||||
orientation === HANDLE_HORIZONTAL &&
|
||||
handlePixels >= MIN_HANDLE_PIXELS
|
||||
) {
|
||||
return (
|
||||
<DivisionHeader
|
||||
buttons={headerButtons}
|
||||
menuOptions={menuOptions}
|
||||
onMinimize={this.handleMinimize}
|
||||
onMaximize={this.handleMaximize}
|
||||
name={name}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (handlePixels >= MIN_HANDLE_PIXELS) {
|
||||
return <div className={this.titleClass}>{name}</div>
|
||||
}
|
||||
}
|
||||
|
||||
private get handleStyle(): CSSProperties {
|
||||
const {handleDisplay: display, orientation, handlePixels} = this.props
|
||||
|
||||
|
@ -178,7 +235,7 @@ class Division extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
private get handleClass(): string {
|
||||
const {draggable, orientation} = this.props
|
||||
const {draggable, orientation, name} = this.props
|
||||
|
||||
const collapsed = orientation === HANDLE_VERTICAL && this.isTitleObscured
|
||||
|
||||
|
@ -188,6 +245,7 @@ class Division extends PureComponent<Props> {
|
|||
dragging: this.isDragging,
|
||||
vertical: orientation === HANDLE_VERTICAL,
|
||||
horizontal: orientation === HANDLE_HORIZONTAL,
|
||||
named: name,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,18 +8,32 @@ interface Props {
|
|||
onMaximize: () => void
|
||||
buttons: JSX.Element[]
|
||||
menuOptions?: MenuItem[]
|
||||
name?: string
|
||||
}
|
||||
|
||||
class DivisionHeader extends PureComponent<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<div className="threesizer--header">
|
||||
{this.props.buttons.map(b => b)}
|
||||
<DivisionMenu menuItems={this.menuItems} />
|
||||
{this.renderName}
|
||||
<div className="threesizer--header-controls">
|
||||
{this.props.buttons.map(b => b)}
|
||||
<DivisionMenu menuItems={this.menuItems} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private get renderName(): JSX.Element {
|
||||
const {name} = this.props
|
||||
|
||||
if (!name) {
|
||||
return
|
||||
}
|
||||
|
||||
return <div className="threesizer--header-name">{name}</div>
|
||||
}
|
||||
|
||||
private get menuItems(): MenuItem[] {
|
||||
const {onMaximize, onMinimize, menuOptions} = this.props
|
||||
return [
|
||||
|
|
|
@ -174,3 +174,80 @@ export const modeTickscript = {
|
|||
lineComment: '//',
|
||||
},
|
||||
}
|
||||
|
||||
export const modeInfluxQL = {
|
||||
// The start state contains the rules that are intially used
|
||||
start: [
|
||||
// The regex matches the token, the token property contains the type
|
||||
{
|
||||
regex: /"(?:[^\\]|\\.)*?(?:"|$)/,
|
||||
token: 'string.double',
|
||||
},
|
||||
{
|
||||
regex: /'(?:[^\\]|\\.)*?(?:'|$)/,
|
||||
token: 'string.single',
|
||||
},
|
||||
{
|
||||
regex: /(function)(\s+)([a-z$][\w$]*)/,
|
||||
token: ['keyword', null, 'variable-2'],
|
||||
},
|
||||
// Rules are matched in the order in which they appear, so there is
|
||||
// no ambiguity between this one and the one above
|
||||
{
|
||||
regex: /(SELECT\s|AS\s|FROM\s|WHERE\s|GROUP\sBY\s)/i,
|
||||
token: 'clause',
|
||||
},
|
||||
{
|
||||
regex: /FILL(?=[(])/i,
|
||||
token: 'clause',
|
||||
},
|
||||
{
|
||||
regex: /(CREATE\s|SHOW\s|DROP\s)/i,
|
||||
token: 'meta',
|
||||
},
|
||||
{
|
||||
regex: /0x[a-f\d]+|[-+]?(?:\.\d+|\d+\.?\d*)(?:e[-+]?\d+)?/i,
|
||||
token: 'number',
|
||||
},
|
||||
{
|
||||
regex: /[:](interval|dashboardTime|dashboardUpper)[:]/,
|
||||
token: 'temp-system',
|
||||
},
|
||||
{
|
||||
regex: /[:]\w+[:]/,
|
||||
token: 'temp-var',
|
||||
},
|
||||
{
|
||||
regex: /now[(][)]\s\S\s\S+/,
|
||||
token: 'now',
|
||||
},
|
||||
{
|
||||
regex: /[-+\/*=~<>!]+/,
|
||||
token: 'operator',
|
||||
},
|
||||
{
|
||||
regex: /(NULL)/i,
|
||||
token: 'null',
|
||||
},
|
||||
],
|
||||
// The multi-line comment state.
|
||||
comment: [
|
||||
{
|
||||
regex: /.*?\*\//,
|
||||
token: 'comment',
|
||||
next: 'start',
|
||||
},
|
||||
{
|
||||
regex: /.*/,
|
||||
token: 'comment',
|
||||
},
|
||||
],
|
||||
// The meta property contains global information about the mode. It
|
||||
// can contain properties like lineComment, which are supported by
|
||||
// all modes, and also directives like dontIndentStates, which are
|
||||
// specific to simple modes.
|
||||
meta: {
|
||||
dontIndentStates: ['comment'],
|
||||
lineComment: '//',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -481,6 +481,7 @@ export const HANDLE_VERTICAL = 'vertical'
|
|||
export const HANDLE_HORIZONTAL = 'horizontal'
|
||||
export const HANDLE_NONE = 'none'
|
||||
export const HANDLE_PIXELS = 20
|
||||
export const MIN_HANDLE_PIXELS = 20
|
||||
export const MAX_SIZE = 1
|
||||
export const MIN_SIZE = 0
|
||||
|
||||
|
|
|
@ -660,10 +660,10 @@ export const notifyKapacitorNotFound = () => ({
|
|||
})
|
||||
|
||||
// Flux notifications
|
||||
export const analyzeSuccess = {
|
||||
export const validateSuccess = () => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'No errors found. Happy Happy Joy Joy!',
|
||||
}
|
||||
})
|
||||
|
||||
export const notifyCopyToClipboardSuccess = text => ({
|
||||
...defaultSuccessNotification,
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
CodeMirror "InfluxQL" Theme
|
||||
------------------------------------------------------------------------------
|
||||
Intended for use with the influxQL CodeMirror Mode
|
||||
*/
|
||||
|
||||
.cm-s-influxql {
|
||||
color: $g11-sidewalk;
|
||||
font-weight: 600;
|
||||
|
||||
.cm-clause {
|
||||
color: $c-pool;
|
||||
}
|
||||
.cm-meta {
|
||||
color: $c-honeydew;
|
||||
}
|
||||
.cm-string {
|
||||
color: $g15-platinum;
|
||||
}
|
||||
.cm-comment {
|
||||
color: $g8-storm;
|
||||
}
|
||||
.cm-number {
|
||||
color: $c-pineapple;
|
||||
}
|
||||
.cm-operator {
|
||||
color: $c-pool;
|
||||
}
|
||||
.cm-temp-var {
|
||||
color: $c-comet;
|
||||
}
|
||||
.cm-temp-system {
|
||||
color: #ff4d9e ;
|
||||
}
|
||||
.cm-now {
|
||||
color: $c-pineapple;
|
||||
}
|
||||
.cm-null {
|
||||
color: $g8-storm;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
.cm-s-time-machine {
|
||||
background-color: $g1-raven;
|
||||
color: $g11-sidewalk;
|
||||
|
||||
.cm-variable {
|
||||
|
@ -46,4 +47,13 @@
|
|||
.cm-comment {
|
||||
color: $g8-storm;
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.CodeMirror-vscrollbar,
|
||||
.CodeMirror-hscrollbar {
|
||||
@include custom-scrollbar-round($g1-raven, $g6-smoke);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,4 +90,5 @@ div.CodeMirror-selected,
|
|||
*/
|
||||
@import 'time-machine';
|
||||
@import 'tickscript';
|
||||
@import 'influxql';
|
||||
@import 'hints';
|
||||
|
|
|
@ -13,40 +13,15 @@
|
|||
position: relative;
|
||||
z-index: 3; /* Minimum amount to obcure the toggle flip within Query Builder. Will fix later */
|
||||
}
|
||||
.query-editor--field {
|
||||
font-family: $code-font;
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
font-weight: 600;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
@include custom-scrollbar($query-editor--field-bg, $query-editor--field-text);
|
||||
display: block;
|
||||
resize: none;
|
||||
width: 100%;
|
||||
height: $query-editor--field-height;
|
||||
transition:
|
||||
color 0.25s ease,
|
||||
background-color 0.25s ease,
|
||||
border-color 0.25s ease;
|
||||
.query-editor--code {
|
||||
background-color: $query-editor--field-bg;
|
||||
border: 2px solid $query-editor--bg;
|
||||
border-bottom: 0;
|
||||
background-color: $query-editor--field-bg;
|
||||
color: $query-editor--field-text;
|
||||
padding: 12px 10px 0 10px;
|
||||
border-radius: $radius $radius 0 0;
|
||||
margin: 0;
|
||||
padding: 6px 8px;
|
||||
transition: border-color 0.25s ease;
|
||||
|
||||
&:hover,
|
||||
&:hover + .query-editor--status {
|
||||
border-color: $query-editor--bg;
|
||||
}
|
||||
&:focus {
|
||||
outline: none;
|
||||
color: $query-editor--field-text !important;
|
||||
border-color: $c-pool;
|
||||
}
|
||||
&:focus + .varmoji {
|
||||
&.focus {
|
||||
border-color: $c-pool;
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +71,9 @@
|
|||
max-width: $query-editor--templates-menu-width;
|
||||
}
|
||||
}
|
||||
button.btn.query-editor--submit {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
@ -113,6 +91,10 @@
|
|||
height: $query-editor--status-height;
|
||||
width: 100%;
|
||||
perspective: 1000px;
|
||||
|
||||
&.focus {
|
||||
border-color: $c-pool;
|
||||
}
|
||||
}
|
||||
.varmoji-container {
|
||||
transition: transform 0.6s ease;
|
||||
|
|
|
@ -149,6 +149,27 @@ $threesizer-shadow-stop: fade-out($g0-obsidian, 1);
|
|||
}
|
||||
}
|
||||
|
||||
.threesizer--header-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: $g11-sidewalk;
|
||||
padding-left: 4px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.threesizer--header-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
|
||||
> * {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.threesizer--body {
|
||||
.horizontal>&:only-child {
|
||||
width: 100%;
|
||||
|
@ -168,10 +189,6 @@ $threesizer-shadow-stop: fade-out($g0-obsidian, 1);
|
|||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.analyze--button {
|
||||
margin-right: 3px
|
||||
}
|
||||
|
||||
.dash-graph-context--button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
@ -307,4 +324,25 @@ $threesizer-shadow-stop: fade-out($g0-obsidian, 1);
|
|||
// Hide Header children when collapsed
|
||||
.threesizer--handle.vertical.threesizer--collapsed+.threesizer--contents>.threesizer--header>* {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// When threesizer has horizontal handles, division headers appear inside
|
||||
// the drag handle and styles must adapt
|
||||
.threesizer--handle.horizontal.named {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
|
||||
.threesizer--header {
|
||||
border-right: 0;
|
||||
border-bottom: 2px solid $g4-onyx;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
transition: background-color 0.25s ease;
|
||||
}
|
||||
|
||||
&:hover .threesizer--header,
|
||||
&.dragging .threesizer--header {
|
||||
background-color: $g3-castle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,35 +248,47 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
}
|
||||
}
|
||||
|
||||
.func-node--tooltip {
|
||||
.func-node--menu {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate(100%, -50%);
|
||||
opacity: 0;
|
||||
transition: opacity 0.25s ease;
|
||||
|
||||
> button.btn {
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.func-node:hover .func-node--menu,
|
||||
.func-node.editing .func-node--menu,
|
||||
.func-node.active .func-node--menu {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.func-node--editor {
|
||||
position: relative;
|
||||
margin-left: $flux-node-gap;
|
||||
margin-bottom: $flux-node-gap;
|
||||
margin-top: $flux-node-tooltip-gap / 2;
|
||||
background-color: $g3-castle;
|
||||
border-radius: $radius;
|
||||
padding: 10px;
|
||||
padding: 6px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: calc(100% + #{$flux-node-tooltip-gap});
|
||||
z-index: 9999;
|
||||
box-shadow: 0 0 10px 2px $g2-kevlar; // Caret
|
||||
}
|
||||
|
||||
.func-node--editor .func-node--connector {
|
||||
// Vertical Line
|
||||
&:before {
|
||||
content: '';
|
||||
border-width: 9px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
border-right-color: $g3-castle;
|
||||
position: absolute;
|
||||
top: $flux-node-height / 2;
|
||||
left: 0;
|
||||
transform: translate(-100%, -50%);
|
||||
} // Invisible block to continue hovering
|
||||
height: calc(100% + #{($flux-node-tooltip-gap / 2) + $flux-node-gap});
|
||||
}
|
||||
// Horizontal Line
|
||||
&:after {
|
||||
content: '';
|
||||
height: 50%;
|
||||
width: $flux-node-tooltip-gap * 3;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -$flux-node-tooltip-gap * 3;
|
||||
content: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +296,6 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.func-node--build {
|
||||
|
@ -313,7 +324,7 @@ $flux-invalid-hover: $c-dreamsicle;
|
|||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: $g10-wolf;
|
||||
padding-right: 8px;
|
||||
padding: 0 8px;
|
||||
@include no-user-select();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ $flux-tree-gutter: 11px;
|
|||
height: 100%;
|
||||
background-color: $g2-kevlar;
|
||||
min-width: $flux-tree-min-width;
|
||||
padding-left: 30px;
|
||||
}
|
||||
|
||||
.flux-schema-tree {
|
||||
|
|
|
@ -27,6 +27,17 @@ $flux-builder-yield-tabs-max-width: 400px;
|
|||
background-color: $g3-castle;
|
||||
padding: $flux-node-padding;
|
||||
border-radius: $radius $radius 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.yield-node--name {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-right: 6px;
|
||||
@include no-user-select();
|
||||
color: $c-honeydew;
|
||||
}
|
||||
|
||||
.yield-node--visualization {
|
||||
|
@ -56,8 +67,8 @@ $flux-builder-yield-tabs-max-width: 400px;
|
|||
}
|
||||
|
||||
.yield-node--sidebar-filter.form-control.input-xs {
|
||||
font-size: 12px;
|
||||
}
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
// Tabs
|
||||
.yield-node--tabs {
|
||||
|
@ -124,7 +135,11 @@ $flux-builder-yield-tabs-max-width: 400px;
|
|||
flex: 1 0 0;
|
||||
background-color: $g3-castle;
|
||||
overflow: hidden;
|
||||
border-radius: 0 $radius $radius 0;
|
||||
border-radius: 0 0 $radius $radius;
|
||||
|
||||
&:only-child {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Line Graph
|
||||
|
|
|
@ -22,7 +22,6 @@ $table--highlight-color: $g4-onyx;
|
|||
font-family: $code-font;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
&.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -32,6 +31,13 @@ $table--highlight-color: $g4-onyx;
|
|||
&.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
& > .text-ellipsis {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
// Header
|
||||
|
|
|
@ -10,6 +10,7 @@ const setup = () => {
|
|||
funcName: '',
|
||||
declarationID: '',
|
||||
argKey: '',
|
||||
args: [],
|
||||
value: '',
|
||||
type: '',
|
||||
service,
|
||||
|
|
|
@ -12,7 +12,7 @@ const setup = () => {
|
|||
suggestions: [],
|
||||
onSubmitScript: () => {},
|
||||
onChangeScript: () => {},
|
||||
onAnalyze: () => {},
|
||||
onValidate: () => {},
|
||||
onAppendFrom: () => {},
|
||||
onAppendJoin: () => {},
|
||||
status: {type: '', text: ''},
|
||||
|
|
Loading…
Reference in New Issue