fix(ui): adding times in script editor will default start and endtime for timerange queries (#16201)
fix(ui): adding times in script editor will default start and endtime for timerange queries, compute timeranges based on script and based on widest date range & fix dashboard so that cells that have been saved with timerange scripts are based on those timerangespull/15967/head
parent
48e854776e
commit
eefb8dd525
|
@ -25,6 +25,7 @@
|
|||
1. [16175](https://github.com/influxdata/influxdb/pull/16175): Added delete functionality to note cells so that they can be deleted
|
||||
1. [16204](https://github.com/influxdata/influxdb/pull/16204): Fix failure to create labels when creating telegraf configs
|
||||
1. [16207](https://github.com/influxdata/influxdb/pull/16207): Fix crash when editing a Telegraf config
|
||||
1. [16201](https://github.com/influxdata/influxdb/pull/16201): Updated start/endtime functionality so that custom script timeranges overwrite dropdown selections
|
||||
|
||||
### UI Improvements
|
||||
|
||||
|
|
|
@ -16,12 +16,16 @@ import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
|||
import {INVALID_DATA_COPY} from 'src/shared/copy/cell'
|
||||
|
||||
// Types
|
||||
import {RemoteDataState, HeatmapViewProperties, TimeZone} from 'src/types'
|
||||
import {
|
||||
RemoteDataState,
|
||||
HeatmapViewProperties,
|
||||
TimeZone,
|
||||
TimeRange,
|
||||
} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
endTime: number
|
||||
loading: RemoteDataState
|
||||
startTime: number
|
||||
timeRange: TimeRange | null
|
||||
table: Table
|
||||
timeZone: TimeZone
|
||||
viewProperties: HeatmapViewProperties
|
||||
|
@ -29,9 +33,8 @@ interface Props {
|
|||
}
|
||||
|
||||
const HeatmapPlot: FunctionComponent<Props> = ({
|
||||
endTime,
|
||||
loading,
|
||||
startTime,
|
||||
timeRange,
|
||||
table,
|
||||
timeZone,
|
||||
viewProperties: {
|
||||
|
@ -56,8 +59,7 @@ const HeatmapPlot: FunctionComponent<Props> = ({
|
|||
const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings(
|
||||
storedXDomain,
|
||||
table.getColumn(xColumn, 'number'),
|
||||
startTime,
|
||||
endTime
|
||||
timeRange
|
||||
)
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings(
|
||||
|
|
|
@ -10,13 +10,12 @@ import ViewSwitcher from 'src/shared/components/ViewSwitcher'
|
|||
// Utils
|
||||
import {GlobalAutoRefresher} from 'src/utils/AutoRefresher'
|
||||
import {getTimeRangeVars} from 'src/variables/utils/getTimeRangeVars'
|
||||
import {getVariableAssignments} from 'src/variables/selectors'
|
||||
import {getDashboardValuesStatus} from 'src/variables/selectors'
|
||||
import {
|
||||
getVariableAssignments,
|
||||
getDashboardValuesStatus,
|
||||
} from 'src/variables/selectors'
|
||||
import {checkResultsLength} from 'src/shared/utils/vis'
|
||||
|
||||
// Selectors
|
||||
import {getEndTime, getStartTime} from 'src/timeMachine/selectors/index'
|
||||
import {getTimeRangeByDashboardID} from 'src/dashboards/selectors/index'
|
||||
import {getActiveTimeRange} from 'src/timeMachine/selectors/index'
|
||||
|
||||
// Types
|
||||
import {
|
||||
|
@ -39,8 +38,7 @@ interface OwnProps {
|
|||
}
|
||||
|
||||
interface StateProps {
|
||||
endTime: number
|
||||
startTime: number
|
||||
ranges: TimeRange | null
|
||||
timeZone: TimeZone
|
||||
variableAssignments: VariableAssignment[]
|
||||
variablesStatus: RemoteDataState
|
||||
|
@ -73,14 +71,7 @@ class RefreshingView extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {
|
||||
check,
|
||||
endTime,
|
||||
properties,
|
||||
manualRefresh,
|
||||
startTime,
|
||||
timeZone,
|
||||
} = this.props
|
||||
const {check, ranges, properties, manualRefresh, timeZone} = this.props
|
||||
const {submitToken} = this.state
|
||||
|
||||
return (
|
||||
|
@ -111,12 +102,11 @@ class RefreshingView extends PureComponent<Props, State> {
|
|||
>
|
||||
<ViewSwitcher
|
||||
check={check}
|
||||
endTime={endTime}
|
||||
files={files}
|
||||
giraffeResult={giraffeResult}
|
||||
loading={loading}
|
||||
properties={properties}
|
||||
startTime={startTime}
|
||||
timeRange={ranges}
|
||||
statuses={statuses}
|
||||
timeZone={timeZone}
|
||||
/>
|
||||
|
@ -168,15 +158,13 @@ const mstp = (state: AppState, ownProps: OwnProps): StateProps => {
|
|||
state,
|
||||
ownProps.dashboardID
|
||||
)
|
||||
const timeRange = getTimeRangeByDashboardID(state, ownProps.dashboardID)
|
||||
|
||||
const valuesStatus = getDashboardValuesStatus(state, ownProps.dashboardID)
|
||||
|
||||
const {properties} = ownProps
|
||||
const timeRange = getActiveTimeRange(ownProps.timeRange, properties.queries)
|
||||
const timeZone = state.app.persisted.timeZone
|
||||
|
||||
return {
|
||||
endTime: getEndTime(timeRange),
|
||||
startTime: getStartTime(timeRange),
|
||||
ranges: timeRange,
|
||||
timeZone,
|
||||
variableAssignments,
|
||||
variablesStatus: valuesStatus,
|
||||
|
|
|
@ -20,14 +20,18 @@ import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
|||
import {INVALID_DATA_COPY} from 'src/shared/copy/cell'
|
||||
|
||||
// Types
|
||||
import {RemoteDataState, ScatterViewProperties, TimeZone} from 'src/types'
|
||||
import {
|
||||
RemoteDataState,
|
||||
ScatterViewProperties,
|
||||
TimeZone,
|
||||
TimeRange,
|
||||
} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
children: (config: Config) => JSX.Element
|
||||
endTime: number
|
||||
fluxGroupKeyUnion?: string[]
|
||||
loading: RemoteDataState
|
||||
startTime: number
|
||||
timeRange: TimeRange | null
|
||||
table: Table
|
||||
timeZone: TimeZone
|
||||
viewProperties: ScatterViewProperties
|
||||
|
@ -35,9 +39,8 @@ interface Props {
|
|||
|
||||
const ScatterPlot: FunctionComponent<Props> = ({
|
||||
children,
|
||||
endTime,
|
||||
loading,
|
||||
startTime,
|
||||
timeRange,
|
||||
timeZone,
|
||||
table,
|
||||
viewProperties: {
|
||||
|
@ -68,8 +71,7 @@ const ScatterPlot: FunctionComponent<Props> = ({
|
|||
const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings(
|
||||
storedXDomain,
|
||||
table.getColumn(xColumn, 'number'),
|
||||
startTime,
|
||||
endTime
|
||||
timeRange
|
||||
)
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings(
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
StatusRow,
|
||||
TimeZone,
|
||||
XYViewProperties,
|
||||
TimeRange,
|
||||
} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
|
@ -34,18 +35,16 @@ interface Props {
|
|||
properties: QueryViewProperties | CheckViewProperties
|
||||
timeZone: TimeZone
|
||||
statuses: StatusRow[][]
|
||||
endTime: number
|
||||
startTime: number
|
||||
timeRange: TimeRange | null
|
||||
}
|
||||
|
||||
const ViewSwitcher: FunctionComponent<Props> = ({
|
||||
properties,
|
||||
check,
|
||||
loading,
|
||||
endTime,
|
||||
timeRange,
|
||||
files,
|
||||
giraffeResult: {table, fluxGroupKeyUnion},
|
||||
startTime,
|
||||
timeZone,
|
||||
statuses,
|
||||
}) => {
|
||||
|
@ -83,10 +82,9 @@ const ViewSwitcher: FunctionComponent<Props> = ({
|
|||
case 'xy':
|
||||
return (
|
||||
<XYPlot
|
||||
endTime={endTime}
|
||||
timeRange={timeRange}
|
||||
fluxGroupKeyUnion={fluxGroupKeyUnion}
|
||||
loading={loading}
|
||||
startTime={startTime}
|
||||
table={table}
|
||||
timeZone={timeZone}
|
||||
viewProperties={properties}
|
||||
|
@ -111,10 +109,9 @@ const ViewSwitcher: FunctionComponent<Props> = ({
|
|||
|
||||
return (
|
||||
<XYPlot
|
||||
endTime={endTime}
|
||||
timeRange={timeRange}
|
||||
fluxGroupKeyUnion={fluxGroupKeyUnion}
|
||||
loading={loading}
|
||||
startTime={startTime}
|
||||
table={table}
|
||||
timeZone={timeZone}
|
||||
viewProperties={xyProperties}
|
||||
|
@ -153,9 +150,8 @@ const ViewSwitcher: FunctionComponent<Props> = ({
|
|||
case 'heatmap':
|
||||
return (
|
||||
<HeatmapPlot
|
||||
endTime={endTime}
|
||||
timeRange={timeRange}
|
||||
loading={loading}
|
||||
startTime={startTime}
|
||||
table={table}
|
||||
timeZone={timeZone}
|
||||
viewProperties={properties}
|
||||
|
@ -167,9 +163,8 @@ const ViewSwitcher: FunctionComponent<Props> = ({
|
|||
case 'scatter':
|
||||
return (
|
||||
<ScatterPlot
|
||||
endTime={endTime}
|
||||
timeRange={timeRange}
|
||||
loading={loading}
|
||||
startTime={startTime}
|
||||
table={table}
|
||||
viewProperties={properties}
|
||||
timeZone={timeZone}
|
||||
|
|
|
@ -23,14 +23,13 @@ import {DEFAULT_LINE_COLORS} from 'src/shared/constants/graphColorPalettes'
|
|||
import {INVALID_DATA_COPY} from 'src/shared/copy/cell'
|
||||
|
||||
// Types
|
||||
import {RemoteDataState, XYViewProperties, TimeZone} from 'src/types'
|
||||
import {RemoteDataState, XYViewProperties, TimeZone, TimeRange} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
children: (config: Config) => JSX.Element
|
||||
endTime: number
|
||||
fluxGroupKeyUnion: string[]
|
||||
loading: RemoteDataState
|
||||
startTime: number
|
||||
timeRange: TimeRange | null
|
||||
table: Table
|
||||
timeZone: TimeZone
|
||||
viewProperties: XYViewProperties
|
||||
|
@ -38,10 +37,9 @@ interface Props {
|
|||
|
||||
const XYPlot: FunctionComponent<Props> = ({
|
||||
children,
|
||||
endTime,
|
||||
fluxGroupKeyUnion,
|
||||
loading,
|
||||
startTime,
|
||||
timeRange,
|
||||
table,
|
||||
timeZone,
|
||||
viewProperties: {
|
||||
|
@ -81,8 +79,7 @@ const XYPlot: FunctionComponent<Props> = ({
|
|||
const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings(
|
||||
storedXDomain,
|
||||
table.getColumn(xColumn, 'number'),
|
||||
startTime,
|
||||
endTime
|
||||
timeRange
|
||||
)
|
||||
|
||||
const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings(
|
||||
|
|
|
@ -3,29 +3,50 @@ import {getValidRange} from 'src/shared/utils/useVisDomainSettings'
|
|||
|
||||
// Types
|
||||
import {numericColumnData as data} from 'mocks/dummyData'
|
||||
import {CustomTimeRange} from 'src/types/queries'
|
||||
|
||||
describe('getValidRange', () => {
|
||||
const startTime: number = 1573123611000
|
||||
const endTime: number = 1574981211000
|
||||
const startTime: string = 'Nov 07 2019 02:46:51 GMT-0800'
|
||||
const unixStart: number = 1573123611000
|
||||
const endTime: string = 'Nov 28 2019 14:46:51 GMT-0800'
|
||||
const unixEnd: number = 1574981211000
|
||||
it('should return null when no parameters are input', () => {
|
||||
expect(getValidRange()).toEqual(null)
|
||||
expect(getValidRange(undefined, undefined)).toEqual(null)
|
||||
})
|
||||
it('should return null when no data is passed', () => {
|
||||
expect(getValidRange([], startTime, endTime)).toEqual(null)
|
||||
const timeRange: CustomTimeRange = {
|
||||
type: 'custom',
|
||||
lower: startTime,
|
||||
upper: endTime,
|
||||
}
|
||||
expect(getValidRange([], timeRange)).toEqual(null)
|
||||
})
|
||||
it("should return the startTime as startTime if it's before the first time in the data array", () => {
|
||||
const [start] = getValidRange(data, startTime, endTime)
|
||||
expect(start).toEqual(startTime)
|
||||
const [beginning] = getValidRange(data, endTime, endTime)
|
||||
const timeRange: CustomTimeRange = {
|
||||
type: 'custom',
|
||||
lower: startTime,
|
||||
upper: endTime,
|
||||
}
|
||||
const [start] = getValidRange(data, timeRange)
|
||||
expect(start).toEqual(unixStart)
|
||||
timeRange.lower = endTime
|
||||
const [beginning] = getValidRange(data, timeRange)
|
||||
expect(beginning).toEqual(data[0])
|
||||
})
|
||||
it("should return the endTime as endTime if it's before the last time in the data array", () => {
|
||||
const range = getValidRange(data, startTime, endTime)
|
||||
expect(range[1]).toEqual(endTime)
|
||||
const newRange = getValidRange(data, endTime, startTime)
|
||||
const timeRange: CustomTimeRange = {
|
||||
type: 'custom',
|
||||
lower: startTime,
|
||||
upper: endTime,
|
||||
}
|
||||
const range = getValidRange(data, timeRange)
|
||||
expect(range[1]).toEqual(unixEnd)
|
||||
timeRange.lower = endTime
|
||||
timeRange.upper = startTime
|
||||
const newRange = getValidRange(data, timeRange)
|
||||
expect(newRange[1]).toEqual(data[data.length - 1])
|
||||
})
|
||||
it('should return the the start and end times based on the data array if no start / endTime are passed', () => {
|
||||
expect(getValidRange(data)).toEqual([data[0], data[data.length - 1]])
|
||||
expect(getValidRange(data, null)).toEqual([data[0], data[data.length - 1]])
|
||||
})
|
||||
})
|
||||
|
|
|
@ -5,7 +5,10 @@ import {NumericColumnData} from '@influxdata/giraffe'
|
|||
// Utils
|
||||
import {useOneWayState} from 'src/shared/utils/useOneWayState'
|
||||
import {extent} from 'src/shared/utils/vis'
|
||||
import {getStartTime, getEndTime} from 'src/timeMachine/selectors/index'
|
||||
|
||||
// Types
|
||||
import {TimeRange} from 'src/types'
|
||||
/*
|
||||
This hook helps map the domain setting stored for line graph to the
|
||||
appropriate settings on a @influxdata/giraffe `Config` object.
|
||||
|
@ -16,11 +19,15 @@ import {extent} from 'src/shared/utils/vis'
|
|||
*/
|
||||
export const getValidRange = (
|
||||
data: NumericColumnData = [],
|
||||
startTime: number = Infinity,
|
||||
endTime: number = -Infinity
|
||||
timeRange: TimeRange | null
|
||||
) => {
|
||||
const range = extent((data as number[]) || [])
|
||||
if (!timeRange) {
|
||||
return range
|
||||
}
|
||||
if (range && range.length >= 2) {
|
||||
const startTime = getStartTime(timeRange)
|
||||
const endTime = getEndTime(timeRange)
|
||||
const start = Math.min(startTime, range[0])
|
||||
const end = Math.max(endTime, range[1])
|
||||
return [start, end]
|
||||
|
@ -31,15 +38,14 @@ export const getValidRange = (
|
|||
export const useVisDomainSettings = (
|
||||
storedDomain: number[],
|
||||
data: NumericColumnData,
|
||||
startTime: number = Infinity,
|
||||
endTime: number = -Infinity
|
||||
timeRange: TimeRange | null = null
|
||||
) => {
|
||||
const initialDomain = useMemo(() => {
|
||||
if (storedDomain) {
|
||||
return storedDomain
|
||||
}
|
||||
|
||||
return getValidRange(data, startTime, endTime)
|
||||
return getValidRange(data, timeRange)
|
||||
}, [storedDomain, data])
|
||||
|
||||
const [domain, setDomain] = useOneWayState(initialDomain)
|
||||
|
|
|
@ -27,18 +27,18 @@ import {
|
|||
AppState,
|
||||
QueryViewProperties,
|
||||
TimeZone,
|
||||
TimeRange,
|
||||
Check,
|
||||
StatusRow,
|
||||
} from 'src/types'
|
||||
|
||||
// Selectors
|
||||
import {getEndTime, getStartTime} from 'src/timeMachine/selectors/index'
|
||||
import {getActiveTimeRange} from 'src/timeMachine/selectors/index'
|
||||
|
||||
interface StateProps {
|
||||
timeRange: TimeRange | null
|
||||
loading: RemoteDataState
|
||||
errorMessage: string
|
||||
endTime: number
|
||||
startTime: number
|
||||
files: string[]
|
||||
viewProperties: QueryViewProperties
|
||||
isInitialFetch: boolean
|
||||
|
@ -58,7 +58,7 @@ type Props = StateProps
|
|||
const TimeMachineVis: SFC<Props> = ({
|
||||
loading,
|
||||
errorMessage,
|
||||
endTime,
|
||||
timeRange,
|
||||
isInitialFetch,
|
||||
isViewingRawData,
|
||||
files,
|
||||
|
@ -69,7 +69,6 @@ const TimeMachineVis: SFC<Props> = ({
|
|||
yColumn,
|
||||
fillColumns,
|
||||
symbolColumns,
|
||||
startTime,
|
||||
timeZone,
|
||||
statuses,
|
||||
}) => {
|
||||
|
@ -113,12 +112,11 @@ const TimeMachineVis: SFC<Props> = ({
|
|||
) : (
|
||||
<ViewSwitcher
|
||||
giraffeResult={giraffeResult}
|
||||
endTime={endTime}
|
||||
timeRange={timeRange}
|
||||
files={files}
|
||||
loading={loading}
|
||||
properties={resolvedViewProperties}
|
||||
check={check}
|
||||
startTime={startTime}
|
||||
timeZone={timeZone}
|
||||
statuses={statuses}
|
||||
/>
|
||||
|
@ -166,8 +164,7 @@ const mstp = (state: AppState): StateProps => {
|
|||
fillColumns,
|
||||
symbolColumns,
|
||||
timeZone,
|
||||
startTime: getStartTime(timeRange),
|
||||
endTime: getEndTime(timeRange),
|
||||
timeRange: getActiveTimeRange(timeRange, viewProperties.queries),
|
||||
statuses,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import {
|
|||
|
||||
// Types
|
||||
import {
|
||||
DashboardQuery,
|
||||
FluxTable,
|
||||
QueryView,
|
||||
AppState,
|
||||
|
@ -290,3 +291,21 @@ export const getEndTime = (timeRange: TimeRange): number => {
|
|||
}
|
||||
return moment().valueOf()
|
||||
}
|
||||
|
||||
export const getActiveTimeRange = (
|
||||
timeRange: TimeRange,
|
||||
queries: DashboardQuery[]
|
||||
) => {
|
||||
if (!queries) {
|
||||
return timeRange
|
||||
}
|
||||
const hasVariableTimes = queries.some(
|
||||
query =>
|
||||
query.text.includes('v.timeRangeStart') ||
|
||||
query.text.includes('v.timeRangeStop')
|
||||
)
|
||||
if (hasVariableTimes) {
|
||||
return timeRange
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue