Persist ifql script
Co-authored-by: Andrew Watkins <andrew.watkinz@gmail.com> Co-authored-by: Chris Henn <chris.henn@influxdata.com>ifql/save-service
parent
b778fd9756
commit
4326855844
|
@ -0,0 +1,17 @@
|
|||
export type Action = ActionUpdateScript
|
||||
|
||||
export interface ActionUpdateScript {
|
||||
type: 'UPDATE_SCRIPT'
|
||||
payload: {
|
||||
script: string
|
||||
}
|
||||
}
|
||||
|
||||
export type UpdateScript = (script: string) => ActionUpdateScript
|
||||
|
||||
export const updateScript = (script: string): ActionUpdateScript => {
|
||||
return {
|
||||
type: 'UPDATE_SCRIPT',
|
||||
payload: {script},
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import AJAX from 'src/utils/ajax'
|
||||
import {Service} from 'src/types'
|
||||
import {updateService} from 'src/shared/apis'
|
||||
|
||||
export const getSuggestions = async (url: string) => {
|
||||
try {
|
||||
|
@ -34,17 +36,24 @@ export const getAST = async (request: ASTRequest) => {
|
|||
}
|
||||
}
|
||||
|
||||
export const getTimeSeries = async (script: string) => {
|
||||
export const getTimeSeries = async (service: Service, script: string) => {
|
||||
const and = encodeURIComponent('&')
|
||||
const mark = encodeURIComponent('?')
|
||||
const garbage = script.replace(/\s/g, '') // server cannot handle whitespace
|
||||
|
||||
try {
|
||||
const data = await AJAX({
|
||||
method: 'POST',
|
||||
url: `http://localhost:8093/query?q=${script}`,
|
||||
url: `${
|
||||
service.links.proxy
|
||||
}?path=/v1/query${mark}orgName=defaulorgname${and}q=${garbage}`,
|
||||
headers: {'Content-Type': 'text/plain'},
|
||||
})
|
||||
|
||||
return data
|
||||
} catch (error) {
|
||||
console.error('Problem fetching data', error)
|
||||
throw error
|
||||
throw error.data.message
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,3 +91,19 @@ export const getTagValues = async () => {
|
|||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export const updateScript = async (service: Service, script: string) => {
|
||||
const updates = {...service, metadata: {script}}
|
||||
|
||||
try {
|
||||
const response = await updateService(updates)
|
||||
return response
|
||||
} catch (error) {
|
||||
if (error.data) {
|
||||
console.error('Could not update script', error.data)
|
||||
throw error.data
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,3 +58,6 @@ export const EXCLUDED_KEYS = [
|
|||
'Meta',
|
||||
' ',
|
||||
]
|
||||
|
||||
export const DEFAULT_SCRIPT =
|
||||
'fil = (r) => r._measurement == "cpu"\ntele = from(db: "telegraf") \n\t\t|> filter(fn: fil)\n |> range(start: -1m)\n |> sum()\n\n'
|
||||
|
|
|
@ -10,11 +10,14 @@ import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
|
|||
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {analyzeSuccess} from 'src/shared/copy/notifications'
|
||||
import {
|
||||
updateScript as updateScriptAction,
|
||||
UpdateScript,
|
||||
} from 'src/ifql/actions'
|
||||
|
||||
import {bodyNodes} from 'src/ifql/helpers'
|
||||
import {getSuggestions, getAST, getTimeSeries} from 'src/ifql/apis'
|
||||
import {builder, argTypes} from 'src/ifql/constants'
|
||||
import {funcNames} from 'src/ifql/constants'
|
||||
import {funcNames, builder, argTypes} from 'src/ifql/constants'
|
||||
|
||||
import {Source, Service, Notification} from 'src/types'
|
||||
import {
|
||||
|
@ -37,6 +40,11 @@ interface Props {
|
|||
services: Service[]
|
||||
sources: Source[]
|
||||
notify: (message: Notification) => void
|
||||
script: string
|
||||
updateScript: UpdateScript
|
||||
params: {
|
||||
sourceID: string
|
||||
}
|
||||
}
|
||||
|
||||
interface Body extends FlatBody {
|
||||
|
@ -46,7 +54,6 @@ interface Body extends FlatBody {
|
|||
interface State {
|
||||
body: Body[]
|
||||
ast: object
|
||||
script: string
|
||||
data: string
|
||||
suggestions: Suggestion[]
|
||||
status: Status
|
||||
|
@ -63,7 +70,6 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
ast: null,
|
||||
data: 'Hit "Get Data!" or Ctrl + Enter to run your script',
|
||||
suggestions: [],
|
||||
script: `fil = (r) => r._measurement == \"cpu\"\ntele = from(db: \"telegraf\") \n\t\t|> filter(fn: fil)\n |> range(start: -1m)\n |> sum()\n\n`,
|
||||
status: {
|
||||
type: 'none',
|
||||
text: '',
|
||||
|
@ -72,7 +78,7 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const {links} = this.props
|
||||
const {links, script} = this.props
|
||||
|
||||
try {
|
||||
const suggestions = await getSuggestions(links.suggestions)
|
||||
|
@ -81,11 +87,12 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
console.error('Could not get function suggestions: ', error)
|
||||
}
|
||||
|
||||
this.getASTResponse(this.state.script)
|
||||
this.getASTResponse(script)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {suggestions, script, data, body, status} = this.state
|
||||
const {suggestions, data, body, status} = this.state
|
||||
const {script} = this.props
|
||||
|
||||
return (
|
||||
<CheckServices>
|
||||
|
@ -140,7 +147,7 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleSubmitScript = () => {
|
||||
this.getASTResponse(this.state.script)
|
||||
this.getASTResponse(this.props.script)
|
||||
}
|
||||
|
||||
private handleGenerateScript = (): void => {
|
||||
|
@ -260,21 +267,21 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleAppendFrom = (): void => {
|
||||
const {script} = this.state
|
||||
const {script} = this.props
|
||||
const newScript = `${script.trim()}\n\n${builder.NEW_FROM}\n\n`
|
||||
|
||||
this.getASTResponse(newScript)
|
||||
}
|
||||
|
||||
private handleAppendJoin = (): void => {
|
||||
const {script} = this.state
|
||||
const {script} = this.props
|
||||
const newScript = `${script.trim()}\n\n${builder.NEW_JOIN}\n\n`
|
||||
|
||||
this.getASTResponse(newScript)
|
||||
}
|
||||
|
||||
private handleChangeScript = (script: string): void => {
|
||||
this.setState({script})
|
||||
this.props.updateScript(script)
|
||||
}
|
||||
|
||||
private handleAddNode = (
|
||||
|
@ -376,10 +383,10 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleAnalyze = async () => {
|
||||
const {links, notify} = this.props
|
||||
const {links, notify, script} = this.props
|
||||
|
||||
try {
|
||||
const ast = await getAST({url: links.ast, body: this.state.script})
|
||||
const ast = await getAST({url: links.ast, body: script})
|
||||
const body = bodyNodes(ast, this.state.suggestions)
|
||||
const status = {type: 'success', text: ''}
|
||||
notify(analyzeSuccess)
|
||||
|
@ -411,7 +418,8 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
})
|
||||
const body = bodyNodes(ast, suggestions)
|
||||
const status = {type: 'success', text: ''}
|
||||
this.setState({ast, script, body, status})
|
||||
this.setState({ast, body, status})
|
||||
this.props.updateScript(script)
|
||||
} catch (error) {
|
||||
this.setState({status: this.parseError(error)})
|
||||
return console.error('Could not parse AST', error)
|
||||
|
@ -419,14 +427,14 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private getTimeSeries = async () => {
|
||||
const {script} = this.state
|
||||
const {script} = this.props
|
||||
this.setState({data: 'fetching data...'})
|
||||
|
||||
try {
|
||||
const {data} = await getTimeSeries(script)
|
||||
const {data} = await getTimeSeries(this.service, script)
|
||||
this.setState({data})
|
||||
} catch (error) {
|
||||
this.setState({data: 'Error fetching data'})
|
||||
this.setState({data: error})
|
||||
console.error('Could not get timeSeries', error)
|
||||
}
|
||||
|
||||
|
@ -440,12 +448,13 @@ export class IFQLPage extends PureComponent<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = ({links, services, sources}) => {
|
||||
return {links: links.ifql, services, sources}
|
||||
const mapStateToProps = ({links, services, sources, script}) => {
|
||||
return {links: links.ifql, services, sources, script}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
notify: notifyAction,
|
||||
updateScript: updateScriptAction,
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(IFQLPage)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import {Action} from 'src/ifql/actions'
|
||||
import {editor} from 'src/ifql/constants'
|
||||
|
||||
const scriptReducer = (
|
||||
state: string = editor.DEFAULT_SCRIPT,
|
||||
action: Action
|
||||
): string => {
|
||||
switch (action.type) {
|
||||
case 'UPDATE_SCRIPT': {
|
||||
return action.payload.script
|
||||
}
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
export default scriptReducer
|
|
@ -56,6 +56,7 @@ export const saveToLocalStorage = ({
|
|||
timeRange,
|
||||
dataExplorer,
|
||||
dashTimeV1: {ranges},
|
||||
script,
|
||||
}: LocalStorage): void => {
|
||||
try {
|
||||
const appPersisted = {app: {persisted}}
|
||||
|
@ -70,6 +71,7 @@ export const saveToLocalStorage = ({
|
|||
dashTimeV1,
|
||||
dataExplorer,
|
||||
dataExplorerQueryConfigs,
|
||||
script,
|
||||
})
|
||||
)
|
||||
} catch (err) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import overlayTechnology from 'src/shared/reducers/overlayTechnology'
|
|||
import dashTimeV1 from 'src/dashboards/reducers/dashTimeV1'
|
||||
import persistStateEnhancer from './persistStateEnhancer'
|
||||
import servicesReducer from 'src/shared/reducers/services'
|
||||
import scriptReducer from 'src/ifql/reducers/script'
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
...statusReducers,
|
||||
|
@ -30,6 +31,7 @@ const rootReducer = combineReducers({
|
|||
dashTimeV1,
|
||||
routing: routerReducer,
|
||||
services: servicesReducer,
|
||||
script: scriptReducer,
|
||||
})
|
||||
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
|
||||
|
|
|
@ -7,6 +7,7 @@ export interface LocalStorage {
|
|||
dataExplorer: DataExplorer
|
||||
dataExplorerQueryConfigs: DataExplorerQueryConfigs
|
||||
timeRange: TimeRange
|
||||
script: string
|
||||
}
|
||||
|
||||
export type VERSION = string
|
||||
|
|
|
@ -10,6 +10,7 @@ export interface NewService {
|
|||
|
||||
export interface Service {
|
||||
id?: string
|
||||
sourceID: string
|
||||
url: string
|
||||
name: string
|
||||
type: string
|
||||
|
@ -17,6 +18,9 @@ export interface Service {
|
|||
password?: string
|
||||
active: boolean
|
||||
insecureSkipVerify: boolean
|
||||
metadata: {
|
||||
[x: string]: any
|
||||
}
|
||||
links: {
|
||||
source: string
|
||||
self: string
|
||||
|
|
|
@ -3,6 +3,7 @@ import {shallow} from 'enzyme'
|
|||
|
||||
import {IFQLPage} from 'src/ifql/containers/IFQLPage'
|
||||
import TimeMachine from 'src/ifql/components/TimeMachine'
|
||||
import {ActionUpdateScript} from 'src/ifql/actions'
|
||||
|
||||
jest.mock('src/ifql/apis', () => require('mocks/ifql/apis'))
|
||||
|
||||
|
@ -15,7 +16,19 @@ const setup = () => {
|
|||
},
|
||||
services: [],
|
||||
sources: [],
|
||||
script: '',
|
||||
notify: () => {},
|
||||
params: {
|
||||
sourceID: '',
|
||||
},
|
||||
updateScript: (script: string) => {
|
||||
return {
|
||||
type: 'UPDATE_SCRIPT',
|
||||
payload: {
|
||||
script,
|
||||
},
|
||||
} as ActionUpdateScript
|
||||
},
|
||||
}
|
||||
|
||||
const wrapper = shallow(<IFQLPage {...props} />)
|
||||
|
|
|
@ -96,6 +96,7 @@ export const kapacitor = {
|
|||
|
||||
export const service = {
|
||||
id: '1',
|
||||
sourceID: '1',
|
||||
url: 'localhost:8082',
|
||||
type: 'ifql',
|
||||
name: 'IFQL',
|
||||
|
@ -108,6 +109,7 @@ export const service = {
|
|||
proxy: '/chronograf/v1/sources/1/services/2/proxy',
|
||||
self: '/chronograf/v1/sources/1/services/2',
|
||||
},
|
||||
metadata: {},
|
||||
}
|
||||
|
||||
export const kapacitorRules = [
|
||||
|
|
Loading…
Reference in New Issue