Convert TickscriptEditor to TypesScript and add initial test

pull/3150/head
Andrew Watkins 2018-04-06 14:08:51 -07:00
parent 646da4919e
commit 21754a10f9
9 changed files with 266 additions and 169 deletions

View File

@ -0,0 +1,2 @@
export const pingKapacitorVersion = jest.fn(() => Promise.resolve('2.0'))
export const getLogStreamByRuleID = jest.fn(() => Promise.resolve())

View File

@ -1,6 +1,7 @@
import {kapacitor} from 'mocks/dummy'
export const getKapacitor = jest.fn(() => Promise.resolve(kapacitor))
export const getActiveKapacitor = jest.fn(() => Promise.resolve(kapacitor))
export const createKapacitor = jest.fn(() => Promise.resolve({data: kapacitor}))
export const updateKapacitor = jest.fn(() => Promise.resolve({data: kapacitor}))
export const pingKapacitor = jest.fn(() => Promise.resolve())

View File

@ -41,6 +41,7 @@
"@types/prop-types": "^15.5.2",
"@types/react": "^16.0.38",
"@types/react-router": "3",
"@types/text-encoding": "^0.0.32",
"autoprefixer": "^6.3.1",
"babel-core": "^6.5.1",
"babel-eslint": "6.1.2",

View File

@ -1,28 +1,88 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import uuid from 'uuid'
import Tickscript from 'src/kapacitor/components/Tickscript'
import * as kapactiorActionCreators from 'src/kapacitor/actions/view'
import * as errorActionCreators from 'shared/actions/errors'
import * as errorActionCreators from 'src/shared/actions/errors'
import {getActiveKapacitor} from 'src/shared/apis'
import {getLogStreamByRuleID, pingKapacitorVersion} from 'src/kapacitor/apis'
import {notify as notifyAction} from 'shared/actions/notifications'
import {notify as notifyAction} from 'src/shared/actions/notifications'
import {Source, Kapacitor, Task, AlertRule} from 'src/types'
import {
notifyTickscriptLoggingUnavailable,
notifyTickscriptLoggingError,
notifyKapacitorNotFound,
} from 'shared/copy/notifications'
} from 'src/shared/copy/notifications'
class TickscriptPage extends Component {
interface ErrorActions {
errorThrown: (notify: string | object) => void
}
interface Router {
push: (path: string) => void
}
interface KapacitorActions {
updateTask: (
kapacitor: Kapacitor,
task: Task,
ruleID: string,
router: Router,
sourceID: string
) => void
createTask: (
kapacitor: Kapacitor,
task: Task,
router: Router,
sourceID: string
) => void
getRule: (kapacitor: Kapacitor, ruleID: string) => void
}
interface Params {
ruleID: string
}
interface Props {
source: Source
errorActions: ErrorActions
kapacitorActions: KapacitorActions
router: Router
params: Params
rules: AlertRule[]
notify: any
}
interface State {
kapacitor: Kapacitor
task: Task
consoleMessage: string
isEditingID: boolean
logs: object[]
areLogsVisible: boolean
areLogsEnabled: boolean
failStr: string
unsavedChanges: boolean
}
export class TickscriptPage extends PureComponent<Props, State> {
constructor(props) {
super(props)
this.state = {
kapacitor: {},
kapacitor: {
id: '',
url: '',
name: '',
active: false,
insecureSkipVerify: false,
links: {
self: '',
},
},
task: {
id: '',
name: '',
@ -34,13 +94,143 @@ class TickscriptPage extends Component {
consoleMessage: '',
isEditingID: true,
logs: [],
areLogsEnabled: false,
failStr: '',
areLogsVisible: false,
areLogsEnabled: false,
unsavedChanges: false,
}
}
fetchChunkedLogs = async (kapacitor, ruleID) => {
public async componentDidMount() {
const {
source,
errorActions,
kapacitorActions,
params: {ruleID},
} = this.props
const kapacitor = await getActiveKapacitor(source)
if (!kapacitor) {
errorActions.errorThrown(notifyKapacitorNotFound())
}
if (this._isEditing()) {
await kapacitorActions.getRule(kapacitor, ruleID)
const {id, name, tickscript, dbrps, type} = this.props.rules.find(
r => r.id === ruleID
)
this.setState({task: {tickscript, dbrps, type, status, name, id}})
}
this.fetchChunkedLogs(kapacitor, ruleID)
this.setState({kapacitor})
}
public componentWillUnmount() {
this.setState({
areLogsEnabled: false,
})
}
public render() {
const {
task,
logs,
areLogsVisible,
areLogsEnabled,
unsavedChanges,
consoleMessage,
} = this.state
return (
<Tickscript
task={task}
logs={logs}
onSave={this.handleSave}
onExit={this.handleExit}
unsavedChanges={unsavedChanges}
areLogsVisible={areLogsVisible}
areLogsEnabled={areLogsEnabled}
consoleMessage={consoleMessage}
onChangeID={this.handleChangeID}
onChangeType={this.handleChangeType}
isNewTickscript={!this._isEditing()}
onSelectDbrps={this.handleSelectDbrps}
onChangeScript={this.handleChangeScript}
onToggleLogsVisibility={this.handleToggleLogsVisibility}
/>
)
}
private handleSave = async () => {
const {kapacitor, task} = this.state
const {
source: {id: sourceID},
router,
kapacitorActions: {createTask, updateTask},
params: {ruleID},
} = this.props
let response
try {
if (this._isEditing()) {
response = await updateTask(kapacitor, task, ruleID, router, sourceID)
} else {
response = await createTask(kapacitor, task, router, sourceID)
router.push(`/sources/${sourceID}/tickscript/${response.id}`)
}
if (response.code) {
this.setState({unsavedChanges: true, consoleMessage: response.message})
} else {
this.setState({unsavedChanges: false, consoleMessage: ''})
}
} catch (error) {
console.error(error)
throw error
}
}
private handleExit = () => {
const {source: {id: sourceID}, router} = this.props
return router.push(`/sources/${sourceID}/alert-rules`)
}
private handleChangeScript = tickscript => {
this.setState({
task: {...this.state.task, tickscript},
unsavedChanges: true,
})
}
private handleSelectDbrps = dbrps => {
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
}
private handleChangeType = type => () => {
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
}
private handleChangeID = e => {
this.setState({
task: {...this.state.task, id: e.target.value},
unsavedChanges: true,
})
}
private handleToggleLogsVisibility = () => {
this.setState({areLogsVisible: !this.state.areLogsVisible})
}
private _isEditing() {
const {params} = this.props
return params.ruleID && params.ruleID !== 'new'
}
private fetchChunkedLogs = async (kapacitor, ruleID) => {
const {notify} = this.props
try {
@ -110,7 +300,7 @@ class TickscriptPage extends Component {
failStr,
})
} catch (err) {
console.warn(err, failStr)
console.warn(err, failStr) // tslint:disable-line
this.setState({
logs: [...logs, ...this.state.logs],
failStr,
@ -119,165 +309,10 @@ class TickscriptPage extends Component {
}
} catch (error) {
console.error(error)
notify(notifyTickscriptLoggingError()(error))
notify(notifyTickscriptLoggingError(error))
throw error
}
}
async componentDidMount() {
const {
source,
errorActions,
kapacitorActions,
params: {ruleID},
} = this.props
const kapacitor = await getActiveKapacitor(source)
if (!kapacitor) {
errorActions.errorThrown(notifyKapacitorNotFound())
}
if (this._isEditing()) {
await kapacitorActions.getRule(kapacitor, ruleID)
const {id, name, tickscript, dbrps, type} = this.props.rules.find(
r => r.id === ruleID
)
this.setState({task: {tickscript, dbrps, type, status, name, id}})
}
this.fetchChunkedLogs(kapacitor, ruleID)
this.setState({kapacitor})
}
componentWillUnmount() {
this.setState({
areLogsEnabled: false,
})
}
handleSave = async () => {
const {kapacitor, task} = this.state
const {
source: {id: sourceID},
router,
kapacitorActions: {createTask, updateTask},
params: {ruleID},
} = this.props
let response
try {
if (this._isEditing()) {
response = await updateTask(kapacitor, task, ruleID, router, sourceID)
} else {
response = await createTask(kapacitor, task, router, sourceID)
router.push(`/sources/${sourceID}/tickscript/${response.id}`)
}
if (response.code) {
this.setState({unsavedChanges: true, consoleMessage: response.message})
} else {
this.setState({unsavedChanges: false, consoleMessage: ''})
}
} catch (error) {
console.error(error)
throw error
}
}
handleExit = () => {
const {source: {id: sourceID}, router} = this.props
return router.push(`/sources/${sourceID}/alert-rules`)
}
handleChangeScript = tickscript => {
this.setState({
task: {...this.state.task, tickscript},
unsavedChanges: true,
})
}
handleSelectDbrps = dbrps => {
this.setState({task: {...this.state.task, dbrps}, unsavedChanges: true})
}
handleChangeType = type => () => {
this.setState({task: {...this.state.task, type}, unsavedChanges: true})
}
handleChangeID = e => {
this.setState({
task: {...this.state.task, id: e.target.value},
unsavedChanges: true,
})
}
handleToggleLogsVisibility = () => {
this.setState({areLogsVisible: !this.state.areLogsVisible})
}
render() {
const {source} = this.props
const {
task,
logs,
areLogsVisible,
areLogsEnabled,
unsavedChanges,
consoleMessage,
} = this.state
return (
<Tickscript
task={task}
logs={logs}
source={source}
consoleMessage={consoleMessage}
onSave={this.handleSave}
unsavedChanges={unsavedChanges}
onExit={this.handleExit}
isNewTickscript={!this._isEditing()}
onSelectDbrps={this.handleSelectDbrps}
onChangeScript={this.handleChangeScript}
onChangeType={this.handleChangeType}
onChangeID={this.handleChangeID}
areLogsVisible={areLogsVisible}
areLogsEnabled={areLogsEnabled}
onToggleLogsVisibility={this.handleToggleLogsVisibility}
/>
)
}
_isEditing() {
const {params} = this.props
return params.ruleID && params.ruleID !== 'new'
}
}
const {arrayOf, func, shape, string} = PropTypes
TickscriptPage.propTypes = {
source: shape({
name: string,
}),
errorActions: shape({
errorThrown: func.isRequired,
}).isRequired,
kapacitorActions: shape({
updateTask: func.isRequired,
createTask: func.isRequired,
getRule: func.isRequired,
}),
router: shape({
push: func.isRequired,
}).isRequired,
params: shape({
ruleID: string,
}).isRequired,
rules: arrayOf(shape()),
notify: func.isRequired,
}
const mapStateToProps = state => {

View File

@ -1,6 +1,6 @@
import {AuthLinks, Organization, Role, User, Me} from './auth'
import {AlertRule, Kapacitor} from './kapacitor'
import {Query, QueryConfig, TimeRange} from './query'
import {AlertRule, Kapacitor, Task} from './kapacitor'
import {Source} from './sources'
import {DropdownAction, DropdownItem} from './shared'
@ -18,4 +18,5 @@ export {
DropdownAction,
DropdownItem,
TimeRange,
Task,
}

View File

@ -34,6 +34,15 @@ export interface AlertRule {
'last-enabled'?: string
}
export interface Task {
id: string
name: string
status: string
tickscript: string
dbrps: DBRP[]
type: string
}
type TICKScript = string
// AlertNodes defines all possible kapacitor interactions with an alert.

View File

@ -0,0 +1,43 @@
import React from 'react'
import {shallow} from 'enzyme'
import {TickscriptPage} from 'src/kapacitor/containers/TickscriptPage'
import {source} from 'test/resources'
jest.mock('src/shared/apis', () => require('mocks/shared/apis'))
jest.mock('src/kapacitor/apis', () => require('mocks/kapacitor/apis'))
const setup = () => {
const props = {
source,
errorActions: {
errorThrown: () => {},
},
kapacitorActions: {
updateTask: () => {},
createTask: () => {},
getRule: () => {},
},
router: {
push: () => {},
},
params: {
ruleID: '',
},
rules: [],
notify: () => {},
}
const wrapper = shallow(<TickscriptPage {...props} />)
return {
wrapper,
}
}
describe('Kapacitor.Containers.TickscriptPage', () => {
describe('rendering', () => {
it('renders without errors', () => {
const {wrapper} = setup()
expect(wrapper.exists()).toBe(true)
})
})
})

View File

@ -8,7 +8,8 @@
"react",
"prop-types",
"jest",
"react-router"
"react-router",
"text-encoding"
],
"target": "es6",
"module": "es2015",

View File

@ -72,6 +72,10 @@
version "16.0.40"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.0.40.tgz#caabc2296886f40b67f6fc80f0f3464476461df9"
"@types/text-encoding@^0.0.32":
version "0.0.32"
resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.32.tgz#52289b320a406850b14f08f48b475ca021218048"
abab@^1.0.3, abab@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"