From eefb8dd525d4cb2f5c76956374fa9f81ad90ecd1 Mon Sep 17 00:00:00 2001 From: Ariel Salem Date: Thu, 12 Dec 2019 10:29:09 -0800 Subject: [PATCH] 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 timeranges --- CHANGELOG.md | 1 + ui/src/shared/components/HeatmapPlot.tsx | 16 ++++--- ui/src/shared/components/RefreshingView.tsx | 34 +++++---------- ui/src/shared/components/ScatterPlot.tsx | 16 ++++--- ui/src/shared/components/ViewSwitcher.tsx | 19 +++----- ui/src/shared/components/XYPlot.tsx | 11 ++--- .../shared/utils/useVisDomainSettings.test.ts | 43 ++++++++++++++----- ui/src/shared/utils/useVisDomainSettings.ts | 16 ++++--- ui/src/timeMachine/components/Vis.tsx | 15 +++---- ui/src/timeMachine/selectors/index.ts | 19 ++++++++ 10 files changed, 109 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f29f1d131d6..619903c4523 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/ui/src/shared/components/HeatmapPlot.tsx b/ui/src/shared/components/HeatmapPlot.tsx index 92e0289ed77..87023609996 100644 --- a/ui/src/shared/components/HeatmapPlot.tsx +++ b/ui/src/shared/components/HeatmapPlot.tsx @@ -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 = ({ - endTime, loading, - startTime, + timeRange, table, timeZone, viewProperties: { @@ -56,8 +59,7 @@ const HeatmapPlot: FunctionComponent = ({ const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings( storedXDomain, table.getColumn(xColumn, 'number'), - startTime, - endTime + timeRange ) const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings( diff --git a/ui/src/shared/components/RefreshingView.tsx b/ui/src/shared/components/RefreshingView.tsx index f6229cb2c4a..eaee19a3b87 100644 --- a/ui/src/shared/components/RefreshingView.tsx +++ b/ui/src/shared/components/RefreshingView.tsx @@ -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 { } 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 { > @@ -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, diff --git a/ui/src/shared/components/ScatterPlot.tsx b/ui/src/shared/components/ScatterPlot.tsx index 02c68ada0d4..4688152f28d 100644 --- a/ui/src/shared/components/ScatterPlot.tsx +++ b/ui/src/shared/components/ScatterPlot.tsx @@ -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 = ({ children, - endTime, loading, - startTime, + timeRange, timeZone, table, viewProperties: { @@ -68,8 +71,7 @@ const ScatterPlot: FunctionComponent = ({ const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings( storedXDomain, table.getColumn(xColumn, 'number'), - startTime, - endTime + timeRange ) const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings( diff --git a/ui/src/shared/components/ViewSwitcher.tsx b/ui/src/shared/components/ViewSwitcher.tsx index e908661d6b8..008927e0d49 100644 --- a/ui/src/shared/components/ViewSwitcher.tsx +++ b/ui/src/shared/components/ViewSwitcher.tsx @@ -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 = ({ properties, check, loading, - endTime, + timeRange, files, giraffeResult: {table, fluxGroupKeyUnion}, - startTime, timeZone, statuses, }) => { @@ -83,10 +82,9 @@ const ViewSwitcher: FunctionComponent = ({ case 'xy': return ( = ({ return ( = ({ case 'heatmap': return ( = ({ case 'scatter': return ( 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 = ({ children, - endTime, fluxGroupKeyUnion, loading, - startTime, + timeRange, table, timeZone, viewProperties: { @@ -81,8 +79,7 @@ const XYPlot: FunctionComponent = ({ const [xDomain, onSetXDomain, onResetXDomain] = useVisDomainSettings( storedXDomain, table.getColumn(xColumn, 'number'), - startTime, - endTime + timeRange ) const [yDomain, onSetYDomain, onResetYDomain] = useVisDomainSettings( diff --git a/ui/src/shared/utils/useVisDomainSettings.test.ts b/ui/src/shared/utils/useVisDomainSettings.test.ts index 8b4e84fb6b0..4e35aeb7df8 100644 --- a/ui/src/shared/utils/useVisDomainSettings.test.ts +++ b/ui/src/shared/utils/useVisDomainSettings.test.ts @@ -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]]) }) }) diff --git a/ui/src/shared/utils/useVisDomainSettings.ts b/ui/src/shared/utils/useVisDomainSettings.ts index 096f611b2e2..0f1deebf40b 100644 --- a/ui/src/shared/utils/useVisDomainSettings.ts +++ b/ui/src/shared/utils/useVisDomainSettings.ts @@ -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) diff --git a/ui/src/timeMachine/components/Vis.tsx b/ui/src/timeMachine/components/Vis.tsx index d1fe3b0d9f6..57a170b0c9e 100644 --- a/ui/src/timeMachine/components/Vis.tsx +++ b/ui/src/timeMachine/components/Vis.tsx @@ -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 = ({ loading, errorMessage, - endTime, + timeRange, isInitialFetch, isViewingRawData, files, @@ -69,7 +69,6 @@ const TimeMachineVis: SFC = ({ yColumn, fillColumns, symbolColumns, - startTime, timeZone, statuses, }) => { @@ -113,12 +112,11 @@ const TimeMachineVis: SFC = ({ ) : ( @@ -166,8 +164,7 @@ const mstp = (state: AppState): StateProps => { fillColumns, symbolColumns, timeZone, - startTime: getStartTime(timeRange), - endTime: getEndTime(timeRange), + timeRange: getActiveTimeRange(timeRange, viewProperties.queries), statuses, } } diff --git a/ui/src/timeMachine/selectors/index.ts b/ui/src/timeMachine/selectors/index.ts index e2f9420ee26..bb8a21ff5e7 100644 --- a/ui/src/timeMachine/selectors/index.ts +++ b/ui/src/timeMachine/selectors/index.ts @@ -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 +}