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 creatorspull/14412/head
parent
491b2067b2
commit
6c700628fa
|
@ -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)))
|
||||
}
|
||||
}
|
|
@ -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)))
|
||||
}
|
||||
}
|
|
@ -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 don’t have any Checks , why not create one?"
|
||||
highlightWords={['Checks']}
|
||||
/>
|
||||
</EmptyState>
|
||||
)
|
||||
}
|
||||
|
||||
export default CheckCards
|
|
@ -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)
|
|
@ -0,0 +1,7 @@
|
|||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
const EndpointsColumn: FunctionComponent = () => {
|
||||
return <div>Endpoints</div>
|
||||
}
|
||||
|
||||
export default EndpointsColumn
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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, {}>(
|
||||
|
|
|
@ -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}`,
|
||||
})
|
||||
|
|
|
@ -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: () => '',
|
||||
})
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export {Check, NotificationRule} from '@influxdata/influx'
|
|
@ -30,3 +30,4 @@ export * from './members'
|
|||
export * from './autoRefresh'
|
||||
export * from './arguments'
|
||||
export * from './timeZones'
|
||||
export * from './alerting'
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue