parent
9d6d1d1418
commit
626286863a
|
@ -19,8 +19,10 @@ import {
|
|||
import {
|
||||
Action as TimeMachineAction,
|
||||
setActiveTimeMachine,
|
||||
updateTimeMachineCheck,
|
||||
setCheckStatus,
|
||||
} from 'src/timeMachine/actions'
|
||||
import {setCheckStatus} from 'src/timeMachine/actions'
|
||||
import {executeQueries} from 'src/timeMachine/actions/queries'
|
||||
|
||||
// Types
|
||||
import {
|
||||
|
@ -246,3 +248,8 @@ export const cloneCheck = (check: Check) => async (
|
|||
dispatch(notify(copy.createCheckFailed(error.message)))
|
||||
}
|
||||
}
|
||||
|
||||
export const selectCheckEvery = (every: string) => async dispatch => {
|
||||
dispatch(updateTimeMachineCheck({every}))
|
||||
dispatch(executeQueries())
|
||||
}
|
||||
|
|
|
@ -36,12 +36,9 @@ const CheckEOHeader: FC<Props> = ({name, onSetName, onCancel, onSave}) => {
|
|||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setSaveStatus(RemoteDataState.Loading)
|
||||
await onSave()
|
||||
} catch {
|
||||
setSaveStatus(RemoteDataState.NotStarted)
|
||||
}
|
||||
setSaveStatus(RemoteDataState.Loading)
|
||||
await onSave()
|
||||
setSaveStatus(RemoteDataState.NotStarted)
|
||||
}
|
||||
|
||||
const handleClickOutsideTitle = (e: MouseEvent<HTMLElement>) => {
|
||||
|
@ -82,7 +79,7 @@ const CheckEOHeader: FC<Props> = ({name, onSetName, onCancel, onSave}) => {
|
|||
color={ComponentColor.Success}
|
||||
size={ComponentSize.Small}
|
||||
status={saveButtonStatus}
|
||||
onClick={onSave}
|
||||
onClick={handleSave}
|
||||
testID="save-cell--button"
|
||||
/>
|
||||
</Page.Header.Right>
|
||||
|
|
|
@ -31,4 +31,8 @@
|
|||
|
||||
.alert-builder--check-type-selector {
|
||||
margin: $ix-marg-c;
|
||||
}
|
||||
}
|
||||
|
||||
.alert-builder--tag-row {
|
||||
margin-bottom: $ix-marg-b;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ const AlertBuilder: FC = () => {
|
|||
className="alert-builder--card"
|
||||
>
|
||||
<BuilderCard.Header title="Conditions" />
|
||||
<BuilderCard.Body addPadding={true}>
|
||||
<BuilderCard.Body addPadding={true} autoHideScrollbars={true}>
|
||||
<CheckConditionsCard />
|
||||
</BuilderCard.Body>
|
||||
</BuilderCard>
|
||||
|
@ -40,7 +40,7 @@ const AlertBuilder: FC = () => {
|
|||
className="alert-builder--card"
|
||||
>
|
||||
<BuilderCard.Header title="Matching Notification Rules" />
|
||||
<BuilderCard.Body addPadding={true}>
|
||||
<BuilderCard.Body addPadding={true} autoHideScrollbars={true}>
|
||||
<CheckMatchingRulesCard />
|
||||
</BuilderCard.Body>
|
||||
</BuilderCard>
|
||||
|
|
|
@ -11,21 +11,26 @@ import {
|
|||
Wrap,
|
||||
ComponentColor,
|
||||
Grid,
|
||||
InfluxColors,
|
||||
} 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'
|
||||
import DurationSelector from 'src/timeMachine/components/DurationSelector'
|
||||
|
||||
// Actions & Selectors
|
||||
import {updateTimeMachineCheck} from 'src/timeMachine/actions'
|
||||
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
import {selectCheckEvery} from 'src/alerting/actions/checks'
|
||||
|
||||
// Constants
|
||||
import {CHECK_EVERY_OPTIONS, CHECK_OFFSET_OPTIONS} from 'src/alerting/constants'
|
||||
|
||||
// Types
|
||||
import {Check, AppState, CheckTagSet} from 'src/types'
|
||||
|
||||
interface DispatchProps {
|
||||
updateTimeMachineCheck: typeof updateTimeMachineCheck
|
||||
onUpdateTimeMachineCheck: typeof updateTimeMachineCheck
|
||||
onSelectCheckEvery: typeof selectCheckEvery
|
||||
}
|
||||
|
||||
interface StateProps {
|
||||
|
@ -34,28 +39,32 @@ interface StateProps {
|
|||
|
||||
type Props = DispatchProps & StateProps
|
||||
|
||||
const CheckMetaCard: FC<Props> = ({updateTimeMachineCheck, check}) => {
|
||||
const CheckMetaCard: FC<Props> = ({
|
||||
check,
|
||||
onUpdateTimeMachineCheck,
|
||||
onSelectCheckEvery,
|
||||
}) => {
|
||||
const handleChange = (
|
||||
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
) => {
|
||||
updateTimeMachineCheck({[e.target.name]: e.target.value})
|
||||
onUpdateTimeMachineCheck({[e.target.name]: e.target.value})
|
||||
}
|
||||
|
||||
const addTagsRow = () => {
|
||||
const tags = check.tags || []
|
||||
updateTimeMachineCheck({tags: [...tags, {key: '', value: ''}]})
|
||||
onUpdateTimeMachineCheck({tags: [...tags, {key: '', value: ''}]})
|
||||
}
|
||||
|
||||
const handleChangeTagRow = (index: number, tagSet: CheckTagSet) => {
|
||||
const tags = [...check.tags]
|
||||
tags[index] = tagSet
|
||||
updateTimeMachineCheck({tags})
|
||||
onUpdateTimeMachineCheck({tags})
|
||||
}
|
||||
|
||||
const handleRemoveTagRow = (index: number) => {
|
||||
let tags = [...check.tags]
|
||||
tags = tags.filter((_, i) => i !== index)
|
||||
updateTimeMachineCheck({tags})
|
||||
onUpdateTimeMachineCheck({tags})
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -94,29 +103,26 @@ const CheckMetaCard: FC<Props> = ({updateTimeMachineCheck, check}) => {
|
|||
<Grid>
|
||||
<Grid.Row>
|
||||
<Grid.Column widthSM={6}>
|
||||
<Form.Element label="Schedule every">
|
||||
<Input
|
||||
name="every"
|
||||
onChange={handleChange}
|
||||
titleText="Check run interval"
|
||||
value={check.every}
|
||||
<Form.Element label="Schedule Every">
|
||||
<DurationSelector
|
||||
selectedDuration={check.every}
|
||||
durations={CHECK_EVERY_OPTIONS}
|
||||
onSelectDuration={onSelectCheckEvery}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
<Grid.Column widthSM={6}>
|
||||
<Form.Element label="Offset">
|
||||
<Input
|
||||
name="offset"
|
||||
onChange={handleChange}
|
||||
titleText="Check offset interval"
|
||||
value={check.offset}
|
||||
<DurationSelector
|
||||
selectedDuration={check.offset}
|
||||
durations={CHECK_OFFSET_OPTIONS}
|
||||
onSelectDuration={offset => onUpdateTimeMachineCheck({offset})}
|
||||
/>
|
||||
</Form.Element>
|
||||
</Grid.Column>
|
||||
</Grid.Row>
|
||||
</Grid>
|
||||
<Form.Label label="Tags :" />
|
||||
<Form.Divider lineColor={InfluxColors.Smoke} />
|
||||
<Form.Label label="Tags" />
|
||||
{check.tags &&
|
||||
check.tags.map((t, i) => (
|
||||
<CheckTagRow
|
||||
|
@ -128,7 +134,7 @@ const CheckMetaCard: FC<Props> = ({updateTimeMachineCheck, check}) => {
|
|||
/>
|
||||
))}
|
||||
<DashedButton
|
||||
text="+ Tags"
|
||||
text="+ Tag"
|
||||
onClick={addTagsRow}
|
||||
color={ComponentColor.Primary}
|
||||
size={ComponentSize.Small}
|
||||
|
@ -146,7 +152,8 @@ const mstp = (state: AppState): StateProps => {
|
|||
}
|
||||
|
||||
const mdtp: DispatchProps = {
|
||||
updateTimeMachineCheck: updateTimeMachineCheck,
|
||||
onUpdateTimeMachineCheck: updateTimeMachineCheck,
|
||||
onSelectCheckEvery: selectCheckEvery,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps, {}>(
|
||||
|
|
|
@ -38,7 +38,11 @@ const CheckTagRow: FC<Props> = ({
|
|||
}
|
||||
|
||||
return (
|
||||
<Panel testID="tag-rule" size={ComponentSize.ExtraSmall}>
|
||||
<Panel
|
||||
testID="tag-rule"
|
||||
size={ComponentSize.ExtraSmall}
|
||||
className="alert-builder--tag-row"
|
||||
>
|
||||
<DismissButton onClick={handleRemove} color={ComponentColor.Default} />
|
||||
<Panel.Body>
|
||||
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Small}>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {DURATIONS} from 'src/timeMachine/constants/queryBuilder'
|
||||
|
||||
import {
|
||||
Check,
|
||||
DashboardQuery,
|
||||
|
@ -12,12 +14,29 @@ export const DEFAULT_CHECK_NAME = 'Name this check'
|
|||
export const DEFAULT_NOTIFICATION_RULE_NAME = 'Name this notification rule'
|
||||
|
||||
export const CHECK_NAME_MAX_LENGTH = 68
|
||||
export const DEFAULT_CHECK_CRON = '1h'
|
||||
export const DEFAULT_CHECK_EVERY = '1h'
|
||||
export const DEFAULT_CHECK_EVERY = '5m'
|
||||
export const DEFAULT_CHECK_OFFSET = '0s'
|
||||
export const DEFAULT_CHECK_REPORT_ZERO = false
|
||||
export const DEFAULT_DEADMAN_LEVEL: CheckStatusLevel = 'CRIT'
|
||||
|
||||
export const CHECK_EVERY_OPTIONS = DURATIONS
|
||||
|
||||
export const CHECK_OFFSET_OPTIONS = [
|
||||
{duration: '0s', displayText: 'None'},
|
||||
{duration: '5s', displayText: '5 seconds'},
|
||||
{duration: '15s', displayText: '15 seconds'},
|
||||
{duration: '1m', displayText: '1 minute'},
|
||||
{duration: '5m', displayText: '5 minutes'},
|
||||
{duration: '15m', displayText: '15 minutes'},
|
||||
{duration: '1h', displayText: '1 hour'},
|
||||
{duration: '6h', displayText: '6 hours'},
|
||||
{duration: '12h', displayText: '12 hours'},
|
||||
{duration: '24h', displayText: '24 hours'},
|
||||
{duration: '2d', displayText: '2 days'},
|
||||
{duration: '7d', displayText: '7 days'},
|
||||
{duration: '30d', displayText: '30 days'},
|
||||
]
|
||||
|
||||
export const LEVEL_COLORS = {
|
||||
OK: '#32B08C',
|
||||
INFO: '#4591ED',
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import {getCheckVisTimeRange} from 'src/alerting/utils/vis'
|
||||
|
||||
const TESTS = [
|
||||
['5s', {lower: 'now() - 1500s'}],
|
||||
['1m', {lower: 'now() - 300m'}],
|
||||
['1m5s', {lower: 'now() - 300m1500s'}],
|
||||
]
|
||||
|
||||
test.each(TESTS)('getCheckVisTimeRange(%s)', (input, expected) => {
|
||||
expect(getCheckVisTimeRange(input)).toEqual(expected)
|
||||
})
|
|
@ -0,0 +1,26 @@
|
|||
// Utils
|
||||
import {parseDuration} from 'src/variables/utils/parseDuration'
|
||||
|
||||
// Types
|
||||
import {TimeRange} from 'src/types'
|
||||
|
||||
const POINTS_PER_CHECK_PLOT = 300
|
||||
|
||||
/*
|
||||
Given the duration in a check's `every` field, return a `TimeRange` suitable
|
||||
for visualizing the input data to the check.
|
||||
|
||||
For example, suppose a check has an `every` value of `1m`. Then the check is
|
||||
run once per minute, and the input data to the `check` for each run is a
|
||||
single value aggregated from the last `1m`. To display a visualization of the
|
||||
check data over time, we want to show a series of the values aggregated for
|
||||
each minute. So to display a plot with say, 300 points, we need to query a
|
||||
time range of the last 300 minutes.
|
||||
*/
|
||||
export const getCheckVisTimeRange = (durationStr: string): TimeRange => {
|
||||
const durationMultiple = parseDuration(durationStr)
|
||||
.map(({magnitude, unit}) => `${magnitude * POINTS_PER_CHECK_PLOT}${unit}`)
|
||||
.join('')
|
||||
|
||||
return {lower: `now() - ${durationMultiple}`}
|
||||
}
|
|
@ -66,7 +66,7 @@ const CheckPlot: FunctionComponent<Props> = ({
|
|||
}
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings(
|
||||
[0, 100],
|
||||
null,
|
||||
table.getColumn(Y_COLUMN, 'number')
|
||||
)
|
||||
|
||||
|
@ -95,12 +95,14 @@ const CheckPlot: FunctionComponent<Props> = ({
|
|||
table
|
||||
)
|
||||
|
||||
const yTicks = flatMap(thresholds, (t: any) => [
|
||||
const thresholdValues = flatMap(thresholds, (t: any) => [
|
||||
t.value,
|
||||
t.minValue,
|
||||
t.maxValue,
|
||||
]).filter(t => t !== undefined)
|
||||
|
||||
const yTicks = thresholdValues.length ? thresholdValues : null
|
||||
|
||||
const config: Config = {
|
||||
...VIS_THEME,
|
||||
table,
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
DEFAULT_GAUGE_COLORS,
|
||||
DEFAULT_THRESHOLDS_LIST_COLORS,
|
||||
} from 'src/shared/constants/thresholds'
|
||||
import {DEFAULT_CHECK_EVERY} from 'src/alerting/constants'
|
||||
|
||||
// Types
|
||||
import {
|
||||
|
@ -251,7 +252,19 @@ const NEW_VIEW_CREATORS = {
|
|||
type: 'check',
|
||||
shape: 'chronograf-v2',
|
||||
checkID: '',
|
||||
queries: [defaultViewQuery()],
|
||||
queries: [
|
||||
{
|
||||
name: '',
|
||||
text: '',
|
||||
editMode: 'builder',
|
||||
builderConfig: {
|
||||
buckets: [],
|
||||
tags: [{key: '_measurement', values: []}],
|
||||
functions: [{name: 'mean'}],
|
||||
aggregateWindow: {period: DEFAULT_CHECK_EVERY},
|
||||
},
|
||||
},
|
||||
],
|
||||
colors: NINETEEN_EIGHTY_FOUR,
|
||||
},
|
||||
}),
|
||||
|
|
|
@ -100,7 +100,6 @@
|
|||
@import 'src/timeMachine/components/view_options/ViewOptions.scss';
|
||||
@import 'src/timeMachine/components/view_options/ViewTypeDropdown.scss';
|
||||
@import 'src/timeMachine/components/builderCard/BuilderCard.scss';
|
||||
@import 'src/timeMachine/components/WindowSelector.scss';
|
||||
@import 'src/dataLoaders/components/side_bar/SideBar.scss';
|
||||
@import 'src/dataLoaders/components/DataLoadersOverlay.scss';
|
||||
@import 'src/shared/components/EmptyGraphError.scss';
|
||||
|
|
|
@ -13,7 +13,7 @@ import {notify} from 'src/shared/actions/notifications'
|
|||
import {rateLimitReached, resultTooLarge} from 'src/shared/copy/notifications'
|
||||
|
||||
// Utils
|
||||
import {getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
import {getActiveTimeMachine, getTimeRange} from 'src/timeMachine/selectors'
|
||||
import {getVariableAssignments} from 'src/variables/selectors'
|
||||
import {getTimeRangeVars} from 'src/variables/utils/getTimeRangeVars'
|
||||
import {filterUnusedVars} from 'src/shared/utils/filterUnusedVars'
|
||||
|
@ -88,7 +88,8 @@ export const refreshTimeMachineVariableValues = () => async (
|
|||
let pendingResults: Array<CancelBox<RunQueryResult>> = []
|
||||
|
||||
export const executeQueries = () => async (dispatch, getState: GetState) => {
|
||||
const {view, timeRange} = getActiveTimeMachine(getState())
|
||||
const {view} = getActiveTimeMachine(getState())
|
||||
const timeRange = getTimeRange(getState())
|
||||
const queries = view.properties.queries.filter(({text}) => !!text.trim())
|
||||
|
||||
if (!queries.length) {
|
||||
|
|
|
@ -2,7 +2,11 @@
|
|||
import {queryBuilderFetcher} from 'src/timeMachine/apis/QueryBuilderFetcher'
|
||||
|
||||
// Utils
|
||||
import {getActiveQuery, getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
import {
|
||||
getActiveQuery,
|
||||
getActiveTimeMachine,
|
||||
getTimeRange,
|
||||
} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {Dispatch} from 'redux-thunk'
|
||||
|
@ -282,7 +286,7 @@ export const loadTagSelector = (index: number) => async (
|
|||
dispatch(setBuilderTagKeysStatus(index, RemoteDataState.Loading))
|
||||
|
||||
try {
|
||||
const timeRange = getActiveTimeMachine(getState()).timeRange
|
||||
const timeRange = getTimeRange(getState())
|
||||
const searchTerm = getActiveTimeMachine(getState()).queryBuilder.tags[index]
|
||||
.keysSearchTerm
|
||||
|
||||
|
@ -338,7 +342,7 @@ const loadTagSelectorValues = (index: number) => async (
|
|||
dispatch(setBuilderTagValuesStatus(index, RemoteDataState.Loading))
|
||||
|
||||
try {
|
||||
const timeRange = getActiveTimeMachine(getState()).timeRange
|
||||
const timeRange = getTimeRange(getState())
|
||||
const key = getActiveQuery(getState()).builderConfig.tags[index].key
|
||||
const searchTerm = getActiveTimeMachine(getState()).queryBuilder.tags[index]
|
||||
.valuesSearchTerm
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import {Dropdown, ComponentStatus} from '@influxdata/clockface'
|
||||
|
||||
interface Props {
|
||||
selectedDuration: string
|
||||
onSelectDuration: (duration: string) => any
|
||||
durations: Array<{duration: string; displayText: string}>
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const DurationSelector: FunctionComponent<Props> = ({
|
||||
selectedDuration,
|
||||
onSelectDuration,
|
||||
durations,
|
||||
disabled = false,
|
||||
}) => {
|
||||
let resolvedDurations = durations
|
||||
let selected = durations.find(d => d.duration === selectedDuration)
|
||||
|
||||
if (!selected) {
|
||||
selected = {duration: selectedDuration, displayText: selectedDuration}
|
||||
resolvedDurations = [selected, ...resolvedDurations]
|
||||
}
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
testID="duration-selector"
|
||||
button={(active, onClick) => (
|
||||
<Dropdown.Button
|
||||
testID="duration-selector--button"
|
||||
active={active}
|
||||
onClick={onClick}
|
||||
status={getStatus(disabled)}
|
||||
>
|
||||
{selected.displayText}
|
||||
</Dropdown.Button>
|
||||
)}
|
||||
menu={onCollapse => (
|
||||
<Dropdown.Menu onCollapse={onCollapse} testID="duration-selector--menu">
|
||||
{resolvedDurations.map(({duration, displayText}) => (
|
||||
<Dropdown.Item
|
||||
id={duration}
|
||||
key={duration}
|
||||
value={duration}
|
||||
testID={`duration-selector--${duration}`}
|
||||
selected={duration === selectedDuration}
|
||||
onClick={onSelectDuration}
|
||||
>
|
||||
{displayText}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const getStatus = (disabled: boolean): ComponentStatus => {
|
||||
if (disabled) {
|
||||
return ComponentStatus.Disabled
|
||||
}
|
||||
|
||||
return ComponentStatus.Default
|
||||
}
|
||||
|
||||
export default DurationSelector
|
|
@ -6,7 +6,7 @@ import {connect} from 'react-redux'
|
|||
import {Input} from '@influxdata/clockface'
|
||||
import SelectorList from 'src/timeMachine/components/SelectorList'
|
||||
import BuilderCard from 'src/timeMachine/components/builderCard/BuilderCard'
|
||||
import WindowSelector from 'src/timeMachine/components/WindowSelector'
|
||||
import DurationSelector from 'src/timeMachine/components/DurationSelector'
|
||||
|
||||
// Actions
|
||||
import {
|
||||
|
@ -15,12 +15,14 @@ import {
|
|||
} from 'src/timeMachine/actions/queryBuilder'
|
||||
|
||||
// Utils
|
||||
import {getActiveQuery} from 'src/timeMachine/selectors'
|
||||
import {getActiveQuery, getIsInCheckOverlay} from 'src/timeMachine/selectors'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
FUNCTIONS,
|
||||
AGG_WINDOW_AUTO,
|
||||
DURATIONS,
|
||||
AUTO_NONE_DURATIONS,
|
||||
} from 'src/timeMachine/constants/queryBuilder'
|
||||
|
||||
// Types
|
||||
|
@ -31,6 +33,7 @@ const FUNCTION_NAMES = FUNCTIONS.map(f => f.name)
|
|||
interface StateProps {
|
||||
aggregateWindow: BuilderConfig['aggregateWindow']
|
||||
selectedFunctions: BuilderConfig['functions']
|
||||
isInCheckOverlay: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
|
@ -49,9 +52,9 @@ class FunctionSelector extends PureComponent<Props, State> {
|
|||
|
||||
public render() {
|
||||
const {
|
||||
onSelectFunction,
|
||||
selectedFunctions,
|
||||
onSelectAggregateWindow,
|
||||
isInCheckOverlay,
|
||||
} = this.props
|
||||
|
||||
const {searchTerm} = this.state
|
||||
|
@ -60,9 +63,10 @@ class FunctionSelector extends PureComponent<Props, State> {
|
|||
<BuilderCard className="function-selector" testID="function-selector">
|
||||
<BuilderCard.Header title="Aggregate Functions" />
|
||||
<BuilderCard.Menu>
|
||||
<WindowSelector
|
||||
onSelect={onSelectAggregateWindow}
|
||||
period={this.period}
|
||||
<DurationSelector
|
||||
onSelectDuration={onSelectAggregateWindow}
|
||||
selectedDuration={this.duration}
|
||||
durations={this.durations}
|
||||
disabled={!selectedFunctions.length}
|
||||
/>
|
||||
<Input
|
||||
|
@ -75,18 +79,25 @@ class FunctionSelector extends PureComponent<Props, State> {
|
|||
<SelectorList
|
||||
items={this.functions}
|
||||
selectedItems={this.selectedFunctions}
|
||||
onSelectItem={onSelectFunction}
|
||||
multiSelect={true}
|
||||
onSelectItem={this.handleSelectFunction}
|
||||
multiSelect={!isInCheckOverlay}
|
||||
/>
|
||||
</BuilderCard>
|
||||
)
|
||||
}
|
||||
|
||||
private get period(): string {
|
||||
private get duration(): string {
|
||||
const {aggregateWindow} = this.props
|
||||
|
||||
return aggregateWindow.period || AGG_WINDOW_AUTO
|
||||
}
|
||||
|
||||
private get durations(): Array<{duration: string; displayText: string}> {
|
||||
return this.props.isInCheckOverlay
|
||||
? DURATIONS
|
||||
: [...DURATIONS, ...AUTO_NONE_DURATIONS]
|
||||
}
|
||||
|
||||
private get functions(): string[] {
|
||||
return FUNCTION_NAMES.filter(f => f.includes(this.state.searchTerm))
|
||||
}
|
||||
|
@ -98,6 +109,17 @@ class FunctionSelector extends PureComponent<Props, State> {
|
|||
private handleSetSearchTerm = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({searchTerm: e.target.value})
|
||||
}
|
||||
|
||||
private handleSelectFunction = (functionName: string) => {
|
||||
const {isInCheckOverlay, selectedFunctions, onSelectFunction} = this.props
|
||||
|
||||
if (isInCheckOverlay && selectedFunctions[0].name === functionName) {
|
||||
// Disallow empty aggreegate selections in check overlay
|
||||
return
|
||||
}
|
||||
|
||||
onSelectFunction(functionName)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
|
@ -105,7 +127,9 @@ const mstp = (state: AppState) => {
|
|||
state
|
||||
).builderConfig
|
||||
|
||||
return {selectedFunctions, aggregateWindow}
|
||||
const isInCheckOverlay = getIsInCheckOverlay(state)
|
||||
|
||||
return {selectedFunctions, aggregateWindow, isInCheckOverlay}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
|
|
|
@ -15,6 +15,14 @@
|
|||
background: $g2-kevlar;
|
||||
padding: 8px 10px 0 10px;
|
||||
width: 100%;
|
||||
|
||||
.view-raw-data-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 115px;
|
||||
margin-right: $ix-marg-b;
|
||||
}
|
||||
}
|
||||
|
||||
.time-machine-queries--tabs {
|
||||
|
|
|
@ -10,26 +10,27 @@ import TimeMachineRefreshDropdown from 'src/timeMachine/components/RefreshDropdo
|
|||
import TimeRangeDropdown, {
|
||||
RangeType,
|
||||
} from 'src/shared/components/TimeRangeDropdown'
|
||||
import TimeMachineQueryTab from 'src/timeMachine/components/QueryTab'
|
||||
import TimeMachineQueryBuilder from 'src/timeMachine/components/QueryBuilder'
|
||||
import SubmitQueryButton from 'src/timeMachine/components/SubmitQueryButton'
|
||||
import RawDataToggle from 'src/timeMachine/components/RawDataToggle'
|
||||
import QueryTabs from 'src/timeMachine/components/QueryTabs'
|
||||
import {
|
||||
SquareButton,
|
||||
IconFont,
|
||||
ComponentSize,
|
||||
ComponentColor,
|
||||
FlexBox,
|
||||
FlexDirection,
|
||||
JustifyContent,
|
||||
} from '@influxdata/clockface'
|
||||
|
||||
// Actions
|
||||
import {addQuery, setAutoRefresh} from 'src/timeMachine/actions'
|
||||
import {setAutoRefresh} from 'src/timeMachine/actions'
|
||||
import {setTimeRange} from 'src/timeMachine/actions'
|
||||
|
||||
// Utils
|
||||
import {getActiveTimeMachine, getActiveQuery} from 'src/timeMachine/selectors'
|
||||
import {
|
||||
getActiveTimeMachine,
|
||||
getIsInCheckOverlay,
|
||||
getActiveQuery,
|
||||
} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {
|
||||
|
@ -39,18 +40,15 @@ import {
|
|||
AutoRefresh,
|
||||
AutoRefreshStatus,
|
||||
} from 'src/types'
|
||||
import {DashboardDraftQuery} from 'src/types/dashboards'
|
||||
|
||||
interface StateProps {
|
||||
activeQuery: DashboardQuery
|
||||
draftQueries: DashboardDraftQuery[]
|
||||
timeRange: TimeRange
|
||||
autoRefresh: AutoRefresh
|
||||
activeTimeMachineID: string
|
||||
isInCheckOverlay: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onAddQuery: typeof addQuery
|
||||
onSetTimeRange: typeof setTimeRange
|
||||
onSetAutoRefresh: typeof setAutoRefresh
|
||||
}
|
||||
|
@ -59,34 +57,12 @@ type Props = StateProps & DispatchProps
|
|||
|
||||
class TimeMachineQueries extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {
|
||||
draftQueries,
|
||||
onAddQuery,
|
||||
timeRange,
|
||||
activeTimeMachineID,
|
||||
} = this.props
|
||||
const {timeRange, isInCheckOverlay} = this.props
|
||||
|
||||
return (
|
||||
<div className="time-machine-queries">
|
||||
<div className="time-machine-queries--controls">
|
||||
<div className="time-machine-queries--tabs">
|
||||
{draftQueries.map((query, queryIndex) => (
|
||||
<TimeMachineQueryTab
|
||||
key={queryIndex}
|
||||
queryIndex={queryIndex}
|
||||
query={query}
|
||||
/>
|
||||
))}
|
||||
{activeTimeMachineID !== 'alerting' && (
|
||||
<SquareButton
|
||||
className="time-machine-queries--new"
|
||||
icon={IconFont.PlusSkinny}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Default}
|
||||
onClick={onAddQuery}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<QueryTabs />
|
||||
<div className="time-machine-queries--buttons">
|
||||
<FlexBox
|
||||
direction={FlexDirection.Row}
|
||||
|
@ -94,15 +70,17 @@ class TimeMachineQueries extends PureComponent<Props> {
|
|||
margin={ComponentSize.Small}
|
||||
>
|
||||
<RawDataToggle />
|
||||
{activeTimeMachineID !== 'alerting' && <CSVExportButton />}
|
||||
<TimeMachineRefreshDropdown />
|
||||
<TimeRangeDropdown
|
||||
timeRange={timeRange}
|
||||
onSetTimeRange={this.handleSetTimeRange}
|
||||
centerPicker={true}
|
||||
/>
|
||||
{activeTimeMachineID !== 'alerting' && (
|
||||
<TimeMachineQueriesSwitcher />
|
||||
{!isInCheckOverlay && (
|
||||
<>
|
||||
<CSVExportButton />
|
||||
<TimeMachineRefreshDropdown />
|
||||
<TimeRangeDropdown
|
||||
timeRange={timeRange}
|
||||
onSetTimeRange={this.handleSetTimeRange}
|
||||
centerPicker={true}
|
||||
/>
|
||||
<TimeMachineQueriesSwitcher />
|
||||
</>
|
||||
)}
|
||||
<SubmitQueryButton />
|
||||
</FlexBox>
|
||||
|
@ -150,25 +128,19 @@ class TimeMachineQueries extends PureComponent<Props> {
|
|||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {
|
||||
timeMachines: {activeTimeMachineID},
|
||||
} = state
|
||||
|
||||
const {draftQueries, timeRange, autoRefresh} = getActiveTimeMachine(state)
|
||||
const {timeRange, autoRefresh} = getActiveTimeMachine(state)
|
||||
|
||||
const activeQuery = getActiveQuery(state)
|
||||
|
||||
return {
|
||||
timeRange,
|
||||
activeQuery,
|
||||
draftQueries,
|
||||
autoRefresh,
|
||||
activeTimeMachineID,
|
||||
isInCheckOverlay: getIsInCheckOverlay(state),
|
||||
}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onAddQuery: addQuery,
|
||||
onSetTimeRange: setTimeRange,
|
||||
onSetAutoRefresh: setAutoRefresh,
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react'
|
|||
|
||||
import {renderWithRedux} from 'src/mockState'
|
||||
import {waitForElement, fireEvent} from 'react-testing-library'
|
||||
import {windows} from 'src/timeMachine/components/WindowSelector'
|
||||
|
||||
import QueryBuilder from 'src/timeMachine/components/QueryBuilder'
|
||||
|
||||
|
@ -80,20 +79,20 @@ describe('QueryBuilder', () => {
|
|||
const mean = getByTestId('selector-list mean')
|
||||
fireEvent.click(mean)
|
||||
|
||||
let windowSelectorButton = getByTestId('window-selector--button')
|
||||
let windowSelectorButton = getByTestId('duration-selector--button')
|
||||
|
||||
fireEvent.click(windowSelectorButton)
|
||||
|
||||
const windowSelector = getByTestId('window-selector--menu')
|
||||
const windowSelector = getByTestId('duration-selector--menu')
|
||||
|
||||
expect(windowSelector.childElementCount).toBe(windows.length)
|
||||
expect(windowSelector.childElementCount).toBe(14)
|
||||
|
||||
const fiveMins = getByTestId('window-selector--5m')
|
||||
const fiveMins = getByTestId('duration-selector--5m')
|
||||
|
||||
fireEvent.click(fiveMins)
|
||||
|
||||
windowSelectorButton = getByTestId('window-selector--button')
|
||||
windowSelectorButton = getByTestId('duration-selector--button')
|
||||
|
||||
expect(windowSelectorButton.textContent).toContain('5m')
|
||||
expect(windowSelectorButton.textContent).toContain('5 minutes')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// Libraries
|
||||
import React, {FC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Components
|
||||
import TimeMachineQueryTab from 'src/timeMachine/components/QueryTab'
|
||||
import {
|
||||
SquareButton,
|
||||
IconFont,
|
||||
ComponentSize,
|
||||
ComponentColor,
|
||||
} from '@influxdata/clockface'
|
||||
|
||||
// Actions
|
||||
import {addQuery} from 'src/timeMachine/actions'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
getActiveTimeMachine,
|
||||
getIsInCheckOverlay,
|
||||
} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {AppState, DashboardDraftQuery} from 'src/types'
|
||||
|
||||
interface StateProps {
|
||||
draftQueries: DashboardDraftQuery[]
|
||||
isInCheckOverlay: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
onAddQuery: () => any
|
||||
}
|
||||
|
||||
type Props = StateProps & DispatchProps
|
||||
|
||||
const QueryTabs: FC<Props> = ({draftQueries, isInCheckOverlay, onAddQuery}) => {
|
||||
return (
|
||||
<div className="time-machine-queries--tabs">
|
||||
{draftQueries.map((query, queryIndex) => (
|
||||
<TimeMachineQueryTab
|
||||
key={queryIndex}
|
||||
queryIndex={queryIndex}
|
||||
query={query}
|
||||
/>
|
||||
))}
|
||||
{!isInCheckOverlay && (
|
||||
<SquareButton
|
||||
className="time-machine-queries--new"
|
||||
icon={IconFont.PlusSkinny}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
color={ComponentColor.Default}
|
||||
onClick={onAddQuery}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mstp = (state: AppState): StateProps => {
|
||||
const {draftQueries} = getActiveTimeMachine(state)
|
||||
const isInCheckOverlay = getIsInCheckOverlay(state)
|
||||
|
||||
return {draftQueries, isInCheckOverlay}
|
||||
}
|
||||
|
||||
const mdtp = {
|
||||
onAddQuery: addQuery,
|
||||
}
|
||||
|
||||
export default connect<StateProps, DispatchProps>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(QueryTabs)
|
|
@ -29,14 +29,14 @@ class TimeMachineQueries extends PureComponent<Props> {
|
|||
const {isViewingRawData} = this.props
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="view-raw-data-toggle">
|
||||
<SlideToggle.Label text="View Raw Data" />
|
||||
<SlideToggle
|
||||
active={isViewingRawData}
|
||||
onChange={this.handleToggleIsViewingRawData}
|
||||
size={ComponentSize.ExtraSmall}
|
||||
/>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ const SelectorList: SFC<Props> = props => {
|
|||
const {items, selectedItems, onSelectItem, multiSelect} = props
|
||||
|
||||
return (
|
||||
<BuilderCard.Body addPadding={false}>
|
||||
<BuilderCard.Body addPadding={false} autoHideScrollbars={true}>
|
||||
{items.map(item => {
|
||||
const className = classnames('selector-list--item', {
|
||||
selected: selectedItems.includes(item),
|
||||
|
|
|
@ -32,7 +32,11 @@ import {
|
|||
// Utils
|
||||
import {toComponentStatus} from 'src/shared/utils/toComponentStatus'
|
||||
import DefaultDebouncer from 'src/shared/utils/debouncer'
|
||||
import {getActiveQuery, getActiveTimeMachine} from 'src/timeMachine/selectors'
|
||||
import {
|
||||
getActiveQuery,
|
||||
getActiveTimeMachine,
|
||||
getIsInCheckOverlay,
|
||||
} from 'src/timeMachine/selectors'
|
||||
|
||||
// Types
|
||||
import {AppState, RemoteDataState} from 'src/types'
|
||||
|
@ -49,6 +53,7 @@ interface StateProps {
|
|||
selectedValues: string[]
|
||||
valuesSearchTerm: string
|
||||
keysSearchTerm: string
|
||||
isInCheckOverlay: boolean
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
|
@ -179,7 +184,7 @@ class TagSelector extends PureComponent<Props> {
|
|||
items={values}
|
||||
selectedItems={selectedValues}
|
||||
onSelectItem={this.handleSelectValue}
|
||||
multiSelect={true}
|
||||
multiSelect={!this.props.isInCheckOverlay}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -268,6 +273,8 @@ const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
|
|||
emptyText = `Select a ${tags[ownProps.index - 1].key} value first`
|
||||
}
|
||||
|
||||
const isInCheckOverlay = getIsInCheckOverlay(state)
|
||||
|
||||
return {
|
||||
emptyText,
|
||||
keys,
|
||||
|
@ -278,6 +285,7 @@ const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
|
|||
selectedValues,
|
||||
valuesSearchTerm,
|
||||
keysSearchTerm,
|
||||
isInCheckOverlay,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
.window-selector--label {
|
||||
display: none;
|
||||
margin-right: $ix-marg-a;
|
||||
}
|
||||
|
||||
.cf-dropdown--button .window-selector--label {
|
||||
display: inline-block;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import {Dropdown, ComponentStatus} from '@influxdata/clockface'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
AGG_WINDOW_AUTO,
|
||||
AGG_WINDOW_NONE,
|
||||
} from 'src/timeMachine/constants/queryBuilder'
|
||||
|
||||
interface Window {
|
||||
period: string
|
||||
}
|
||||
|
||||
export const windows: Window[] = [
|
||||
{period: AGG_WINDOW_NONE},
|
||||
{period: AGG_WINDOW_AUTO},
|
||||
{period: '5m'},
|
||||
{period: '15m'},
|
||||
{period: '1h'},
|
||||
{period: '6h'},
|
||||
{period: '12h'},
|
||||
{period: '24h'},
|
||||
{period: '2d'},
|
||||
{period: '7d'},
|
||||
{period: '30d'},
|
||||
]
|
||||
|
||||
interface Props {
|
||||
onSelect: (period: string) => void
|
||||
period: string
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
const WindowSelector: FunctionComponent<Props> = ({
|
||||
onSelect,
|
||||
period,
|
||||
disabled,
|
||||
}) => {
|
||||
return (
|
||||
<Dropdown
|
||||
testID="window-selector"
|
||||
button={(active, onClick) => (
|
||||
<Dropdown.Button
|
||||
testID="window-selector--button"
|
||||
active={active}
|
||||
onClick={onClick}
|
||||
status={getStatus(disabled)}
|
||||
>
|
||||
{showPrefix(period) && (
|
||||
<span className="window-selector--label">Every</span>
|
||||
)}
|
||||
{period}
|
||||
</Dropdown.Button>
|
||||
)}
|
||||
menu={onCollapse => (
|
||||
<Dropdown.Menu onCollapse={onCollapse} testID="window-selector--menu">
|
||||
{windows.map(window => (
|
||||
<Dropdown.Item
|
||||
id={window.period}
|
||||
key={window.period}
|
||||
value={window.period}
|
||||
testID={`window-selector--${window.period}`}
|
||||
selected={window.period === period}
|
||||
onClick={onSelect}
|
||||
>
|
||||
{showPrefix(window.period) && (
|
||||
<span className="window-selector--label">Every</span>
|
||||
)}
|
||||
{window.period}
|
||||
</Dropdown.Item>
|
||||
))}
|
||||
</Dropdown.Menu>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const showPrefix = (id: string): boolean => {
|
||||
return id !== AGG_WINDOW_AUTO && id !== AGG_WINDOW_NONE
|
||||
}
|
||||
|
||||
const getStatus = (disabled: boolean): ComponentStatus => {
|
||||
if (disabled) {
|
||||
return ComponentStatus.Disabled
|
||||
}
|
||||
|
||||
return ComponentStatus.Default
|
||||
}
|
||||
|
||||
export default WindowSelector
|
|
@ -1,6 +1,26 @@
|
|||
export const AGG_WINDOW_AUTO = 'auto'
|
||||
export const AGG_WINDOW_NONE = 'none'
|
||||
|
||||
export const DURATIONS = [
|
||||
{duration: '5s', displayText: 'Every 5 seconds'},
|
||||
{duration: '15s', displayText: 'Every 15 seconds'},
|
||||
{duration: '1m', displayText: 'Every minute'},
|
||||
{duration: '5m', displayText: 'Every 5 minutes'},
|
||||
{duration: '15m', displayText: 'Every 15 minutes'},
|
||||
{duration: '1h', displayText: 'Every hour'},
|
||||
{duration: '6h', displayText: 'Every 6 hours'},
|
||||
{duration: '12h', displayText: 'Every 12 hours'},
|
||||
{duration: '24h', displayText: 'Every 24 hours'},
|
||||
{duration: '2d', displayText: 'Every 2 days'},
|
||||
{duration: '7d', displayText: 'Every 7 days'},
|
||||
{duration: '30d', displayText: 'Every 30 days'},
|
||||
]
|
||||
|
||||
export const AUTO_NONE_DURATIONS = [
|
||||
{duration: AGG_WINDOW_AUTO, displayText: 'Auto'},
|
||||
{duration: AGG_WINDOW_NONE, displayText: 'None'},
|
||||
]
|
||||
|
||||
export interface QueryFn {
|
||||
name: string
|
||||
flux: (period?: string) => string
|
||||
|
|
|
@ -146,6 +146,8 @@ export const timeMachinesReducer = (
|
|||
}))
|
||||
const queryBuilder = initialQueryBuilderState(draftQueries[0].builderConfig)
|
||||
const queryResults = initialQueryResultsState()
|
||||
const timeRange =
|
||||
activeTimeMachineID === 'alerting' ? null : activeTimeMachine.timeRange
|
||||
|
||||
return {
|
||||
...state,
|
||||
|
@ -155,6 +157,7 @@ export const timeMachinesReducer = (
|
|||
[activeTimeMachineID]: {
|
||||
...activeTimeMachine,
|
||||
activeTab: 'queries',
|
||||
timeRange,
|
||||
...initialState,
|
||||
isViewingRawData: false,
|
||||
activeQueryIndex: 0,
|
||||
|
@ -604,7 +607,6 @@ export const timeMachineReducer = (
|
|||
|
||||
if (action.payload.resetSelections) {
|
||||
builderConfig.tags = [{key: '', values: []}]
|
||||
builderConfig.functions = []
|
||||
buildActiveQuery(draftState)
|
||||
}
|
||||
})
|
||||
|
@ -765,6 +767,10 @@ export const timeMachineReducer = (
|
|||
|
||||
draftQueries[activeQueryIndex].builderConfig.aggregateWindow = {period}
|
||||
buildActiveQuery(draftState)
|
||||
|
||||
if (state.alerting.check) {
|
||||
state.alerting.check.every = period
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -837,12 +843,24 @@ export const timeMachineReducer = (
|
|||
return {...state, alerting}
|
||||
|
||||
case 'UPDATE_TIMEMACHINE_CHECK':
|
||||
const updatedCheck = {
|
||||
...state.alerting.check,
|
||||
...action.payload.checkUpdate,
|
||||
} as Partial<Check>
|
||||
return produce(state, draftState => {
|
||||
draftState.alerting.check = {
|
||||
...draftState.alerting.check,
|
||||
...action.payload.checkUpdate,
|
||||
} as Check
|
||||
|
||||
return {...state, alerting: {...state.alerting, check: updatedCheck}}
|
||||
const every = action.payload.checkUpdate.every
|
||||
|
||||
if (every) {
|
||||
const {activeQueryIndex, draftQueries} = draftState
|
||||
|
||||
draftQueries[activeQueryIndex].builderConfig.aggregateWindow = {
|
||||
period: every,
|
||||
}
|
||||
|
||||
buildActiveQuery(draftState)
|
||||
}
|
||||
})
|
||||
|
||||
case 'CHANGE_TIMEMACHINE_CHECK_TYPE':
|
||||
return produce(state, draftState => {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {fromFlux, Table} from '@influxdata/giraffe'
|
|||
|
||||
// Utils
|
||||
import {parseResponse} from 'src/shared/parsing/flux/response'
|
||||
import {getCheckVisTimeRange} from 'src/alerting/utils/vis'
|
||||
import {
|
||||
defaultXColumn,
|
||||
defaultYColumn,
|
||||
|
@ -13,7 +14,13 @@ import {
|
|||
} from 'src/shared/utils/vis'
|
||||
|
||||
// Types
|
||||
import {FluxTable, QueryView, AppState, DashboardDraftQuery} from 'src/types'
|
||||
import {
|
||||
FluxTable,
|
||||
QueryView,
|
||||
AppState,
|
||||
DashboardDraftQuery,
|
||||
TimeRange,
|
||||
} from 'src/types'
|
||||
|
||||
export const getActiveTimeMachine = (state: AppState) => {
|
||||
const {activeTimeMachineID, timeMachines} = state.timeMachines
|
||||
|
@ -22,6 +29,20 @@ export const getActiveTimeMachine = (state: AppState) => {
|
|||
return timeMachine
|
||||
}
|
||||
|
||||
export const getIsInCheckOverlay = (state: AppState): boolean => {
|
||||
return state.timeMachines.activeTimeMachineID === 'alerting'
|
||||
}
|
||||
|
||||
export const getTimeRange = (state: AppState): TimeRange => {
|
||||
const {alerting, timeRange} = getActiveTimeMachine(state)
|
||||
|
||||
if (!getIsInCheckOverlay(state)) {
|
||||
return timeRange
|
||||
}
|
||||
|
||||
return getCheckVisTimeRange(alerting.check.every)
|
||||
}
|
||||
|
||||
export const getActiveQuery = (state: AppState): DashboardDraftQuery => {
|
||||
const {draftQueries, activeQueryIndex} = getActiveTimeMachine(state)
|
||||
|
||||
|
|
Loading…
Reference in New Issue