feat(ui): add initial alert threshold visualization
parent
ee7ff84d8b
commit
98e8dc9ad8
|
@ -140,7 +140,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@influxdata/clockface": "0.0.13",
|
||||
"@influxdata/giraffe": "0.15.0",
|
||||
"@influxdata/giraffe": "0.16.0",
|
||||
"@influxdata/influx": "0.4.0",
|
||||
"@influxdata/influxdb-templates": "0.2.0",
|
||||
"@influxdata/react-custom-scrollbars": "4.3.8",
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// Libraries
|
||||
import React, {useState, FunctionComponent} from 'react'
|
||||
import {Config, Table} from '@influxdata/giraffe'
|
||||
import {flatMap} from 'lodash'
|
||||
|
||||
// Components
|
||||
import EmptyGraphMessage from 'src/shared/components/EmptyGraphMessage'
|
||||
import GraphLoadingDots from 'src/shared/components/GraphLoadingDots'
|
||||
import ThresholdMarkers from 'src/shared/components/ThresholdMarkers'
|
||||
|
||||
// Utils
|
||||
import {getFormatter, filterNoisyColumns} from 'src/shared/utils/vis'
|
||||
import {useVisDomainSettings} from 'src/shared/utils/useVisDomainSettings'
|
||||
|
||||
// Constants
|
||||
import {VIS_THEME} from 'src/shared/constants'
|
||||
import {INVALID_DATA_COPY} from 'src/shared/copy/cell'
|
||||
|
||||
// Types
|
||||
import {RemoteDataState, CheckView, TimeZone, ThresholdConfig} from 'src/types'
|
||||
|
||||
const X_COLUMN = '_time'
|
||||
const Y_COLUMN = '_value'
|
||||
|
||||
const THRESHOLDS: ThresholdConfig[] = [
|
||||
{
|
||||
type: 'less',
|
||||
allValues: false,
|
||||
level: 'UNKNOWN',
|
||||
value: 20,
|
||||
},
|
||||
]
|
||||
|
||||
interface Props {
|
||||
table: Table
|
||||
fluxGroupKeyUnion: string[]
|
||||
loading: RemoteDataState
|
||||
timeZone: TimeZone
|
||||
viewProperties: CheckView
|
||||
children: (config: Config) => JSX.Element
|
||||
}
|
||||
|
||||
const AlertCheckContainer: FunctionComponent<Props> = ({
|
||||
table,
|
||||
fluxGroupKeyUnion,
|
||||
loading,
|
||||
children,
|
||||
timeZone,
|
||||
viewProperties: {yDomain: storedYDomain},
|
||||
}) => {
|
||||
const [thresholds, setThresholds] = useState(THRESHOLDS)
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings(
|
||||
storedYDomain,
|
||||
table.getColumn(Y_COLUMN, 'number')
|
||||
)
|
||||
|
||||
const columnKeys = table.columnKeys
|
||||
const isValidView =
|
||||
columnKeys.includes(X_COLUMN) && columnKeys.includes(Y_COLUMN)
|
||||
|
||||
if (!isValidView) {
|
||||
return <EmptyGraphMessage message={INVALID_DATA_COPY} />
|
||||
}
|
||||
|
||||
const groupKey = [...fluxGroupKeyUnion, 'result']
|
||||
|
||||
const xFormatter = getFormatter(table.getColumnType(X_COLUMN), {
|
||||
timeZone,
|
||||
trimZeros: false,
|
||||
})
|
||||
|
||||
const yFormatter = getFormatter(table.getColumnType(Y_COLUMN), {
|
||||
timeZone,
|
||||
trimZeros: false,
|
||||
})
|
||||
|
||||
const legendColumns = filterNoisyColumns(
|
||||
[...groupKey, X_COLUMN, Y_COLUMN],
|
||||
table
|
||||
)
|
||||
|
||||
const yTicks = flatMap(thresholds, (t: any) => [
|
||||
t.value,
|
||||
t.minValue,
|
||||
t.maxValue,
|
||||
]).filter(t => t !== undefined)
|
||||
|
||||
const config: Config = {
|
||||
...VIS_THEME,
|
||||
table,
|
||||
legendColumns,
|
||||
yTicks,
|
||||
yDomain,
|
||||
onSetYDomain,
|
||||
onResetYDomain,
|
||||
valueFormatters: {
|
||||
[X_COLUMN]: xFormatter,
|
||||
[Y_COLUMN]: yFormatter,
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
type: 'line',
|
||||
x: X_COLUMN,
|
||||
y: Y_COLUMN,
|
||||
fill: groupKey,
|
||||
interpolation: 'monotoneX',
|
||||
},
|
||||
{
|
||||
type: 'custom',
|
||||
render: ({yScale, yDomain}) => (
|
||||
<ThresholdMarkers
|
||||
key="custom"
|
||||
thresholds={thresholds}
|
||||
onSetThresholds={setThresholds}
|
||||
yScale={yScale}
|
||||
yDomain={yDomain}
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="vis-plot-container vis-plot-container--alert-check">
|
||||
{loading === RemoteDataState.Loading && <GraphLoadingDots />}
|
||||
{children(config)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AlertCheckContainer
|
|
@ -0,0 +1,47 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
import {Scale} from '@influxdata/giraffe'
|
||||
|
||||
// Components
|
||||
import ThresholdMarker from 'src/shared/components/ThresholdMarker'
|
||||
import ThresholdMarkerArea from 'src/shared/components/ThresholdMarkerArea'
|
||||
|
||||
// Utils
|
||||
import {isInDomain, clamp} from 'src/shared/utils/vis'
|
||||
import {DragEvent} from 'src/shared/utils/useDragBehavior'
|
||||
|
||||
// Types
|
||||
import {GreaterThresholdConfig} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
yScale: Scale<number, number>
|
||||
yDomain: number[]
|
||||
threshold: GreaterThresholdConfig
|
||||
onChangePos: (e: DragEvent) => void
|
||||
}
|
||||
|
||||
const GreaterThresholdMarker: FunctionComponent<Props> = ({
|
||||
yDomain,
|
||||
yScale,
|
||||
threshold: {level, value},
|
||||
onChangePos,
|
||||
}) => {
|
||||
const y = yScale(clamp(value, yDomain))
|
||||
|
||||
return (
|
||||
<>
|
||||
{isInDomain(value, yDomain) && (
|
||||
<ThresholdMarker level={level} y={y} onDrag={onChangePos} />
|
||||
)}
|
||||
{value <= yDomain[1] && (
|
||||
<ThresholdMarkerArea
|
||||
level={level}
|
||||
top={yScale(yDomain[1])}
|
||||
height={y - yScale(yDomain[1])}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default GreaterThresholdMarker
|
|
@ -0,0 +1,47 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
import {Scale} from '@influxdata/giraffe'
|
||||
|
||||
// Components
|
||||
import ThresholdMarker from 'src/shared/components/ThresholdMarker'
|
||||
import ThresholdMarkerArea from 'src/shared/components/ThresholdMarkerArea'
|
||||
|
||||
// Utils
|
||||
import {clamp, isInDomain} from 'src/shared/utils/vis'
|
||||
import {DragEvent} from 'src/shared/utils/useDragBehavior'
|
||||
|
||||
// Types
|
||||
import {LessThresholdConfig} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
yScale: Scale<number, number>
|
||||
yDomain: number[]
|
||||
threshold: LessThresholdConfig
|
||||
onChangePos: (e: DragEvent) => void
|
||||
}
|
||||
|
||||
const LessThresholdMarker: FunctionComponent<Props> = ({
|
||||
yScale,
|
||||
yDomain,
|
||||
threshold: {level, value},
|
||||
onChangePos,
|
||||
}) => {
|
||||
const y = yScale(clamp(value, yDomain))
|
||||
|
||||
return (
|
||||
<>
|
||||
{isInDomain(value, yDomain) && (
|
||||
<ThresholdMarker level={level} y={y} onDrag={onChangePos} />
|
||||
)}
|
||||
{value >= yDomain[0] && (
|
||||
<ThresholdMarkerArea
|
||||
level={level}
|
||||
top={y}
|
||||
height={yScale(yDomain[0]) - y}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default LessThresholdMarker
|
|
@ -0,0 +1,66 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
import {Scale} from '@influxdata/giraffe'
|
||||
|
||||
// Components
|
||||
import ThresholdMarker from 'src/shared/components/ThresholdMarker'
|
||||
import ThresholdMarkerArea from 'src/shared/components/ThresholdMarkerArea'
|
||||
|
||||
// Utils
|
||||
import {isInDomain, clamp} from 'src/shared/utils/vis'
|
||||
import {DragEvent} from 'src/shared/utils/useDragBehavior'
|
||||
|
||||
// Types
|
||||
import {RangeThresholdConfig} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
yScale: Scale<number, number>
|
||||
yDomain: number[]
|
||||
threshold: RangeThresholdConfig
|
||||
onChangeMaxPos: (e: DragEvent) => void
|
||||
onChangeMinPos: (e: DragEvent) => void
|
||||
}
|
||||
|
||||
const RangeThresholdMarkers: FunctionComponent<Props> = ({
|
||||
yScale,
|
||||
yDomain,
|
||||
threshold: {level, within, minValue, maxValue},
|
||||
onChangeMinPos,
|
||||
onChangeMaxPos,
|
||||
}) => {
|
||||
const minY = yScale(clamp(minValue, yDomain))
|
||||
const maxY = yScale(clamp(maxValue, yDomain))
|
||||
|
||||
return (
|
||||
<>
|
||||
{isInDomain(minValue, yDomain) && (
|
||||
<ThresholdMarker level={level} y={minY} onDrag={onChangeMinPos} />
|
||||
)}
|
||||
{isInDomain(maxValue, yDomain) && (
|
||||
<ThresholdMarker level={level} y={maxY} onDrag={onChangeMaxPos} />
|
||||
)}
|
||||
{within ? (
|
||||
<ThresholdMarkerArea level={level} top={maxY} height={minY - maxY} />
|
||||
) : (
|
||||
<>
|
||||
{maxValue <= yDomain[1] && (
|
||||
<ThresholdMarkerArea
|
||||
level={level}
|
||||
top={yScale(yDomain[1])}
|
||||
height={maxY - yScale(yDomain[1])}
|
||||
/>
|
||||
)}
|
||||
{minValue >= yDomain[0] && (
|
||||
<ThresholdMarkerArea
|
||||
level={level}
|
||||
top={minY}
|
||||
height={yScale(yDomain[0]) - minY}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default RangeThresholdMarkers
|
|
@ -0,0 +1,33 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
// Utils
|
||||
import {useDragBehavior, DragEvent} from 'src/shared/utils/useDragBehavior'
|
||||
|
||||
// Types
|
||||
import {CheckStatusLevel} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
level: CheckStatusLevel
|
||||
y: number
|
||||
onDrag: (e: DragEvent) => void
|
||||
}
|
||||
|
||||
const ThresholdMarker: FunctionComponent<Props> = ({level, y, onDrag}) => {
|
||||
const dragTargetProps = useDragBehavior(onDrag)
|
||||
const levelClass = `threshold-marker--${level.toLowerCase()}`
|
||||
const style = {top: `${y}px`}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`threshold-marker--line ${levelClass}`} style={style} />
|
||||
<div
|
||||
className={`threshold-marker--handle ${levelClass}`}
|
||||
style={style}
|
||||
{...dragTargetProps}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThresholdMarker
|
|
@ -0,0 +1,27 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
// Types
|
||||
import {CheckStatusLevel} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
level: CheckStatusLevel
|
||||
top: number
|
||||
height: number
|
||||
}
|
||||
|
||||
const ThresholdMarkerArea: FunctionComponent<Props> = ({
|
||||
level,
|
||||
top,
|
||||
height,
|
||||
}) => (
|
||||
<div
|
||||
className={`threshold-marker--area threshold-marker--${level.toLowerCase()}`}
|
||||
style={{
|
||||
top: `${top}px`,
|
||||
height: `${height}px`,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
export default ThresholdMarkerArea
|
|
@ -0,0 +1,75 @@
|
|||
$threshold-marker--handle-height: 18px;
|
||||
$threshold-marker--handle-width: 30px;
|
||||
$threshold-marker--caret-width: 12px;
|
||||
|
||||
@mixin threshold-marker--color($color, $color-varient) {
|
||||
background-color: $color;
|
||||
|
||||
&.threshold-marker--handle {
|
||||
background: linear-gradient(115deg, $color 0%, $color 35%, $color-varient 100%);
|
||||
|
||||
&:before {
|
||||
border-right: $threshold-marker--caret-width solid $color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.threshold-markers {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.threshold-marker--crit {
|
||||
@include threshold-marker--color($c-fire, $c-curacao);
|
||||
}
|
||||
|
||||
.threshold-marker--warn {
|
||||
@include threshold-marker--color($c-tiger, $c-pineapple);
|
||||
}
|
||||
|
||||
.threshold-marker--ok {
|
||||
@include threshold-marker--color($c-rainforest, $c-honeydew);
|
||||
}
|
||||
|
||||
.threshold-marker--info {
|
||||
@include threshold-marker--color($c-pool, $c-laser);
|
||||
}
|
||||
|
||||
.threshold-marker--unknown {
|
||||
@include threshold-marker--color($c-amethyst, $c-amethyst);
|
||||
}
|
||||
|
||||
.threshold-marker--area {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
opacity: 0.07;
|
||||
}
|
||||
|
||||
.threshold-marker--line {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.threshold-marker--handle {
|
||||
position: absolute;
|
||||
right: 1px - $threshold-marker--handle-width;
|
||||
width: $threshold-marker--handle-width - $threshold-marker--caret-width;
|
||||
height: $threshold-marker--handle-height;
|
||||
border-radius: 0 $radius-small $radius-small 0;
|
||||
transform: translateY(-50%);
|
||||
cursor: grab;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
border-top: ($threshold-marker--handle-height / 2) solid transparent;
|
||||
border-bottom: ($threshold-marker--handle-height / 2) solid transparent;
|
||||
display: block;
|
||||
left: 0 - $threshold-marker--caret-width;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
// Libraries
|
||||
import React, {useRef, FunctionComponent} from 'react'
|
||||
import {Scale} from '@influxdata/giraffe'
|
||||
|
||||
// Components
|
||||
import RangeThresholdMarkers from 'src/shared/components/RangeThresholdMarkers'
|
||||
import LessThresholdMarker from 'src/shared/components/LessThresholdMarker'
|
||||
import GreaterThresholdMarker from 'src/shared/components/GreaterThresholdMarker'
|
||||
|
||||
// Utils
|
||||
import {clamp} from 'src/shared/utils/vis'
|
||||
|
||||
// Types
|
||||
import {ThresholdConfig} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
thresholds: ThresholdConfig[]
|
||||
onSetThresholds: (newThresholds: ThresholdConfig[]) => void
|
||||
yScale: Scale<number, number>
|
||||
yDomain: number[]
|
||||
}
|
||||
|
||||
const ThresholdMarkers: FunctionComponent<Props> = ({
|
||||
yScale,
|
||||
yDomain,
|
||||
thresholds,
|
||||
onSetThresholds,
|
||||
}) => {
|
||||
const originRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const handleDrag = (index: number, field: string, y: number) => {
|
||||
const yRelative = y - originRef.current.getBoundingClientRect().top
|
||||
const yValue = clamp(yScale.invert(yRelative), yDomain)
|
||||
const nextThreshold = {...thresholds[index], [field]: yValue}
|
||||
|
||||
if (
|
||||
nextThreshold.type === 'range' &&
|
||||
nextThreshold.minValue > nextThreshold.maxValue
|
||||
) {
|
||||
// If the user drags the min past the max or vice versa, we swap the
|
||||
// values that are set so that the min is always at most the max
|
||||
const maxValue = nextThreshold.minValue
|
||||
|
||||
nextThreshold.minValue = nextThreshold.maxValue
|
||||
nextThreshold.maxValue = maxValue
|
||||
}
|
||||
|
||||
const nextThresholds = thresholds.map((t, i) =>
|
||||
i === index ? nextThreshold : t
|
||||
)
|
||||
|
||||
onSetThresholds(nextThresholds)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="threshold-markers" ref={originRef}>
|
||||
{thresholds.map((threshold, index) => {
|
||||
const onChangePos = ({y}) => handleDrag(index, 'value', y)
|
||||
const onChangeMaxPos = ({y}) => handleDrag(index, 'maxValue', y)
|
||||
const onChangeMinPos = ({y}) => handleDrag(index, 'minValue', y)
|
||||
|
||||
switch (threshold.type) {
|
||||
case 'greater':
|
||||
return (
|
||||
<GreaterThresholdMarker
|
||||
key={index}
|
||||
yScale={yScale}
|
||||
yDomain={yDomain}
|
||||
threshold={threshold}
|
||||
onChangePos={onChangePos}
|
||||
/>
|
||||
)
|
||||
case 'less':
|
||||
return (
|
||||
<LessThresholdMarker
|
||||
key={index}
|
||||
yScale={yScale}
|
||||
yDomain={yDomain}
|
||||
threshold={threshold}
|
||||
onChangePos={onChangePos}
|
||||
/>
|
||||
)
|
||||
case 'range':
|
||||
return (
|
||||
<RangeThresholdMarkers
|
||||
key={index}
|
||||
yScale={yScale}
|
||||
yDomain={yDomain}
|
||||
threshold={threshold}
|
||||
onChangeMinPos={onChangeMinPos}
|
||||
onChangeMaxPos={onChangeMaxPos}
|
||||
/>
|
||||
)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThresholdMarkers
|
|
@ -174,6 +174,11 @@ $cell--header-size: 36px;
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
padding: $ix-marg-c;
|
||||
|
||||
&.vis-plot-container--alert-check {
|
||||
padding-right: $ix-marg-c + 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.giraffe-tooltip-container {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import * as React from 'react'
|
||||
import {useCallback} from 'react'
|
||||
|
||||
export interface DragEvent {
|
||||
x: number
|
||||
y: number
|
||||
type: 'dragStart' | 'drag' | 'dragStop'
|
||||
}
|
||||
|
||||
type MouseDownEvent = React.MouseEvent<Element, MouseEvent>
|
||||
|
||||
export const useDragBehavior = (
|
||||
onDrag: (e: DragEvent) => any
|
||||
): {onMouseDown: (e: MouseDownEvent) => any} => {
|
||||
const onMouseDown = useCallback(
|
||||
(mouseDownEvent: MouseDownEvent) => {
|
||||
mouseDownEvent.stopPropagation()
|
||||
|
||||
onDrag({
|
||||
type: 'dragStart',
|
||||
x: mouseDownEvent.pageX,
|
||||
y: mouseDownEvent.pageY,
|
||||
})
|
||||
|
||||
const onMouseMove = mouseMoveEvent => {
|
||||
onDrag({
|
||||
type: 'drag',
|
||||
x: mouseMoveEvent.pageX,
|
||||
y: mouseMoveEvent.pageY,
|
||||
})
|
||||
}
|
||||
|
||||
const onMouseUp = mouseUpEvent => {
|
||||
document.removeEventListener('mousemove', onMouseMove)
|
||||
document.removeEventListener('mouseup', onMouseUp)
|
||||
|
||||
onDrag({
|
||||
type: 'dragStop',
|
||||
x: mouseUpEvent.pageX,
|
||||
y: mouseUpEvent.pageY,
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', onMouseMove)
|
||||
document.addEventListener('mouseup', onMouseUp)
|
||||
},
|
||||
[onDrag]
|
||||
)
|
||||
|
||||
return {onMouseDown}
|
||||
}
|
|
@ -45,11 +45,12 @@ interface GetFormatterOptions {
|
|||
suffix?: string
|
||||
base?: Base
|
||||
timeZone?: TimeZone
|
||||
trimZeros?: boolean
|
||||
}
|
||||
|
||||
export const getFormatter = (
|
||||
columnType: ColumnType,
|
||||
{prefix, suffix, base, timeZone}: GetFormatterOptions = {}
|
||||
{prefix, suffix, base, timeZone, trimZeros = true}: GetFormatterOptions = {}
|
||||
): null | ((x: any) => string) => {
|
||||
if (columnType === 'number' && base === '2') {
|
||||
return binaryPrefixFormatter({
|
||||
|
@ -64,6 +65,7 @@ export const getFormatter = (
|
|||
prefix,
|
||||
suffix,
|
||||
significantDigits: VIS_SIG_DIGITS,
|
||||
trimZeros,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -223,3 +225,18 @@ export const defaultYColumn = (
|
|||
|
||||
return null
|
||||
}
|
||||
|
||||
export const isInDomain = (value: number, domain: number[]) =>
|
||||
value >= domain[0] && value <= domain[1]
|
||||
|
||||
export const clamp = (value: number, domain: number[]) => {
|
||||
if (value < domain[0]) {
|
||||
return domain[0]
|
||||
}
|
||||
|
||||
if (value > domain[1]) {
|
||||
return domain[1]
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@
|
|||
@import 'src/templates/components/createFromTemplateOverlay/CreateFromTemplateOverlay.scss';
|
||||
@import 'src/onboarding/components/SigninForm.scss';
|
||||
@import 'src/shared/components/ThresholdsSettings.scss';
|
||||
|
||||
@import 'src/shared/components/ThresholdMarkers.scss';
|
||||
|
||||
// External
|
||||
@import '../../node_modules/@influxdata/react-custom-scrollbars/dist/styles.css';
|
||||
|
|
|
@ -127,6 +127,7 @@ export type ViewProperties =
|
|||
| HistogramView
|
||||
| HeatmapView
|
||||
| ScatterView
|
||||
| CheckView
|
||||
|
||||
export type QueryViewProperties = Extract<
|
||||
ViewProperties,
|
||||
|
@ -286,6 +287,47 @@ export interface ScatterView {
|
|||
showNoteWhenEmpty: boolean
|
||||
}
|
||||
|
||||
export type CheckStatusLevel = 'OK' | 'INFO' | 'WARN' | 'CRIT' | 'UNKNOWN'
|
||||
|
||||
export interface GreaterThresholdConfig {
|
||||
type: 'greater'
|
||||
level: CheckStatusLevel
|
||||
allValues: boolean
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface LessThresholdConfig {
|
||||
type: 'less'
|
||||
level: CheckStatusLevel
|
||||
allValues: boolean
|
||||
value: number
|
||||
}
|
||||
|
||||
export interface RangeThresholdConfig {
|
||||
type: 'range'
|
||||
level: CheckStatusLevel
|
||||
allValues: boolean
|
||||
minValue: number
|
||||
maxValue: number
|
||||
within: boolean
|
||||
}
|
||||
|
||||
export type ThresholdConfig =
|
||||
| GreaterThresholdConfig
|
||||
| LessThresholdConfig
|
||||
| RangeThresholdConfig
|
||||
|
||||
export interface CheckView {
|
||||
type: ViewType.Check
|
||||
shape: ViewShape.ChronografV2
|
||||
queries: DashboardQuery[]
|
||||
thresholds: ThresholdConfig[]
|
||||
yDomain: [number, number]
|
||||
colors: string[]
|
||||
note: string
|
||||
showNoteWhenEmpty: boolean
|
||||
}
|
||||
|
||||
export interface MarkdownView {
|
||||
type: ViewType.Markdown
|
||||
shape: ViewShape.ChronografV2
|
||||
|
@ -308,6 +350,7 @@ export enum ViewType {
|
|||
Histogram = 'histogram',
|
||||
Heatmap = 'heatmap',
|
||||
Scatter = 'scatter',
|
||||
Check = 'check',
|
||||
}
|
||||
|
||||
export interface DashboardFile {
|
||||
|
|
|
@ -748,10 +748,10 @@
|
|||
react-scrollbars-custom "^4.0.0-alpha.10"
|
||||
storybook-addon-jsx "^7.1.0"
|
||||
|
||||
"@influxdata/giraffe@0.15.0":
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/giraffe/-/giraffe-0.15.0.tgz#e580095a44b0ece4d20ff04dcd393632205e3775"
|
||||
integrity sha512-PtEqcckyOU7KAnsWfjlk59BCPvZrKHzm1M/Qz4rL6WYLDn7NDKrjCuXr6ztMIC8AD1S5MAPrB/w1cNB8Rhe/Wg==
|
||||
"@influxdata/giraffe@0.16.0":
|
||||
version "0.16.0"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/giraffe/-/giraffe-0.16.0.tgz#b04a304460a7c9449fe1a9fa2a3f5db97949e916"
|
||||
integrity sha512-nDVQgx5Lq3fjsMXTzYwzf0HXKjSxzsBJibitObwtE0wefpzU4LW0IEUrcCBNIQyXj1OxyBNL9a67gZ4DyV7M2w==
|
||||
|
||||
"@influxdata/influx@0.4.0":
|
||||
version "0.4.0"
|
||||
|
|
Loading…
Reference in New Issue