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
pull/14412/head
Deniz Kusefoglu 2019-07-22 15:19:02 -07:00 committed by GitHub
parent 491b2067b2
commit 6c700628fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 456 additions and 2 deletions

View File

@ -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<typeof setAllChecks>
| ReturnType<typeof setChecksStatus>
| ReturnType<typeof setCheck>
| ReturnType<typeof setCheckStatus>
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<Action | NotificationAction>,
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<Action | NotificationAction>
) => {
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)))
}
}

View File

@ -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<typeof setAllNotificationRules>
| ReturnType<typeof setNotificationRulesStatus>
| ReturnType<typeof setNotificationRule>
| ReturnType<typeof setNotificationRuleStatus>
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<Action | NotificationAction>,
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<Action | NotificationAction>
) => {
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)))
}
}

View File

@ -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<Props> = ({checks}) => {
if (checks && checks.length) {
return <></>
}
return (
<EmptyState size={ComponentSize.ExtraSmall}>
<EmptyState.Text
text="Looks like you dont have any Checks , why not create one?"
highlightWords={['Checks']}
/>
</EmptyState>
)
}
export default CheckCards

View File

@ -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<Props> = ({checks}) => {
return (
<>
Checks
<CheckCards checks={checks} />
</>
)
}
const mstp = (state: AppState) => {
const {
checks: {list: checks},
} = state
return {checks}
}
export default connect<StateProps, {}, {}>(
mstp,
null
)(ChecksColumn)

View File

@ -0,0 +1,7 @@
import React, {FunctionComponent} from 'react'
const EndpointsColumn: FunctionComponent = () => {
return <div>Endpoints</div>
}
export default EndpointsColumn

View File

@ -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<Props> = () => {
return <>NotificationRules</>
}
const mstp = (state: AppState) => {
const {
notificationRules: {list: notificationRules},
} = state
return {notificationRules}
}
export default connect<StateProps, {}, {}>(
mstp,
null
)(NotificationRulesColumn)

View File

@ -1,7 +1,46 @@
// Libraries
import React, {FunctionComponent} from 'react'
const AlertingIndex: FunctionComponent = () => {
return <div />
//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 (
<>
<Page titleTag="Alerting">
<Page.Header fullWidth={false}>
<Page.Header.Left>
<PageTitleWithOrg title="Alerting" />
</Page.Header.Left>
</Page.Header>
<Page.Contents fullWidth={true} scrollable={true}>
<Grid>
<GridRow testID="grid--row">
<GridColumn widthLG={4} widthMD={4} widthSM={4} widthXS={12}>
<GetResources resource={ResourceTypes.Checks}>
<ChecksColumn />
</GetResources>
</GridColumn>
<GridColumn widthLG={4} widthMD={4} widthSM={4} widthXS={12}>
<GetResources resource={ResourceTypes.NotificationRules}>
<NotificationRulesColumn />
</GetResources>
</GridColumn>
<GridColumn widthLG={4} widthMD={4} widthSM={4} widthXS={12}>
<EndpointsColumn />
</GridColumn>
</GridRow>
</Grid>
</Page.Contents>
</Page>
{children}
</>
)
}
export default AlertingIndex

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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<Props, StateProps> {
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<StateProps, DispatchProps, {}>(

View File

@ -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}`,
})

View File

@ -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<ReducerState>({
userSettings: userSettingsReducer,
members: membersReducer,
cloud: combineReducers<{limits: LimitsState}>({limits: limitsReducer}),
checks: checksReducer,
notificationRules: notificationRulesReducer,
VERSION: () => '',
})

1
ui/src/types/alerting.ts Normal file
View File

@ -0,0 +1 @@
export {Check, NotificationRule} from '@influxdata/influx'

View File

@ -30,3 +30,4 @@ export * from './members'
export * from './autoRefresh'
export * from './arguments'
export * from './timeZones'
export * from './alerting'

View File

@ -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