From 6c700628fa6ae242c3bd3c8d8292cb40fdfd8b05 Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Mon, 22 Jul 2019 15:19:02 -0700 Subject: [PATCH] Add alerts page (#14406) * Add columns for checks, nr's and endpoints * Add checks getters and redux store * Add notification rules Store and fetching * Connect ChecksColumn to redux and add checkcards * specify const types in action creators --- ui/src/alerting/actions/checks.ts | 80 +++++++++++++++++ ui/src/alerting/actions/notificationRules.ts | 88 +++++++++++++++++++ ui/src/alerting/components/CheckCards.tsx | 25 ++++++ ui/src/alerting/components/ChecksColumn.tsx | 35 ++++++++ .../alerting/components/EndpointsColumn.tsx | 7 ++ .../components/NotificationRulesColumn.tsx | 29 ++++++ ui/src/alerting/containers/AlertingIndex.tsx | 43 ++++++++- ui/src/alerting/reducers/checks.ts | 47 ++++++++++ ui/src/alerting/reducers/notificationRules.ts | 50 +++++++++++ ui/src/shared/components/GetResources.tsx | 24 +++++ ui/src/shared/copy/notifications.ts | 20 +++++ ui/src/store/configureStore.ts | 4 + ui/src/types/alerting.ts | 1 + ui/src/types/index.ts | 1 + ui/src/types/stores.ts | 4 + 15 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 ui/src/alerting/actions/checks.ts create mode 100644 ui/src/alerting/actions/notificationRules.ts create mode 100644 ui/src/alerting/components/CheckCards.tsx create mode 100644 ui/src/alerting/components/ChecksColumn.tsx create mode 100644 ui/src/alerting/components/EndpointsColumn.tsx create mode 100644 ui/src/alerting/components/NotificationRulesColumn.tsx create mode 100644 ui/src/alerting/reducers/checks.ts create mode 100644 ui/src/alerting/reducers/notificationRules.ts create mode 100644 ui/src/types/alerting.ts diff --git a/ui/src/alerting/actions/checks.ts b/ui/src/alerting/actions/checks.ts new file mode 100644 index 0000000000..be88d101b7 --- /dev/null +++ b/ui/src/alerting/actions/checks.ts @@ -0,0 +1,80 @@ +// Libraries +import {client} from 'src/utils/api' +import {Dispatch} from 'react' + +// Constants +import * as copy from 'src/shared/copy/notifications' + +//Actions +import { + notify, + Action as NotificationAction, +} from 'src/shared/actions/notifications' + +// Types +import {RemoteDataState} from '@influxdata/clockface' +import {Check, GetState} from 'src/types' + +export type Action = + | ReturnType + | ReturnType + | ReturnType + | ReturnType + +const setAllChecks = (status: RemoteDataState, checks?: Check[]) => ({ + type: 'SET_ALL_CHECKS' as 'SET_ALL_CHECKS', + payload: {status, checks}, +}) + +const setChecksStatus = (status: RemoteDataState) => ({ + type: 'SET_CHECKS_STATUS' as 'SET_CHECKS_STATUS', + payload: {status}, +}) + +const setCheck = (status: RemoteDataState, check?: Check) => ({ + type: 'SET_CHECK' as 'SET_CHECK', + payload: {status, check}, +}) + +const setCheckStatus = (status: RemoteDataState) => ({ + type: 'SET_CHECK_STATUS' as 'SET_CHECK_STATUS', + payload: {status}, +}) + +export const getChecks = () => async ( + dispatch: Dispatch, + getState: GetState +) => { + try { + dispatch(setChecksStatus(RemoteDataState.Loading)) + const { + orgs: { + org: {id: orgID}, + }, + } = getState() + + const checks = await client.checks.getAll(orgID) + + dispatch(setAllChecks(RemoteDataState.Done, checks)) + } catch (e) { + console.error(e) + dispatch(setChecksStatus(RemoteDataState.Error)) + dispatch(notify(copy.getChecksFailed(e.message))) + } +} + +export const getCheck = (checkID: string) => async ( + dispatch: Dispatch +) => { + try { + dispatch(setCheckStatus(RemoteDataState.Loading)) + + const check = await client.checks.get(checkID) + + dispatch(setCheck(RemoteDataState.Done, check)) + } catch (e) { + console.error(e) + dispatch(setCheckStatus(RemoteDataState.Error)) + dispatch(notify(copy.getCheckFailed(e.message))) + } +} diff --git a/ui/src/alerting/actions/notificationRules.ts b/ui/src/alerting/actions/notificationRules.ts new file mode 100644 index 0000000000..753ec2c2d2 --- /dev/null +++ b/ui/src/alerting/actions/notificationRules.ts @@ -0,0 +1,88 @@ +// Libraries +import {client} from 'src/utils/api' +import {Dispatch} from 'react' + +// Constants +import * as copy from 'src/shared/copy/notifications' + +//Actions +import { + notify, + Action as NotificationAction, +} from 'src/shared/actions/notifications' + +// Types +import {RemoteDataState} from '@influxdata/clockface' +import {NotificationRule, GetState} from 'src/types' + +export type Action = + | ReturnType + | ReturnType + | ReturnType + | ReturnType + +const setAllNotificationRules = ( + status: RemoteDataState, + notificationRules?: NotificationRule[] +) => ({ + type: 'SET_ALL_NOTIFICATIONRULES' as 'SET_ALL_NOTIFICATIONRULES', + payload: {status, notificationRules}, +}) + +const setNotificationRulesStatus = (status: RemoteDataState) => ({ + type: 'SET_NOTIFICATIONRULES_STATUS' as 'SET_NOTIFICATIONRULES_STATUS', + payload: {status}, +}) + +const setNotificationRule = ( + status: RemoteDataState, + notificationRule?: NotificationRule +) => ({ + type: 'SET_NOTIFICATIONRULE' as 'SET_NOTIFICATIONRULE', + payload: {status, notificationRule}, +}) + +const setNotificationRuleStatus = (status: RemoteDataState) => ({ + type: 'SET_NOTIFICATIONRULE_STATUS' as 'SET_NOTIFICATIONRULE_STATUS', + payload: {status}, +}) + +export const getNotificationRules = () => async ( + dispatch: Dispatch, + getState: GetState +) => { + try { + dispatch(setNotificationRulesStatus(RemoteDataState.Loading)) + const { + orgs: { + org: {id: orgID}, + }, + } = getState() + + const notificationRules = await client.notificationRules.getAll(orgID) + + dispatch(setAllNotificationRules(RemoteDataState.Done, notificationRules)) + } catch (e) { + console.error(e) + dispatch(setNotificationRulesStatus(RemoteDataState.Error)) + dispatch(notify(copy.getNotificationRulesFailed(e.message))) + } +} + +export const getNotificationRule = (notificationRuleID: string) => async ( + dispatch: Dispatch +) => { + try { + dispatch(setNotificationRuleStatus(RemoteDataState.Loading)) + + const notificationRule = await client.notificationRules.get( + notificationRuleID + ) + + dispatch(setNotificationRule(RemoteDataState.Done, notificationRule)) + } catch (e) { + console.error(e) + dispatch(setNotificationRuleStatus(RemoteDataState.Error)) + dispatch(notify(copy.getNotificationRuleFailed(e.message))) + } +} diff --git a/ui/src/alerting/components/CheckCards.tsx b/ui/src/alerting/components/CheckCards.tsx new file mode 100644 index 0000000000..584cebba18 --- /dev/null +++ b/ui/src/alerting/components/CheckCards.tsx @@ -0,0 +1,25 @@ +import React, {FunctionComponent} from 'react' + +// Types +import {Check} from 'src/types' +import {EmptyState, ComponentSize} from '@influxdata/clockface' + +interface Props { + checks: Check[] +} + +const CheckCards: FunctionComponent = ({checks}) => { + if (checks && checks.length) { + return <> + } + return ( + + + + ) +} + +export default CheckCards diff --git a/ui/src/alerting/components/ChecksColumn.tsx b/ui/src/alerting/components/ChecksColumn.tsx new file mode 100644 index 0000000000..2a6cf0e718 --- /dev/null +++ b/ui/src/alerting/components/ChecksColumn.tsx @@ -0,0 +1,35 @@ +// Libraries +import React, {FunctionComponent} from 'react' +import {connect} from 'react-redux' + +// Types +import {Check, AppState} from 'src/types' +import CheckCards from 'src/alerting/components/CheckCards' + +interface StateProps { + checks: Check[] +} + +type Props = StateProps + +const ChecksColumn: FunctionComponent = ({checks}) => { + return ( + <> + Checks + + + ) +} + +const mstp = (state: AppState) => { + const { + checks: {list: checks}, + } = state + + return {checks} +} + +export default connect( + mstp, + null +)(ChecksColumn) diff --git a/ui/src/alerting/components/EndpointsColumn.tsx b/ui/src/alerting/components/EndpointsColumn.tsx new file mode 100644 index 0000000000..9664316e23 --- /dev/null +++ b/ui/src/alerting/components/EndpointsColumn.tsx @@ -0,0 +1,7 @@ +import React, {FunctionComponent} from 'react' + +const EndpointsColumn: FunctionComponent = () => { + return
Endpoints
+} + +export default EndpointsColumn diff --git a/ui/src/alerting/components/NotificationRulesColumn.tsx b/ui/src/alerting/components/NotificationRulesColumn.tsx new file mode 100644 index 0000000000..cc7bf75f0a --- /dev/null +++ b/ui/src/alerting/components/NotificationRulesColumn.tsx @@ -0,0 +1,29 @@ +// Libraries +import React, {FunctionComponent} from 'react' +import {connect} from 'react-redux' + +// Types +import {NotificationRule, AppState} from 'src/types' + +interface StateProps { + notificationRules: NotificationRule[] +} + +type Props = StateProps + +const NotificationRulesColumn: FunctionComponent = () => { + return <>NotificationRules +} + +const mstp = (state: AppState) => { + const { + notificationRules: {list: notificationRules}, + } = state + + return {notificationRules} +} + +export default connect( + mstp, + null +)(NotificationRulesColumn) diff --git a/ui/src/alerting/containers/AlertingIndex.tsx b/ui/src/alerting/containers/AlertingIndex.tsx index 06295bdfa1..9016f94bc3 100644 --- a/ui/src/alerting/containers/AlertingIndex.tsx +++ b/ui/src/alerting/containers/AlertingIndex.tsx @@ -1,7 +1,46 @@ +// Libraries import React, {FunctionComponent} from 'react' -const AlertingIndex: FunctionComponent = () => { - return
+//Components +import {Page, Grid, GridRow, GridColumn} from '@influxdata/clockface' +import PageTitleWithOrg from 'src/shared/components/PageTitleWithOrg' +import ChecksColumn from 'src/alerting/components/ChecksColumn' +import NotificationRulesColumn from 'src/alerting/components/NotificationRulesColumn' +import EndpointsColumn from 'src/alerting/components/EndpointsColumn' +import GetResources, {ResourceTypes} from 'src/shared/components/GetResources' + +const AlertingIndex: FunctionComponent = ({children}) => { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + {children} + + ) } export default AlertingIndex diff --git a/ui/src/alerting/reducers/checks.ts b/ui/src/alerting/reducers/checks.ts new file mode 100644 index 0000000000..b58fb2f03e --- /dev/null +++ b/ui/src/alerting/reducers/checks.ts @@ -0,0 +1,47 @@ +// Types +import {RemoteDataState, Check} from 'src/types' +import {Action} from 'src/alerting/actions/checks' + +export interface ChecksState { + status: RemoteDataState + list: Check[] + current: {status: RemoteDataState; check: Check} +} + +export const defaultChecksState: ChecksState = { + status: RemoteDataState.NotStarted, + list: [], + current: {status: RemoteDataState.NotStarted, check: null}, +} + +export default ( + state: ChecksState = defaultChecksState, + action: Action +): ChecksState => { + switch (action.type) { + case 'SET_CHECKS_STATUS': + return { + ...state, + status: action.payload.status, + } + case 'SET_ALL_CHECKS': + return { + ...state, + list: action.payload.checks, + status: RemoteDataState.Done, + } + case 'SET_CHECK_STATUS': + return { + ...state, + current: {...state.current, status: action.payload.status}, + } + case 'SET_CHECK': + return { + ...state, + current: {status: action.payload.status, check: action.payload.check}, + } + + default: + return state + } +} diff --git a/ui/src/alerting/reducers/notificationRules.ts b/ui/src/alerting/reducers/notificationRules.ts new file mode 100644 index 0000000000..046a5608b0 --- /dev/null +++ b/ui/src/alerting/reducers/notificationRules.ts @@ -0,0 +1,50 @@ +// Types +import {RemoteDataState, NotificationRule} from 'src/types' +import {Action} from 'src/alerting/actions/notificationRules' + +export interface NotificationRulesState { + status: RemoteDataState + list: NotificationRule[] + current: {status: RemoteDataState; notificationRule: NotificationRule} +} + +export const defaultNotificationRuleState: NotificationRulesState = { + status: RemoteDataState.NotStarted, + list: [], + current: {status: RemoteDataState.NotStarted, notificationRule: null}, +} + +export default ( + state: NotificationRulesState = defaultNotificationRuleState, + action: Action +): NotificationRulesState => { + switch (action.type) { + case 'SET_NOTIFICATIONRULES_STATUS': + return { + ...state, + status: action.payload.status, + } + case 'SET_ALL_NOTIFICATIONRULES': + return { + ...state, + list: action.payload.notificationRules, + status: RemoteDataState.Done, + } + case 'SET_NOTIFICATIONRULE_STATUS': + return { + ...state, + current: {...state.current, status: action.payload.status}, + } + case 'SET_NOTIFICATIONRULE': + return { + ...state, + current: { + status: action.payload.status, + notificationRule: action.payload.notificationRule, + }, + } + + default: + return state + } +} diff --git a/ui/src/shared/components/GetResources.tsx b/ui/src/shared/components/GetResources.tsx index 29c67d7bb1..7cc4063b6f 100644 --- a/ui/src/shared/components/GetResources.tsx +++ b/ui/src/shared/components/GetResources.tsx @@ -14,6 +14,8 @@ import {getTasks} from 'src/tasks/actions' import {getAuthorizations} from 'src/authorizations/actions' import {getTemplates} from 'src/templates/actions' import {getMembers, getUsers} from 'src/members/actions' +import {getChecks} from 'src/alerting/actions/checks' +import {getNotificationRules} from 'src/alerting/actions/notificationRules' // Types import {AppState} from 'src/types' @@ -27,6 +29,8 @@ import {AuthorizationsState} from 'src/authorizations/reducers' import {VariablesState} from 'src/variables/reducers' import {TemplatesState} from 'src/templates/reducers' import {MembersState, UsersMap} from 'src/members/reducers' +import {ChecksState} from 'src/alerting/reducers/checks' +import {NotificationRulesState} from 'src/alerting/reducers/notificationRules' // Components import {ErrorHandling} from 'src/shared/decorators/errors' @@ -48,6 +52,8 @@ interface StateProps { tasks: TasksState members: MembersState users: {status: RemoteDataState; item: UsersMap} + checks: ChecksState + notificationRules: NotificationRulesState } interface DispatchProps { @@ -62,6 +68,8 @@ interface DispatchProps { getTemplates: typeof getTemplates getMembers: typeof getMembers getUsers: typeof getUsers + getChecks: typeof getChecks + getNotificationRules: typeof getNotificationRules } interface PassedProps { @@ -82,6 +90,8 @@ export enum ResourceTypes { Templates = 'templates', Members = 'members', Users = 'users', + Checks = 'checks', + NotificationRules = 'notificationRules', } @ErrorHandling @@ -132,6 +142,14 @@ class GetResources extends PureComponent { return await this.props.getUsers() } + case ResourceTypes.Checks: { + return await this.props.getChecks() + } + + case ResourceTypes.NotificationRules: { + return await this.props.getNotificationRules() + } + default: { throw new Error('incorrect resource type provided') } @@ -163,6 +181,8 @@ const mstp = ({ tasks, templates, members, + checks, + notificationRules, }: AppState): StateProps => { return { labels, @@ -176,6 +196,8 @@ const mstp = ({ templates, members, users: members.users, + checks, + notificationRules, } } @@ -191,6 +213,8 @@ const mdtp = { getTemplates: getTemplates, getMembers: getMembers, getUsers: getUsers, + getChecks: getChecks, + getNotificationRules: getNotificationRules, } export default connect( diff --git a/ui/src/shared/copy/notifications.ts b/ui/src/shared/copy/notifications.ts index e585502e41..7ed39bb068 100644 --- a/ui/src/shared/copy/notifications.ts +++ b/ui/src/shared/copy/notifications.ts @@ -727,3 +727,23 @@ export const invalidMapType = (): Notification => ({ ...defaultErrorNotification, message: `Variables of type map accept two comma separated values per line`, }) + +export const getChecksFailed = (message: string): Notification => ({ + ...defaultErrorNotification, + message: `Failed to get checks: ${message}`, +}) + +export const getCheckFailed = (message: string): Notification => ({ + ...defaultErrorNotification, + message: `Failed to get check: ${message}`, +}) + +export const getNotificationRulesFailed = (message: string): Notification => ({ + ...defaultErrorNotification, + message: `Failed to get notification rules: ${message}`, +}) + +export const getNotificationRuleFailed = (message: string): Notification => ({ + ...defaultErrorNotification, + message: `Failed to get notification rule: ${message}`, +}) diff --git a/ui/src/store/configureStore.ts b/ui/src/store/configureStore.ts index 8d32bfbf8d..99ee2ef635 100644 --- a/ui/src/store/configureStore.ts +++ b/ui/src/store/configureStore.ts @@ -31,6 +31,8 @@ import {userSettingsReducer} from 'src/userSettings/reducers' import {membersReducer} from 'src/members/reducers' import {autoRefreshReducer} from 'src/shared/reducers/autoRefresh' import {limitsReducer, LimitsState} from 'src/cloud/reducers/limits' +import checksReducer from 'src/alerting/reducers/checks' +import notificationRulesReducer from 'src/alerting/reducers/notificationRules' // Types import {LocalStorage} from 'src/types/localStorage' @@ -62,6 +64,8 @@ export const rootReducer = combineReducers({ userSettings: userSettingsReducer, members: membersReducer, cloud: combineReducers<{limits: LimitsState}>({limits: limitsReducer}), + checks: checksReducer, + notificationRules: notificationRulesReducer, VERSION: () => '', }) diff --git a/ui/src/types/alerting.ts b/ui/src/types/alerting.ts new file mode 100644 index 0000000000..06c8b2a667 --- /dev/null +++ b/ui/src/types/alerting.ts @@ -0,0 +1 @@ +export {Check, NotificationRule} from '@influxdata/influx' diff --git a/ui/src/types/index.ts b/ui/src/types/index.ts index 1717a4b99e..a0550302ca 100644 --- a/ui/src/types/index.ts +++ b/ui/src/types/index.ts @@ -30,3 +30,4 @@ export * from './members' export * from './autoRefresh' export * from './arguments' export * from './timeZones' +export * from './alerting' diff --git a/ui/src/types/stores.ts b/ui/src/types/stores.ts index 34d5dabd94..fb2967e73c 100644 --- a/ui/src/types/stores.ts +++ b/ui/src/types/stores.ts @@ -24,6 +24,8 @@ import {OrgsState} from 'src/organizations/reducers/orgs' import {MembersState} from 'src/members/reducers' import {AutoRefreshState} from 'src/shared/reducers/autoRefresh' import {LimitsState} from 'src/cloud/reducers/limits' +import {ChecksState} from 'src/alerting/reducers/checks' +import {NotificationRulesState} from 'src/alerting/reducers/notificationRules' export interface AppState { VERSION: string @@ -53,6 +55,8 @@ export interface AppState { userSettings: UserSettingsState members: MembersState cloud: {limits: LimitsState} + checks: ChecksState + notificationRules: NotificationRulesState } export type GetState = () => AppState