feat: Alerting add alert builder veo state (#14499)

* Define new check, edit check and check view routes with VEO

Co-authored-by: Michael Desa <mjdesa@gmail.com>

* Add task status to other task types

* Put editAlerting route behind feature flag

* add action and reducer for update current check

* Add init edit and new check editor overlay

* Split VEO in to two for new and edit view

* get edit and new CheckEO's ready

* Create getViewForTimeMachine action

* current check should be a partial check

* Fix view typing

* Fix linter errors

* Fix equality

* Catch save VEO errors
pull/14500/head
Deniz Kusefoglu 2019-07-29 15:54:35 -07:00 committed by GitHub
parent 93649a71b5
commit bbc37b4c68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 586 additions and 281 deletions

View File

@ -8652,12 +8652,7 @@ components:
description: The name of the organization that owns this Task.
type: string
status:
description: Starting state of the task. 'inactive' tasks are not run until they are updated to 'active'
default: active
type: string
enum:
- active
- inactive
$ref: "#/components/schemas/TaskStatusType"
flux:
description: The Flux script to run for this task.
type: string
@ -8669,12 +8664,7 @@ components:
type: object
properties:
status:
description: Starting state of the task. 'inactive' tasks are not run until they are updated to 'active'
default: active
type: string
enum:
- active
- inactive
$ref: "#/components/schemas/TaskStatusType"
flux:
description: The Flux script to run for this task.
type: string

View File

@ -20,6 +20,7 @@ export type Action =
| ReturnType<typeof setCheck>
| ReturnType<typeof removeCheck>
| ReturnType<typeof setCurrentCheck>
| ReturnType<typeof updateCurrentCheck>
export const setAllChecks = (status: RemoteDataState, checks?: Check[]) => ({
type: 'SET_ALL_CHECKS' as 'SET_ALL_CHECKS',
@ -36,11 +37,19 @@ export const removeCheck = (checkID: string) => ({
payload: {checkID},
})
export const setCurrentCheck = (status: RemoteDataState, check?: Check) => ({
export const setCurrentCheck = (
status: RemoteDataState,
check?: Partial<Check>
) => ({
type: 'SET_CURRENT_CHECK' as 'SET_CURRENT_CHECK',
payload: {status, check},
})
export const updateCurrentCheck = (checkUpdate: Partial<Check>) => ({
type: 'UPDATE_CURRENT_CHECK' as 'UPDATE_CURRENT_CHECK',
payload: {status, checkUpdate},
})
export const getChecks = () => async (
dispatch: Dispatch<Action | NotificationAction>,
getState: GetState

View File

@ -0,0 +1,110 @@
// Libraries
import React, {FunctionComponent, useEffect} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
// Components
import {Overlay, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import VEOHeader from 'src/dashboards/components/VEOHeader'
import TimeMachine from 'src/timeMachine/components/TimeMachine'
// Utils
import {createView} from 'src/shared/utils/view'
// Actions
import {
updateCheck,
setCurrentCheck,
updateCurrentCheck,
getCurrentCheck,
} from 'src/alerting/actions/checks'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
// Types
import {Check, AppState, RemoteDataState, XYView, ViewType} from 'src/types'
import {TimeMachineEnum} from 'src/timeMachine/constants'
interface DispatchProps {
updateCheck: typeof updateCheck
setCurrentCheck: typeof setCurrentCheck
updateCurrentCheck: typeof updateCurrentCheck
onSetActiveTimeMachine: typeof setActiveTimeMachine
}
interface StateProps {
check: Partial<Check>
status: RemoteDataState
}
type Props = WithRouterProps & DispatchProps & StateProps
const EditCheckEditorOverlay: FunctionComponent<Props> = ({
onSetActiveTimeMachine,
params,
check,
status,
}) => {
useEffect(() => {
getCurrentCheck(params.checkID)
onSetActiveTimeMachine(TimeMachineEnum.Alerting)
}, [params.checkID])
useEffect(() => {
// create view properties from check
const view = createView<XYView>(ViewType.XY)
onSetActiveTimeMachine(TimeMachineEnum.Alerting, {view})
}, [check.id])
const handleUpdateName = (name: string) => {
updateCurrentCheck({name})
}
const handleCancel = () => {}
const handleSave = () => {}
// dont render time machine until active time machine is what we expect
return (
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<SpinnerContainer
spinnerComponent={<TechnoSpinner />}
loading={status || RemoteDataState.Loading}
>
<VEOHeader
key={check && check.name}
name={check && check.name}
onSetName={handleUpdateName}
onCancel={handleCancel}
onSave={handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</SpinnerContainer>
</div>
</Overlay>
)
}
const mstp = (state: AppState): StateProps => {
const {
checks: {
current: {check, status},
},
} = state
return {check, status}
}
const mdtp: DispatchProps = {
updateCheck: updateCheck,
setCurrentCheck: setCurrentCheck,
updateCurrentCheck: updateCurrentCheck,
onSetActiveTimeMachine: setActiveTimeMachine,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter(EditCheckEditorOverlay))

View File

@ -0,0 +1,104 @@
// Libraries
import React, {FunctionComponent, useEffect} from 'react'
import {connect} from 'react-redux'
// Components
import {Overlay, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import VEOHeader from 'src/dashboards/components/VEOHeader'
import TimeMachine from 'src/timeMachine/components/TimeMachine'
// Actions
import {
updateCheck,
setCurrentCheck,
updateCurrentCheck,
} from 'src/alerting/actions/checks'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
// Utils
import {createView} from 'src/shared/utils/view'
// Types
import {Check, AppState, RemoteDataState, XYView, ViewType} from 'src/types'
import {DEFAULT_CHECK} from 'src/alerting/constants'
import {TimeMachineEnum} from 'src/timeMachine/constants'
interface DispatchProps {
updateCheck: typeof updateCheck
setCurrentCheck: typeof setCurrentCheck
updateCurrentCheck: typeof updateCurrentCheck
onSetActiveTimeMachine: typeof setActiveTimeMachine
}
interface StateProps {
check: Partial<Check>
status: RemoteDataState
}
type Props = DispatchProps & StateProps
const NewCheckOverlay: FunctionComponent<Props> = ({
onSetActiveTimeMachine,
updateCurrentCheck,
setCurrentCheck,
status,
check,
}) => {
useEffect(() => {
setCurrentCheck(RemoteDataState.Done, DEFAULT_CHECK)
const view = createView<XYView>(ViewType.XY)
onSetActiveTimeMachine(TimeMachineEnum.Alerting, {view})
}, [])
const handleUpdateName = (name: string) => {
updateCurrentCheck({name})
}
const handleCancel = () => {}
const handleSave = () => {}
return (
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<SpinnerContainer
spinnerComponent={<TechnoSpinner />}
loading={status || RemoteDataState.Loading}
>
<VEOHeader
key={check && check.name}
name={check && check.name}
onSetName={handleUpdateName}
onCancel={handleCancel}
onSave={handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</SpinnerContainer>
</div>
</Overlay>
)
}
const mstp = (state: AppState): StateProps => {
const {
checks: {
current: {check, status},
},
} = state
return {check, status}
}
const mdtp: DispatchProps = {
updateCheck: updateCheck,
setCurrentCheck: setCurrentCheck,
updateCurrentCheck: updateCurrentCheck,
onSetActiveTimeMachine: setActiveTimeMachine,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(NewCheckOverlay)

View File

@ -9,11 +9,19 @@ import {
NotificationRuleType,
CheckStatusLevel,
ThresholdType,
ThresholdCheck,
} from 'src/types'
export const DEFAULT_CHECK_NAME = 'Name this check'
export const DEFAULT_NOTIFICATION_RULE_NAME = 'Name this notification rule'
export const DEFAULT_CHECK: Partial<ThresholdCheck> = {
name: DEFAULT_CHECK_NAME,
type: CheckType.Threshold,
status: CheckBase.StatusEnum.Active,
thresholds: [],
}
export const query: DashboardQuery = {
text: 'this is query',
editMode: QueryEditMode.Advanced,

View File

@ -8,7 +8,7 @@ import {Action} from 'src/alerting/actions/checks'
export interface ChecksState {
status: RemoteDataState
list: Check[]
current: {status: RemoteDataState; check: Check}
current: {status: RemoteDataState; check: Partial<Check>}
}
export const defaultChecksState: ChecksState = {
@ -52,6 +52,13 @@ export default (
if (action.payload.check) {
draftState.current.check = action.payload.check
}
return
case 'UPDATE_CURRENT_CHECK':
draftState.current.check = {
...draftState.current.check,
...action.payload.checkUpdate,
} as Check
return
}
})

View File

@ -336,13 +336,13 @@ export const deleteDashboardAsync = (dashboard: Dashboard) => async (
}
export const refreshDashboardVariableValues = (
dashboard: Dashboard,
dashboardID: string,
nextViews: View[]
) => (dispatch, getState: GetState) => {
const variables = extractVariablesList(getState())
const variablesInUse = filterUnusedVars(variables, nextViews)
return dispatch(refreshVariableValues(dashboard.id, variablesInUse))
return dispatch(refreshVariableValues(dashboardID, variablesInUse))
}
export const getDashboardAsync = (dashboardID: string) => async (
@ -363,7 +363,7 @@ export const getDashboardAsync = (dashboardID: string) => async (
dispatch(setViews(RemoteDataState.Done, views))
// Ensure the values for the variables in use on the dashboard are populated
await dispatch(refreshDashboardVariableValues(dashboard, views))
await dispatch(refreshDashboardVariableValues(dashboard.id, views))
// Now that all the necessary state has been loaded, set the dashboard
dispatch(setDashboard(dashboard))
@ -390,18 +390,24 @@ export const updateDashboardAsync = (dashboard: Dashboard) => async (
}
export const createCellWithView = (
dashboard: Dashboard,
dashboardID: string,
view: NewView,
clonedCell?: Cell
) => async (dispatch, getState: GetState): Promise<void> => {
try {
const state = getState()
let dashboard = state.dashboards.list.find(d => d.id === dashboardID)
if (!dashboard) {
dashboard = await getDashboardAJAX(dashboardID)
}
const cell: CreateCell = getNewDashboardCell(dashboard, clonedCell)
// Create the cell
const createdCell = await addCellAJAX(dashboard.id, cell)
const createdCell = await addCellAJAX(dashboardID, cell)
// Create the view and associate it with the cell
const newView = await updateViewAJAX(dashboard.id, createdCell.id, view)
const newView = await updateViewAJAX(dashboardID, createdCell.id, view)
// Update the dashboard with the new cell
let updatedDashboard: Dashboard = {
@ -412,9 +418,9 @@ export const createCellWithView = (
updatedDashboard = await updateDashboardAJAX(dashboard)
// Refresh variables in use on dashboard
const views = [...getViewsForDashboard(getState(), dashboard.id), newView]
const views = [...getViewsForDashboard(state, dashboard.id), newView]
await dispatch(refreshDashboardVariableValues(dashboard, views))
await dispatch(refreshDashboardVariableValues(dashboard.id, views))
dispatch(setView(createdCell.id, newView, RemoteDataState.Done))
dispatch(editDashboard(updatedDashboard))
@ -423,20 +429,20 @@ export const createCellWithView = (
}
}
export const updateView = (dashboard: Dashboard, view: View) => async (
export const updateView = (dashboardID: string, view: View) => async (
dispatch,
getState: GetState
) => {
const cellID = view.cellID
try {
const newView = await updateViewAJAX(dashboard.id, cellID, view)
const newView = await updateViewAJAX(dashboardID, cellID, view)
const views = getViewsForDashboard(getState(), dashboard.id)
const views = getViewsForDashboard(getState(), dashboardID)
views.splice(views.findIndex(v => v.id === newView.id), 1, newView)
await dispatch(refreshDashboardVariableValues(dashboard, views))
await dispatch(refreshDashboardVariableValues(dashboardID, views))
dispatch(setView(cellID, newView, RemoteDataState.Done))
} catch (e) {
@ -473,7 +479,7 @@ export const deleteCellAsync = (dashboard: Dashboard, cell: Cell) => async (
await Promise.all([
deleteCellAJAX(dashboard.id, cell),
dispatch(refreshDashboardVariableValues(dashboard, views)),
dispatch(refreshDashboardVariableValues(dashboard.id, views)),
])
dispatch(removeCell(dashboard, cell))
@ -577,7 +583,7 @@ export const convertToTemplate = (dashboardID: string) => async (
}
}
export const saveVEOView = (dashboard: Dashboard) => async (
export const saveVEOView = (dashboardID: string) => async (
dispatch,
getState: GetState
): Promise<void> => {
@ -585,12 +591,13 @@ export const saveVEOView = (dashboard: Dashboard) => async (
try {
if (view.id) {
await dispatch(updateView(dashboard, view))
await dispatch(updateView(dashboardID, view))
} else {
await dispatch(createCellWithView(dashboard, view))
await dispatch(createCellWithView(dashboardID, view))
}
} catch (error) {
console.error(error)
dispatch(notify(copy.cellAddFailed()))
throw error
}
}

View File

@ -76,7 +76,7 @@ export const createNoteCell = (dashboardID: string) => async (
view.properties.note = note
return dispatch(createCellWithView(dashboard, view))
return dispatch(createCellWithView(dashboard.id, view))
}
export interface ResetNoteStateAction {

View File

@ -5,9 +5,14 @@ import {
} from 'src/dashboards/apis/'
// Types
import {RemoteDataState} from 'src/types'
import {RemoteDataState, QueryView} from 'src/types'
import {Dispatch} from 'redux'
import {View} from 'src/types'
import {Action as TimeMachineAction} from 'src/timeMachine/actions'
//Actions
import {setActiveTimeMachine} from 'src/timeMachine/actions'
import {TimeMachineEnum} from 'src/timeMachine/constants'
export type Action = SetViewAction | SetViewsAction | ResetViewsAction
@ -83,3 +88,19 @@ export const updateView = (dashboardID: string, view: View) => async (
dispatch(setView(viewID, null, RemoteDataState.Error))
}
}
export const getViewForTimeMachine = (
dashboardID: string,
cellID: string,
timeMachineID: TimeMachineEnum
) => async (dispatch: Dispatch<Action | TimeMachineAction>): Promise<void> => {
dispatch(setView(cellID, null, RemoteDataState.Loading))
try {
const view = (await getViewAJAX(dashboardID, cellID)) as QueryView
dispatch(setView(cellID, view, RemoteDataState.Done))
dispatch(setActiveTimeMachine(timeMachineID, {view}))
} catch {
dispatch(setView(cellID, null, RemoteDataState.Error))
}
}

View File

@ -27,7 +27,6 @@ import {
// Utils
import {GlobalAutoRefresher} from 'src/utils/AutoRefresher'
import {createView} from 'src/shared/utils/view'
import {
extractRateLimitResourceName,
extractRateLimitStatus,
@ -38,7 +37,6 @@ import {
DASHBOARD_LAYOUT_ROW_HEIGHT,
AUTOREFRESH_DEFAULT,
} from 'src/shared/constants'
import {VEO_TIME_MACHINE_ID} from 'src/timeMachine/constants'
import {DEFAULT_TIME_RANGE} from 'src/shared/constants/timeRanges'
// Types
@ -51,9 +49,6 @@ import {
AppState,
AutoRefresh,
AutoRefreshStatus,
XYView,
ViewType,
QueryView,
} from 'src/types'
import {RemoteDataState} from 'src/types'
import {WithRouterProps} from 'react-router'
@ -299,7 +294,8 @@ class DashboardPage extends Component<Props, State> {
}
private handleAddCell = async (): Promise<void> => {
this.showVEO()
const {router, location} = this.props
router.push(`${location.pathname}/cells/new`)
}
private showNoteOverlay = async (id?: string): Promise<void> => {
@ -311,27 +307,15 @@ class DashboardPage extends Component<Props, State> {
}
private handleEditView = (cellID: string): void => {
this.showVEO(cellID)
}
private showVEO = (id?: string): void => {
const {router, location, views, onSetActiveTimeMachine} = this.props
if (id) {
const view = _.get(views, `${id}.view`) as QueryView
onSetActiveTimeMachine(VEO_TIME_MACHINE_ID, {view})
router.push(`${location.pathname}/cells/${id}/edit`)
} else {
const view = createView<XYView>(ViewType.XY)
onSetActiveTimeMachine(VEO_TIME_MACHINE_ID, {view})
router.push(`${location.pathname}/cells/new`)
}
const {router, location} = this.props
router.push(`${location.pathname}/cells/${cellID}/edit`)
}
private handleCloneCell = async (cell: Cell): Promise<void> => {
const {dashboard, onCreateCellWithView, views} = this.props
const viewEntry = views[cell.id]
if (viewEntry && viewEntry.view) {
await onCreateCellWithView(dashboard, viewEntry.view, cell)
await onCreateCellWithView(dashboard.id, viewEntry.view, cell)
}
}

View File

@ -0,0 +1,139 @@
// Libraries
import React, {FunctionComponent, useEffect} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import {get} from 'lodash'
// Components
import {Overlay, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TimeMachine from 'src/timeMachine/components/TimeMachine'
import VEOHeader from 'src/dashboards/components/VEOHeader'
// Actions
import {setActiveTimeMachine} from 'src/timeMachine/actions'
import {setName} from 'src/timeMachine/actions'
import {saveVEOView} from 'src/dashboards/actions'
import {setView, getViewForTimeMachine} from 'src/dashboards/actions/views'
// Utils
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
import {TimeMachineEnum} from 'src/timeMachine/constants'
// Types
import {AppState, RemoteDataState, View, QueryView} from 'src/types'
import {ViewsState} from 'src/dashboards/reducers/views'
import {executeQueries} from 'src/timeMachine/actions/queries'
interface DispatchProps {
onSetActiveTimeMachine: typeof setActiveTimeMachine
onSetName: typeof setName
onSaveView: typeof saveVEOView
setView: typeof setView
executeQueries: typeof executeQueries
getViewForTimeMachine: typeof getViewForTimeMachine
}
interface StateProps {
view: View
loadingState: RemoteDataState
views: ViewsState
}
type Props = DispatchProps & StateProps & WithRouterProps
const NewViewVEO: FunctionComponent<Props> = ({
onSetActiveTimeMachine,
getViewForTimeMachine,
executeQueries,
loadingState,
onSaveView,
onSetName,
params,
router,
views,
view,
}) => {
useEffect(() => {
onSetActiveTimeMachine(TimeMachineEnum.VEO, {})
const viewInState = get(views, `${params.cellID}.view`, null) as QueryView
if (viewInState) {
onSetActiveTimeMachine(TimeMachineEnum.VEO, {view: viewInState})
} else {
getViewForTimeMachine(
params.dashboardID,
params.cellID,
TimeMachineEnum.VEO
)
}
}, [params.cellID])
useEffect(() => {
executeQueries()
}, [get(view, 'id', null)])
const handleClose = () => {
const {orgID, dashboardID} = params
router.push(`/orgs/${orgID}/dashboards/${dashboardID}`)
}
const handleSave = () => {
try {
onSaveView(params.dashboardID)
handleClose()
} catch (e) {}
}
return (
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<SpinnerContainer
spinnerComponent={<TechnoSpinner />}
loading={loadingState}
>
<VEOHeader
key={view && view.name}
name={view && view.name}
onSetName={onSetName}
onCancel={handleClose}
onSave={handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</SpinnerContainer>
</div>
</Overlay>
)
}
const mstp = (state: AppState, {params: {cellID}}): StateProps => {
const {activeTimeMachineID} = state.timeMachines
const {view} = getActiveTimeMachine(state)
const viewMatchesRoute = get(view, 'id', null) === cellID
let loadingState = RemoteDataState.Loading
if (activeTimeMachineID === TimeMachineEnum.VEO && viewMatchesRoute) {
loadingState = RemoteDataState.Done
}
const {views} = state
return {view, loadingState, views}
}
const mdtp: DispatchProps = {
onSetName: setName,
setView: setView,
onSaveView: saveVEOView,
onSetActiveTimeMachine: setActiveTimeMachine,
executeQueries: executeQueries,
getViewForTimeMachine: getViewForTimeMachine,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter(NewViewVEO))

View File

@ -0,0 +1,111 @@
// Libraries
import React, {FunctionComponent, useEffect} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import {get} from 'lodash'
// Components
import {Overlay, SpinnerContainer, TechnoSpinner} from '@influxdata/clockface'
import TimeMachine from 'src/timeMachine/components/TimeMachine'
import VEOHeader from 'src/dashboards/components/VEOHeader'
// Actions
import {setActiveTimeMachine} from 'src/timeMachine/actions'
import {setName} from 'src/timeMachine/actions'
import {saveVEOView} from 'src/dashboards/actions'
// Utils
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
import {createView} from 'src/shared/utils/view'
import {TimeMachineEnum} from 'src/timeMachine/constants'
// Types
import {AppState, ViewType, XYView, RemoteDataState, View} from 'src/types'
interface DispatchProps {
onSetActiveTimeMachine: typeof setActiveTimeMachine
onSetName: typeof setName
onSaveView: typeof saveVEOView
}
interface StateProps {
view: View
loadingState: RemoteDataState
}
type Props = DispatchProps & StateProps & WithRouterProps
const NewViewVEO: FunctionComponent<Props> = ({
onSetActiveTimeMachine,
loadingState,
onSaveView,
onSetName,
params,
router,
view,
}) => {
useEffect(() => {
const view = createView<XYView>(ViewType.XY)
onSetActiveTimeMachine(TimeMachineEnum.VEO, {view})
}, [])
const handleClose = () => {
const {orgID, dashboardID} = params
router.push(`/orgs/${orgID}/dashboards/${dashboardID}`)
}
const handleSave = () => {
try {
onSaveView(params.dashboardID)
handleClose()
} catch (e) {}
}
return (
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<SpinnerContainer
spinnerComponent={<TechnoSpinner />}
loading={loadingState}
>
<VEOHeader
key={view && view.name}
name={view && view.name}
onSetName={onSetName}
onCancel={handleClose}
onSave={handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</SpinnerContainer>
</div>
</Overlay>
)
}
const mstp = (state: AppState): StateProps => {
const {activeTimeMachineID} = state.timeMachines
const {view} = getActiveTimeMachine(state)
const viewIsNew = !get(view, 'id', null)
let loadingState = RemoteDataState.Loading
if (activeTimeMachineID === TimeMachineEnum.VEO && viewIsNew) {
loadingState = RemoteDataState.Done
}
return {view, loadingState}
}
const mdtp: DispatchProps = {
onSetName: setName,
onSaveView: saveVEOView,
onSetActiveTimeMachine: setActiveTimeMachine,
}
export default connect<StateProps, DispatchProps, {}>(
mstp,
mdtp
)(withRouter(NewViewVEO))

View File

@ -1,103 +0,0 @@
// Libraries
import React, {PureComponent} from 'react'
import {withRouter, WithRouterProps} from 'react-router'
import {connect} from 'react-redux'
import _ from 'lodash'
// Components
import {SpinnerContainer, TechnoSpinner, Overlay} from '@influxdata/clockface'
import VEOContents from 'src/dashboards/components/VEOContents'
// Utils
import {getView} from 'src/dashboards/selectors'
import {createView} from 'src/shared/utils/view'
// Types
import {AppState, ViewType, QueryView, XYView, RemoteDataState} from 'src/types'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
interface OwnProps extends WithRouterProps {
params: {
dashboardID: string
cellID?: string
orgID: string
}
}
interface StateProps {
viewsStatus: RemoteDataState
view: QueryView
}
interface DispatchProps {
onSetActiveTimeMachine: typeof setActiveTimeMachine
}
type Props = StateProps & DispatchProps & OwnProps
class VEO extends PureComponent<Props> {
public render() {
const {params} = this.props
return (
<Overlay visible={true} className="veo-overlay">
<div className="veo">
<SpinnerContainer
spinnerComponent={<TechnoSpinner />}
loading={this.loading}
>
<VEOContents
dashboardID={params.dashboardID}
onClose={this.handleClose}
/>
</SpinnerContainer>
</div>
</Overlay>
)
}
private get loading(): RemoteDataState {
const {viewsStatus, view} = this.props
if (viewsStatus === RemoteDataState.Done && view) {
return RemoteDataState.Done
} else if (viewsStatus === RemoteDataState.Done) {
return RemoteDataState.Error
}
return viewsStatus
}
private handleClose = () => {
const {
router,
params: {dashboardID, orgID},
} = this.props
router.push(`/orgs/${orgID}/dashboards/${dashboardID}`)
}
}
const mstp = (state: AppState, {params}): StateProps => {
const {cellID} = params
const {
views: {status},
} = state
if (cellID) {
const view = getView(state, cellID) as QueryView
return {view, viewsStatus: status}
}
const view = createView<XYView>(ViewType.XY)
return {view, viewsStatus: status}
}
const mdtp: DispatchProps = {
onSetActiveTimeMachine: setActiveTimeMachine,
}
export default connect(
mstp,
mdtp
)(withRouter<OwnProps, {}>(VEO))

View File

@ -1,92 +0,0 @@
// Libraries
import React, {PureComponent} from 'react'
import {connect} from 'react-redux'
import _ from 'lodash'
// Components
import VEOHeader from 'src/dashboards/components/VEOHeader'
import TimeMachine from 'src/timeMachine/components/TimeMachine'
// Actions
import {setName} from 'src/timeMachine/actions'
import {saveVEOView} from 'src/dashboards/actions'
import {executeQueries} from 'src/timeMachine/actions/queries'
// Utils
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
// Types
import {AppState} from 'src/types'
import {Dashboard} from 'src/types'
interface StateProps {
name: string
dashboard: Dashboard
}
interface DispatchProps {
onSetName: typeof setName
onSaveView: typeof saveVEOView
executeQueries: typeof executeQueries
}
interface OwnProps {
dashboardID: string
onClose: () => void
}
type Props = OwnProps & StateProps & DispatchProps
class VEOContents extends PureComponent<Props, {}> {
public componentDidMount() {
this.props.executeQueries()
}
public render() {
const {name, onSetName} = this.props
return (
<>
<VEOHeader
key={name}
name={name}
onSetName={onSetName}
onCancel={this.props.onClose}
onSave={this.handleSave}
/>
<div className="veo-contents">
<TimeMachine />
</div>
</>
)
}
private handleSave = async (): Promise<void> => {
const {dashboard, onSaveView, onClose} = this.props
onSaveView(dashboard)
onClose()
}
}
const mstp = (state: AppState, {dashboardID}): StateProps => {
const {dashboards} = state
const dashboard = dashboards.list.find(d => d.id === dashboardID)
const {
view: {name},
} = getActiveTimeMachine(state)
return {name, dashboard}
}
const mdtp: DispatchProps = {
onSetName: setName,
onSaveView: saveVEOView,
executeQueries,
}
export default connect<StateProps, DispatchProps, OwnProps>(
mstp,
mdtp
)(VEOContents)

View File

@ -11,7 +11,7 @@ import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
import {setActiveTimeMachine} from 'src/timeMachine/actions'
// Utils
import {DE_TIME_MACHINE_ID} from 'src/timeMachine/constants'
import {TimeMachineEnum} from 'src/timeMachine/constants'
import {HoverTimeProvider} from 'src/dashboards/utils/hoverTime'
import {queryBuilderFetcher} from 'src/timeMachine/apis/QueryBuilderFetcher'
import {
@ -37,7 +37,7 @@ class DataExplorer extends PureComponent<Props, {}> {
constructor(props: Props) {
super(props)
props.onSetActiveTimeMachine(DE_TIME_MACHINE_ID)
props.onSetActiveTimeMachine(TimeMachineEnum.DE)
queryBuilderFetcher.clearCache()
}

View File

@ -170,7 +170,7 @@ class SaveAsCellForm extends PureComponent<Props, State> {
} else {
const selectedDashboard = dashboards.find(d => d.id === dashID)
targetDashboardName = selectedDashboard.name
onCreateCellWithView(selectedDashboard, viewWithProps)
onCreateCellWithView(selectedDashboard.id, viewWithProps)
}
notify(cellAdded(cellName, targetDashboardName))
} catch {
@ -195,7 +195,7 @@ class SaveAsCellForm extends PureComponent<Props, State> {
cells: [],
}
const dashboard = await createDashboard(newDashboard)
onCreateCellWithView(dashboard, view)
onCreateCellWithView(dashboard.id, view)
} catch (error) {
console.error(error)
}

View File

@ -39,7 +39,8 @@ import GetMe from 'src/shared/containers/GetMe'
import Notifications from 'src/shared/containers/Notifications'
import TaskExportOverlay from 'src/tasks/components/TaskExportOverlay'
import TaskImportOverlay from 'src/tasks/components/TaskImportOverlay'
import VEO from 'src/dashboards/components/VEO'
import EditVEO from 'src/dashboards/components/EditVEO'
import NewVEO from 'src/dashboards/components/NewVEO'
import NoteEditorOverlay from 'src/dashboards/components/NoteEditorOverlay'
import OnboardingWizardPage from 'src/onboarding/containers/OnboardingWizardPage'
import BucketsIndex from 'src/buckets/containers/BucketsIndex'
@ -78,6 +79,8 @@ import AlertingIndex from 'src/alerting/containers/AlertingIndex'
import AlertHistoryIndex from 'src/alerting/containers/AlertHistoryIndex'
import BucketsDeleteDataOverlay from 'src/shared/components/DeleteDataOverlay'
import DEDeleteDataOverlay from 'src/dataExplorer/components/DeleteDataOverlay'
import NewCheckEO from 'src/alerting/components/NewCheckEO'
import EditCheckEO from 'src/alerting/components/EditCheckEO'
import {FeatureFlag} from 'src/shared/utils/featureFlag'
@ -195,8 +198,8 @@ class Root extends PureComponent {
component={DashboardPage}
>
<Route path="cells">
<Route path="new" component={VEO} />
<Route path=":cellID/edit" component={VEO} />
<Route path="new" component={NewVEO} />
<Route path=":cellID/edit" component={EditVEO} />
</Route>
<Route path="notes">
<Route path="new" component={NoteEditorOverlay} />
@ -313,7 +316,13 @@ class Root extends PureComponent {
/>
</Route>
<FeatureFlag name="alerting">
<Route path="alerting" component={AlertingIndex} />
<Route path="alerting" component={AlertingIndex}>
<Route path="checks/new" component={NewCheckEO} />
<Route
path="checks/:checkID/edit"
component={EditCheckEO}
/>
</Route>
<Route
path="alert-history"
component={AlertHistoryIndex}

View File

@ -23,6 +23,7 @@ import {
} from 'src/types'
import {Color} from 'src/types/colors'
import {HistogramPosition} from '@influxdata/giraffe'
import {TimeMachineEnum} from 'src/timeMachine/constants'
export type Action =
| QueryBuilderAction
@ -76,13 +77,13 @@ export type Action =
interface SetActiveTimeMachineAction {
type: 'SET_ACTIVE_TIME_MACHINE'
payload: {
activeTimeMachineID: string
activeTimeMachineID: TimeMachineEnum
initialState: Partial<TimeMachineState>
}
}
export const setActiveTimeMachine = (
activeTimeMachineID: string,
activeTimeMachineID: TimeMachineEnum,
initialState: Partial<TimeMachineState> = {}
): SetActiveTimeMachineAction => ({
type: 'SET_ACTIVE_TIME_MACHINE',

View File

@ -1,2 +1,5 @@
export const DE_TIME_MACHINE_ID = 'de'
export const VEO_TIME_MACHINE_ID = 'veo'
export enum TimeMachineEnum {
DE = 'de',
VEO = 'veo',
Alerting = 'alerting',
}

View File

@ -26,10 +26,7 @@ import {
import {createView} from 'src/shared/utils/view'
// Constants
import {
DE_TIME_MACHINE_ID,
VEO_TIME_MACHINE_ID,
} from 'src/timeMachine/constants'
import {TimeMachineEnum} from 'src/timeMachine/constants'
// Types
import {TimeMachineTab} from 'src/types/timeMachine'
@ -43,10 +40,10 @@ import {selectAggregateWindow} from '../actions/queryBuilder'
describe('timeMachinesReducer', () => {
test('it directs actions to the currently active timeMachine', () => {
const state = initialState()
const de = state.timeMachines[DE_TIME_MACHINE_ID]
const veo = state.timeMachines[VEO_TIME_MACHINE_ID]
const de = state.timeMachines[TimeMachineEnum.DE]
const veo = state.timeMachines[TimeMachineEnum.VEO]
expect(state.activeTimeMachineID).toEqual(DE_TIME_MACHINE_ID)
expect(state.activeTimeMachineID).toEqual(TimeMachineEnum.DE)
expect(de.activeTab).toEqual(TimeMachineTab.Queries)
expect(veo.activeTab).toEqual(TimeMachineTab.Queries)
@ -55,8 +52,8 @@ describe('timeMachinesReducer', () => {
setActiveTab(TimeMachineTab.Visualization)
)
const nextDE = nextState.timeMachines[DE_TIME_MACHINE_ID]
const nextVEO = nextState.timeMachines[VEO_TIME_MACHINE_ID]
const nextDE = nextState.timeMachines[TimeMachineEnum.DE]
const nextVEO = nextState.timeMachines[TimeMachineEnum.VEO]
expect(nextDE.activeTab).toEqual(TimeMachineTab.Visualization)
expect(nextVEO.activeTab).toEqual(TimeMachineTab.Queries)
@ -65,7 +62,7 @@ describe('timeMachinesReducer', () => {
test('it resets tab and draftScript state on a timeMachine when activated', () => {
const state = initialState()
expect(state.activeTimeMachineID).toEqual(DE_TIME_MACHINE_ID)
expect(state.activeTimeMachineID).toEqual(TimeMachineEnum.DE)
const activeTimeMachine = state.timeMachines[state.activeTimeMachineID]
@ -100,10 +97,10 @@ describe('timeMachinesReducer', () => {
const nextState = timeMachinesReducer(
state,
setActiveTimeMachine(VEO_TIME_MACHINE_ID, {view})
setActiveTimeMachine(TimeMachineEnum.VEO, {view})
)
expect(nextState.activeTimeMachineID).toEqual(VEO_TIME_MACHINE_ID)
expect(nextState.activeTimeMachineID).toEqual(TimeMachineEnum.VEO)
const nextTimeMachine =
nextState.timeMachines[nextState.activeTimeMachineID]

View File

@ -8,10 +8,7 @@ import {createView, defaultViewQuery} from 'src/shared/utils/view'
import {isConfigValid, buildQuery} from 'src/timeMachine/utils/queryBuilder'
// Constants
import {
VEO_TIME_MACHINE_ID,
DE_TIME_MACHINE_ID,
} from 'src/timeMachine/constants'
import {TimeMachineEnum} from 'src/timeMachine/constants'
import {AUTOREFRESH_DEFAULT} from 'src/shared/constants'
import {
THRESHOLD_TYPE_TEXT,
@ -71,9 +68,11 @@ export interface TimeMachineState {
}
export interface TimeMachinesState {
activeTimeMachineID: string
activeTimeMachineID: TimeMachineEnum
timeMachines: {
[timeMachineID: string]: TimeMachineState
[TimeMachineEnum.DE]: TimeMachineState
[TimeMachineEnum.VEO]: TimeMachineState
[TimeMachineEnum.Alerting]: TimeMachineState
}
}
@ -105,10 +104,11 @@ export const initialStateHelper = (): TimeMachineState => ({
})
export const initialState = (): TimeMachinesState => ({
activeTimeMachineID: DE_TIME_MACHINE_ID,
activeTimeMachineID: TimeMachineEnum.DE,
timeMachines: {
[VEO_TIME_MACHINE_ID]: initialStateHelper(),
[DE_TIME_MACHINE_ID]: initialStateHelper(),
[TimeMachineEnum.VEO]: initialStateHelper(),
[TimeMachineEnum.DE]: initialStateHelper(),
[TimeMachineEnum.Alerting]: initialStateHelper(),
},
})