feat: add check tags (#14700)
* Enable getChecks * Fix EditCheck check getting * Fix threshold null bugs * Add CheckTagSet editing * Remove console.logpull/14712/head
parent
86cca67de1
commit
b90cfc91e5
|
@ -15,11 +15,15 @@ import {
|
|||
notify,
|
||||
Action as NotificationAction,
|
||||
} from 'src/shared/actions/notifications'
|
||||
import {Action as TimeMachineAction} from 'src/timeMachine/actions'
|
||||
import {setCheckStatus, setTimeMachineCheck} from 'src/timeMachine/actions'
|
||||
import {
|
||||
Action as TimeMachineAction,
|
||||
setActiveTimeMachine,
|
||||
} from 'src/timeMachine/actions'
|
||||
import {setCheckStatus} from 'src/timeMachine/actions'
|
||||
|
||||
// Types
|
||||
import {Check, GetState, RemoteDataState} from 'src/types'
|
||||
import {Check, GetState, RemoteDataState, CheckViewProperties} from 'src/types'
|
||||
import {createView} from 'src/shared/utils/view'
|
||||
|
||||
export type Action =
|
||||
| ReturnType<typeof setAllChecks>
|
||||
|
@ -42,25 +46,24 @@ export const removeCheck = (checkID: string) => ({
|
|||
})
|
||||
|
||||
export const getChecks = () => async (
|
||||
dispatch: Dispatch<Action | NotificationAction>
|
||||
// getState: GetState
|
||||
dispatch: Dispatch<Action | NotificationAction>,
|
||||
getState: GetState
|
||||
) => {
|
||||
try {
|
||||
dispatch(setAllChecks(RemoteDataState.Loading))
|
||||
// TODO: use this when its actually implemented
|
||||
// const {
|
||||
// orgs: {
|
||||
// org: {id: orgID},
|
||||
// },
|
||||
// } = getState()
|
||||
const {
|
||||
orgs: {
|
||||
org: {id: orgID},
|
||||
},
|
||||
} = getState()
|
||||
|
||||
// const resp = await api.getChecks({query: {orgID}})
|
||||
const resp = await api.getChecks({query: {orgID}})
|
||||
|
||||
// if (resp.status !== 200) {
|
||||
// throw new Error(resp.data.message)
|
||||
// }
|
||||
if (resp.status !== 200) {
|
||||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(setAllChecks(RemoteDataState.Done, []))
|
||||
dispatch(setAllChecks(RemoteDataState.Done, resp.data.checks))
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(setAllChecks(RemoteDataState.Error))
|
||||
|
@ -80,7 +83,15 @@ export const getCheckForTimeMachine = (checkID: string) => async (
|
|||
throw new Error(resp.data.message)
|
||||
}
|
||||
|
||||
dispatch(setTimeMachineCheck(RemoteDataState.Done, resp.data))
|
||||
const view = createView<CheckViewProperties>('check')
|
||||
// todo: when check has own view get view here
|
||||
dispatch(
|
||||
setActiveTimeMachine('alerting', {
|
||||
view,
|
||||
activeTab: 'alerting',
|
||||
alerting: {check: resp.data, checkStatus: RemoteDataState.Done},
|
||||
})
|
||||
)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
dispatch(setCheckStatus(RemoteDataState.Error))
|
||||
|
|
|
@ -9,7 +9,6 @@ import CheckEOHeader from 'src/alerting/components/CheckEOHeader'
|
|||
import TimeMachine from 'src/timeMachine/components/TimeMachine'
|
||||
|
||||
// Utils
|
||||
import {createView} from 'src/shared/utils/view'
|
||||
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
|
||||
// Actions
|
||||
|
@ -26,7 +25,6 @@ import {
|
|||
AppState,
|
||||
RemoteDataState,
|
||||
DashboardDraftQuery,
|
||||
CheckViewProperties,
|
||||
TimeMachineID,
|
||||
} from 'src/types'
|
||||
|
||||
|
@ -51,7 +49,6 @@ const EditCheckEditorOverlay: FunctionComponent<Props> = ({
|
|||
onUpdateCheck,
|
||||
onGetCheckForTimeMachine,
|
||||
onUpdateTimeMachineCheck,
|
||||
onSetActiveTimeMachine,
|
||||
onSetTimeMachineCheck,
|
||||
activeTimeMachineID,
|
||||
checkStatus,
|
||||
|
@ -61,26 +58,16 @@ const EditCheckEditorOverlay: FunctionComponent<Props> = ({
|
|||
check,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (check) {
|
||||
const view = createView<CheckViewProperties>('check')
|
||||
// todo: when check has own view get view here
|
||||
onSetActiveTimeMachine('alerting', {
|
||||
view,
|
||||
activeTab: 'alerting',
|
||||
isViewingRawData: false,
|
||||
})
|
||||
} else {
|
||||
onGetCheckForTimeMachine(checkID)
|
||||
}
|
||||
}, [check, checkID])
|
||||
onGetCheckForTimeMachine(checkID)
|
||||
}, [checkID])
|
||||
|
||||
const handleUpdateName = (name: string) => {
|
||||
onUpdateTimeMachineCheck({name})
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
onSetTimeMachineCheck(RemoteDataState.NotStarted, null)
|
||||
router.push(`/orgs/${orgID}/alerting`)
|
||||
onSetTimeMachineCheck(RemoteDataState.NotStarted, null)
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Libraries
|
||||
import React, {FC, ChangeEvent} from 'react'
|
||||
import React, {FC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {get} from 'lodash'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -13,8 +12,12 @@ import {
|
|||
TextArea,
|
||||
AutoComplete,
|
||||
Wrap,
|
||||
ComponentColor,
|
||||
Grid,
|
||||
} from '@influxdata/clockface'
|
||||
import {Input} from '@influxdata/clockface'
|
||||
import DashedButton from 'src/shared/components/dashed_button/DashedButton'
|
||||
import CheckTagRow from 'src/alerting/components/builder/CheckTagRow'
|
||||
|
||||
// Actions
|
||||
import {updateTimeMachineCheck, changeCheckType} from 'src/timeMachine/actions'
|
||||
|
@ -23,7 +26,7 @@ import {updateTimeMachineCheck, changeCheckType} from 'src/timeMachine/actions'
|
|||
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {Check, AppState, CheckType} from 'src/types'
|
||||
import {Check, AppState, CheckType, CheckTagSet} from 'src/types'
|
||||
import {
|
||||
DEFAULT_CHECK_EVERY,
|
||||
DEFAULT_CHECK_OFFSET,
|
||||
|
@ -50,24 +53,15 @@ const CheckMetaCard: FC<Props> = ({
|
|||
changeCheckType(type)
|
||||
}
|
||||
|
||||
const handleChangeName = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateTimeMachineCheck({name: e.target.value})
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
updateTimeMachineCheck({[e.target.name]: e.target.value})
|
||||
}
|
||||
|
||||
const handleChangeKey = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateTimeMachineCheck({
|
||||
tags: [{key: e.target.value, value: get(check, 'tags[0].value', '')}],
|
||||
})
|
||||
}
|
||||
const handleChangeValue = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
updateTimeMachineCheck({
|
||||
tags: [{value: e.target.value, key: get(check, 'tags[0].key', '')}],
|
||||
})
|
||||
}
|
||||
|
||||
const handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const statusMessageTemplate = e.target.value
|
||||
updateTimeMachineCheck({statusMessageTemplate})
|
||||
const addTagsRow = () => {
|
||||
const tags = check.tags || []
|
||||
updateTimeMachineCheck({tags: [...tags, {key: '', value: ''}]})
|
||||
}
|
||||
|
||||
const handleChangeSchedule = (scheduleType: 'cron' | 'every') => {
|
||||
|
@ -88,6 +82,12 @@ const CheckMetaCard: FC<Props> = ({
|
|||
return
|
||||
}
|
||||
}
|
||||
const handleChangeTagRow = (index: number, tagSet: CheckTagSet) => {
|
||||
const tags = [...check.tags]
|
||||
tags[index] = tagSet
|
||||
updateTimeMachineCheck({tags})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Element label="Check Type">
|
||||
|
@ -117,15 +117,10 @@ const CheckMetaCard: FC<Props> = ({
|
|||
<Form.Element label="Name">
|
||||
<Input
|
||||
autoFocus={true}
|
||||
maxLength={24}
|
||||
name="Name"
|
||||
onChange={handleChangeName}
|
||||
name="name"
|
||||
onChange={handleChange}
|
||||
placeholder="Name this check"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
testID="input-field"
|
||||
titleText="Title Text"
|
||||
type={InputType.Text}
|
||||
value={check.name}
|
||||
/>
|
||||
</Form.Element>
|
||||
|
@ -139,8 +134,8 @@ const CheckMetaCard: FC<Props> = ({
|
|||
form=""
|
||||
maxLength={50}
|
||||
minLength={5}
|
||||
name=""
|
||||
onChange={handleChangeMessage}
|
||||
name="statusMessageTemplate"
|
||||
onChange={handleChange}
|
||||
placeholder="Example: {tags.cpu} exceeded threshold: {value}%"
|
||||
readOnly={false}
|
||||
required={false}
|
||||
|
@ -151,30 +146,6 @@ const CheckMetaCard: FC<Props> = ({
|
|||
wrap={Wrap.Soft}
|
||||
/>
|
||||
</Form.Element>
|
||||
<Form.Element label="Tag-Key">
|
||||
<Input
|
||||
maxLength={24}
|
||||
name="TagKey"
|
||||
onChange={handleChangeKey}
|
||||
placeholder="Key"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
testID="input-field"
|
||||
value={get(check, 'tags[0].key', '')}
|
||||
/>
|
||||
</Form.Element>
|
||||
<Form.Element label="Tag-Value">
|
||||
<Input
|
||||
maxLength={24}
|
||||
name="TagValue"
|
||||
onChange={handleChangeValue}
|
||||
placeholder="Value"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
testID="input-field"
|
||||
value={get(check, 'tags[0].value', '')}
|
||||
/>
|
||||
</Form.Element>
|
||||
<Form.Element label="Schedule">
|
||||
<Radio shape={ButtonShape.StretchToFit}>
|
||||
<Radio.Button
|
||||
|
@ -199,47 +170,41 @@ const CheckMetaCard: FC<Props> = ({
|
|||
</Radio.Button>
|
||||
</Radio>
|
||||
</Form.Element>
|
||||
{check.every != null && (
|
||||
<Form.Element label="Every">
|
||||
<Input
|
||||
autoFocus={false}
|
||||
maxLength={24}
|
||||
name="Name"
|
||||
onChange={handleChangeName}
|
||||
placeholder="Name this check"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
testID="input-field"
|
||||
titleText="Name of the check"
|
||||
type={InputType.Text}
|
||||
value={check.every}
|
||||
/>
|
||||
</Form.Element>
|
||||
)}
|
||||
{check.offset != null && (
|
||||
<Form.Element label="Offset">
|
||||
<Input
|
||||
autoFocus={false}
|
||||
maxLength={24}
|
||||
name="Offset"
|
||||
onChange={handleChangeName}
|
||||
placeholder="offset"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
testID="input-field"
|
||||
titleText="Offset check interval"
|
||||
type={InputType.Text}
|
||||
value={check.offset}
|
||||
/>
|
||||
</Form.Element>
|
||||
)}
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthSM={6}>
|
||||
{check.every != null && (
|
||||
<Form.Element label="Every">
|
||||
<Input
|
||||
name="every"
|
||||
onChange={handleChange}
|
||||
titleText="Name of the check"
|
||||
value={check.every}
|
||||
/>
|
||||
</Form.Element>
|
||||
)}
|
||||
</Grid.Column>
|
||||
<Grid.Column widthSM={6}>
|
||||
{check.offset != null && (
|
||||
<Form.Element label="Offset">
|
||||
<Input
|
||||
name="offset"
|
||||
onChange={handleChange}
|
||||
titleText="Offset check interval"
|
||||
value={check.offset}
|
||||
/>
|
||||
</Form.Element>
|
||||
)}
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
{check.cron != null && (
|
||||
<Form.Element label="Cron">
|
||||
<Input
|
||||
autoFocus={false}
|
||||
maxLength={24}
|
||||
name="Cron"
|
||||
onChange={handleChangeName}
|
||||
name="cron"
|
||||
onChange={handleChange}
|
||||
placeholder="cron"
|
||||
size={ComponentSize.Small}
|
||||
spellCheck={false}
|
||||
|
@ -250,6 +215,21 @@ const CheckMetaCard: FC<Props> = ({
|
|||
/>
|
||||
</Form.Element>
|
||||
)}
|
||||
{check.tags &&
|
||||
check.tags.map((t, i) => (
|
||||
<CheckTagRow
|
||||
key={i}
|
||||
index={i}
|
||||
tagSet={t}
|
||||
handleChangeTagRow={handleChangeTagRow}
|
||||
/>
|
||||
))}
|
||||
<DashedButton
|
||||
text="+ Tags"
|
||||
onClick={addTagsRow}
|
||||
color={ComponentColor.Primary}
|
||||
size={ComponentSize.Small}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Libraries
|
||||
import React, {FC} from 'react'
|
||||
|
||||
// Components
|
||||
import {Grid, Input, Form} from '@influxdata/clockface'
|
||||
|
||||
// Types
|
||||
import {CheckTagSet} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
index: number
|
||||
tagSet: CheckTagSet
|
||||
handleChangeTagRow: (i: number, tags: CheckTagSet) => void
|
||||
}
|
||||
|
||||
const CheckTagRow: FC<Props> = ({tagSet, handleChangeTagRow, index}) => {
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
handleChangeTagRow(index, {...tagSet, [e.target.name]: e.target.value})
|
||||
}
|
||||
return (
|
||||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthSM={6}>
|
||||
<Form.Element label="Tag Key">
|
||||
<Input
|
||||
name="key"
|
||||
onChange={handleChange}
|
||||
titleText="Name of the check"
|
||||
value={tagSet.key}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthSM={6}>
|
||||
<Form.Element label="Tag Value">
|
||||
<Input
|
||||
name="value"
|
||||
onChange={handleChange}
|
||||
titleText="Offset check interval"
|
||||
value={tagSet.value}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
export default CheckTagRow
|
|
@ -19,9 +19,11 @@ interface Props {
|
|||
|
||||
const ThresholdConditions: FC<Props> = ({check}) => {
|
||||
const thresholds = {}
|
||||
check.thresholds.forEach(t => {
|
||||
thresholds[t.level] = t
|
||||
})
|
||||
if (check.thresholds) {
|
||||
check.thresholds.forEach(t => {
|
||||
thresholds[t.level] = t
|
||||
})
|
||||
}
|
||||
return (
|
||||
<FlexBox
|
||||
direction={FlexDirection.Column}
|
||||
|
|
|
@ -913,13 +913,17 @@ export const timeMachineReducer = (
|
|||
return produce(state, draftState => {
|
||||
const check = draftState.alerting.check
|
||||
if (check.type === 'threshold') {
|
||||
const filteredThresholds = check.thresholds.filter(
|
||||
const thresholds = check.thresholds || []
|
||||
const filteredThresholds = thresholds.filter(
|
||||
t => t.level !== action.payload.threshold.level
|
||||
)
|
||||
const thresholds = [...filteredThresholds, action.payload.threshold]
|
||||
const updatedThresholds = [
|
||||
...filteredThresholds,
|
||||
action.payload.threshold,
|
||||
]
|
||||
draftState.alerting.check = {
|
||||
...check,
|
||||
thresholds,
|
||||
thresholds: updatedThresholds,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -74,4 +74,6 @@ import {Check, Threshold} from '../client'
|
|||
export type CheckType = Check['type']
|
||||
export type ThresholdType = Threshold['type']
|
||||
|
||||
export type CheckTagSet = Check['tags'][0]
|
||||
|
||||
export type AlertHistoryType = 'statuses' | 'notifications'
|
||||
|
|
Loading…
Reference in New Issue