From bca1af25a9a315634e836aad3e8c89cb6da2476b Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Mon, 5 Aug 2019 17:38:49 -0700 Subject: [PATCH] feat: alerting - Add alert builder (#14550) * Add check saving flows and change activeTab type * Add first pass at alertBuilder * Change TimeMachineEnum type * Add xy view properties to checks, and convert to and from check View type * Add Column Header to checks column * Add change current check type action * Access view type through properties * Load xy view options for check view * Add orgID to check in createCheck * Clear current check on close CheckEO * Create Check Alerting Button * Create check view on edit and new check EO * Fix edit check eo action bug * Update threshold types * When switch schedule from every to cron change the inputs that are visible * save Current Check from VEO if view type is check * Add description component to checks * TimeMachineIDs to TimeMachineID * Remove bracketed object decleration * Remove as Threshold type * Use ViewType instead of typeof * Create CheckType type * Remove time machine reducer tests * Remove check view properties that come from xyView * Fix EditCheck hooks * Move status calculations to body of function * Update redux store when performing check CRUD * Create add and remove check actions in timeMachine * Remove trailing space --- http/swagger.yml | 12 +- ui/src/alerting/actions/checks.ts | 58 +- .../components/CheckAlertingButton.tsx | 63 ++ ui/src/alerting/components/CheckCard.tsx | 14 +- ui/src/alerting/components/CheckEOHeader.tsx | 75 ++ ui/src/alerting/components/ChecksColumn.tsx | 21 +- ui/src/alerting/components/EditCheckEO.tsx | 87 ++- ui/src/alerting/components/NewCheckEO.tsx | 44 +- .../components/builder/AlertBuilder.tsx | 42 ++ .../builder/CheckMatchingRulesCard.tsx | 8 + .../components/builder/CheckMetaCard.tsx | 225 ++++++ .../builder/CheckThresholdsCard.tsx | 8 + .../components/builder/HelpButton.tsx | 19 + .../components/builder/RemoveButton.tsx | 48 ++ ui/src/alerting/constants/index.ts | 33 +- ui/src/alerting/reducers/checks.ts | 28 +- ui/src/client/index.ts | 27 +- ui/src/dashboards/actions/views.ts | 14 +- ui/src/dashboards/components/EditVEO.tsx | 34 +- ui/src/dashboards/components/NewVEO.tsx | 36 +- ui/src/dashboards/components/VEOHeader.tsx | 2 + .../dataExplorer/components/DataExplorer.tsx | 3 +- ui/src/shared/components/CheckPlot.tsx | 5 +- .../components/GreaterThresholdMarker.tsx | 12 +- .../shared/components/LessThresholdMarker.tsx | 12 +- .../components/RangeThresholdMarkers.tsx | 20 +- ui/src/shared/components/ThresholdMarkers.tsx | 81 +-- ui/src/shared/components/ViewSwitcher.tsx | 1 - ui/src/shared/utils/view.ts | 13 +- ui/src/timeMachine/actions/index.ts | 16 +- .../timeMachine/components/AlertingButton.tsx | 86 +++ ui/src/timeMachine/components/TimeMachine.tsx | 23 +- .../components/TimeMachineAlerting.tsx | 45 ++ .../components/VisOptionsButton.tsx | 8 +- .../view_options/ViewTypeDropdown.tsx | 11 +- ui/src/timeMachine/constants/index.ts | 6 +- ui/src/timeMachine/reducers/index.test.ts | 657 ------------------ ui/src/timeMachine/reducers/index.ts | 35 +- ui/src/types/alerting.ts | 7 +- ui/src/types/timeMachine.ts | 5 +- 40 files changed, 1052 insertions(+), 892 deletions(-) create mode 100644 ui/src/alerting/components/CheckAlertingButton.tsx create mode 100644 ui/src/alerting/components/CheckEOHeader.tsx create mode 100644 ui/src/alerting/components/builder/AlertBuilder.tsx create mode 100644 ui/src/alerting/components/builder/CheckMatchingRulesCard.tsx create mode 100644 ui/src/alerting/components/builder/CheckMetaCard.tsx create mode 100644 ui/src/alerting/components/builder/CheckThresholdsCard.tsx create mode 100644 ui/src/alerting/components/builder/HelpButton.tsx create mode 100644 ui/src/alerting/components/builder/RemoveButton.tsx create mode 100644 ui/src/timeMachine/components/AlertingButton.tsx create mode 100644 ui/src/timeMachine/components/TimeMachineAlerting.tsx delete mode 100644 ui/src/timeMachine/reducers/index.test.ts diff --git a/http/swagger.yml b/http/swagger.yml index 0dbedfa36c..d9475b4862 100644 --- a/http/swagger.yml +++ b/http/swagger.yml @@ -7506,7 +7506,8 @@ components: - type - shape - checkID - - check + - queries + - colors properties: type: type: string @@ -7518,6 +7519,15 @@ components: type: string check: $ref: '#/components/schemas/Check' + queries: + type: array + items: + $ref: "#/components/schemas/DashboardQuery" + colors: + description: Colors define color encoding of data into a visualization + type: array + items: + type: string Axes: description: The viewport for a View's visualizations type: object diff --git a/ui/src/alerting/actions/checks.ts b/ui/src/alerting/actions/checks.ts index e42ecadb7e..22d204d056 100644 --- a/ui/src/alerting/actions/checks.ts +++ b/ui/src/alerting/actions/checks.ts @@ -7,6 +7,9 @@ import * as copy from 'src/shared/copy/notifications' // APIs import * as api from 'src/client' +// Utils +import {getActiveTimeMachine} from 'src/timeMachine/selectors' + //Actions import { notify, @@ -15,14 +18,16 @@ import { // Types import {RemoteDataState} from '@influxdata/clockface' -import {Check, GetState} from 'src/types' +import {Check, GetState, CheckType} from 'src/types' export type Action = | ReturnType | ReturnType | ReturnType | ReturnType + | ReturnType | ReturnType + | ReturnType export const setAllChecks = (status: RemoteDataState, checks?: Check[]) => ({ type: 'SET_ALL_CHECKS' as 'SET_ALL_CHECKS', @@ -41,17 +46,27 @@ export const removeCheck = (checkID: string) => ({ export const setCurrentCheck = ( status: RemoteDataState, - check?: Partial + check: Partial ) => ({ type: 'SET_CURRENT_CHECK' as 'SET_CURRENT_CHECK', payload: {status, check}, }) +export const setCurrentCheckStatus = (status: RemoteDataState) => ({ + type: 'SET_CURRENT_CHECK_STATUS' as 'SET_CURRENT_CHECK_STATUS', + payload: {status}, +}) + export const updateCurrentCheck = (checkUpdate: Partial) => ({ type: 'UPDATE_CURRENT_CHECK' as 'UPDATE_CURRENT_CHECK', payload: {status, checkUpdate}, }) +export const changeCurrentCheckType = (type: CheckType) => ({ + type: 'CHANGE_CURRENT_CHECK_TYPE' as 'CHANGE_CURRENT_CHECK_TYPE', + payload: {status, type}, +}) + export const getChecks = () => async ( dispatch: Dispatch, getState: GetState @@ -82,7 +97,7 @@ export const getCurrentCheck = (checkID: string) => async ( dispatch: Dispatch ) => { try { - dispatch(setCurrentCheck(RemoteDataState.Loading)) + dispatch(setCurrentCheckStatus(RemoteDataState.Loading)) const resp = await api.getCheck({checkID}) @@ -93,18 +108,37 @@ export const getCurrentCheck = (checkID: string) => async ( dispatch(setCurrentCheck(RemoteDataState.Done, resp.data)) } catch (e) { console.error(e) - dispatch(setCurrentCheck(RemoteDataState.Error)) + dispatch(setCurrentCheckStatus(RemoteDataState.Error)) dispatch(notify(copy.getCheckFailed(e.message))) } } -export const createCheck = (check: Partial) => async ( - dispatch: Dispatch +export const saveCurrentCheck = () => async ( + dispatch: Dispatch, + getState: GetState ) => { try { - const resp = await api.postCheck({data: check as Check}) + const state = getState() + const { + checks: { + current: {check}, + }, + orgs: { + org: {id: orgID}, + }, + } = state - if (resp.status !== 201) { + const {draftQueries} = getActiveTimeMachine(state) + + const checkWithOrg = {...check, query: draftQueries[0], orgID} as Check + + const resp = check.id + ? await api.patchCheck({checkID: check.id, data: checkWithOrg}) + : await api.postCheck({data: checkWithOrg}) + + if (resp.status === 201 || resp.status === 200) { + dispatch(setCheck(resp.data)) + } else { throw new Error(resp.data.message) } } catch (e) { @@ -119,7 +153,9 @@ export const updateCheck = (check: Partial) => async ( try { const resp = await api.patchCheck({checkID: check.id, data: check as Check}) - if (resp.status !== 200) { + if (resp.status === 200) { + dispatch(setCheck(resp.data)) + } else { throw new Error(resp.data.message) } @@ -136,7 +172,9 @@ export const deleteCheck = (checkID: string) => async ( try { const resp = await api.deleteCheck({checkID}) - if (resp.status !== 204) { + if (resp.status === 204) { + dispatch(removeCheck(checkID)) + } else { throw new Error(resp.data.message) } diff --git a/ui/src/alerting/components/CheckAlertingButton.tsx b/ui/src/alerting/components/CheckAlertingButton.tsx new file mode 100644 index 0000000000..08d31c9e97 --- /dev/null +++ b/ui/src/alerting/components/CheckAlertingButton.tsx @@ -0,0 +1,63 @@ +// Libraries +import React, {FunctionComponent} from 'react' +import {connect} from 'react-redux' + +// Components +import {Button, ComponentStatus} from '@influxdata/clockface' + +// Utils +import {getActiveTimeMachine} from 'src/timeMachine/selectors' + +// Actions +import {setActiveTab} from 'src/timeMachine/actions' + +// Types +import {AppState, TimeMachineTab} from 'src/types' + +interface DispatchProps { + setActiveTab: typeof setActiveTab +} + +interface StateProps { + activeTab: TimeMachineTab +} + +type Props = DispatchProps & StateProps + +const CheckAlertingButton: FunctionComponent = ({ + setActiveTab, + activeTab, +}) => { + let buttonStatus = ComponentStatus.Default + if (activeTab === 'alerting') { + buttonStatus = ComponentStatus.Disabled + } + + const handleClick = () => { + setActiveTab('alerting') + } + + return ( +