From 30f98f38a7ebf871e9fbfcac33679da4554c3239 Mon Sep 17 00:00:00 2001 From: asalem Date: Wed, 6 May 2020 10:57:54 -0700 Subject: [PATCH 01/14] feat(tz-supported-queries): Integrated timeZone selection when executing a query with a custom timeRange Need to integrate this functionality for the queryBuilder --- ui/src/dashboards/selectors/index.ts | 6 ++++- ui/src/variables/selectors/index.tsx | 39 +++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index a789e8c4d2e..7779b6f8d08 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -1,6 +1,6 @@ import {get} from 'lodash' -import {AppState, View, Check, ViewType, TimeRange} from 'src/types' +import {AppState, View, Check, ViewType, TimeRange, TimeZone} from 'src/types' import {currentContext} from 'src/shared/selectors/currentContext' // Constants @@ -15,6 +15,10 @@ export const getTimeRange = (state: AppState): TimeRange => { return state.ranges[contextID] || DEFAULT_TIME_RANGE } +export const getTimeZone = (state: AppState): TimeZone => { + return state.app.persisted.timeZone || 'Local' +} + export const getCheckForView = ( state: AppState, view: View diff --git a/ui/src/variables/selectors/index.tsx b/ui/src/variables/selectors/index.tsx index 500ba8089a1..7c405c63086 100644 --- a/ui/src/variables/selectors/index.tsx +++ b/ui/src/variables/selectors/index.tsx @@ -4,7 +4,7 @@ import {get} from 'lodash' // Utils import {getActiveQuery} from 'src/timeMachine/selectors' import {getRangeVariable} from 'src/variables/utils/getTimeRangeVars' -import {getTimeRange} from 'src/dashboards/selectors' +import {getTimeRange, getTimeZone} from 'src/dashboards/selectors' import {getWindowPeriodVariable} from 'src/variables/utils/getWindowVars' import { TIME_RANGE_START, @@ -22,6 +22,7 @@ import { } from 'src/types' import {VariableAssignment} from 'src/types/ast' import {AppState, VariableArgumentType, Variable} from 'src/types' +import moment from 'moment' export const extractVariableEditorName = (state: AppState): string => { return state.variableEditor.name @@ -108,14 +109,36 @@ export const getAllVariables = ( .concat([TIME_RANGE_START, TIME_RANGE_STOP, WINDOW_PERIOD]) .reduce((prev, curr) => { prev.push(getVariable(state, curr)) - return prev }, []) .filter(v => !!v) - return vars } +const setTimeToUTC = (date: string): string => { + const offset = new Date(date).getTimezoneOffset() + // check if date has offset + if (offset === 0) { + return date + } + let offsetDate = date + if (offset > 0) { + // subtract tz minute difference + offsetDate = moment + .utc(date) + .subtract(offset, 'minutes') + .format() + } + if (offset < 0) { + // add tz minute difference + offsetDate = moment + .utc(date) + .add(offset, 'minutes') + .format() + } + return offsetDate +} + export const getVariable = (state: AppState, variableID: string): Variable => { const contextID = currentContext(state) const ctx = get(state, ['resources', 'variables', 'values', contextID]) @@ -127,8 +150,16 @@ export const getVariable = (state: AppState, variableID: string): Variable => { if (variableID === TIME_RANGE_START || variableID === TIME_RANGE_STOP) { const timeRange = getTimeRange(state) + const timeZone = getTimeZone(state) + // create a copy of the timeRange so as not to mutate the original timeRange + const newTimeRange = Object.assign({}, timeRange) + if (timeRange.type === 'custom' && timeZone === 'UTC') { + // check to see if the timeRange has an offset + newTimeRange.lower = setTimeToUTC(newTimeRange.lower) + newTimeRange.upper = setTimeToUTC(newTimeRange.upper) + } - vari = getRangeVariable(variableID, timeRange) + vari = getRangeVariable(variableID, newTimeRange) } if (variableID === WINDOW_PERIOD) { From e4043a82b546fea6313518dc70eaba2ca04f8d79 Mon Sep 17 00:00:00 2001 From: asalem Date: Wed, 6 May 2020 13:24:20 -0700 Subject: [PATCH 02/14] chore(getTimeZone): updated timeZone retrieval to use getTimeZone selector --- ui/src/checks/components/CheckHistory.tsx | 3 ++- ui/src/shared/components/TimeZoneDropdown.tsx | 5 ++-- ui/src/timeMachine/actions/queryBuilder.ts | 27 +++++++++++++++++-- ui/src/timeMachine/components/Vis.tsx | 4 +-- ui/src/variables/selectors/index.tsx | 2 +- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/ui/src/checks/components/CheckHistory.tsx b/ui/src/checks/components/CheckHistory.tsx index 9a33c2946cf..849f97cd387 100644 --- a/ui/src/checks/components/CheckHistory.tsx +++ b/ui/src/checks/components/CheckHistory.tsx @@ -21,6 +21,7 @@ import {STATUS_FIELDS} from 'src/alerting/constants/history' // Utils import {loadStatuses, getInitialState} from 'src/alerting/utils/history' import {getCheckIDs} from 'src/checks/selectors' +import {getTimeZone} from 'src/dashboards/selectors' // Types import {ResourceIDs} from 'src/checks/reducers' @@ -101,7 +102,7 @@ const CheckHistory: FC = ({ } const mstp = (state: AppState, props: OwnProps) => { - const timeZone = state.app.persisted.timeZone + const timeZone = getTimeZone(state) const checkIDs = getCheckIDs(state) const check = getByID(state, ResourceType.Checks, props.params.checkID) diff --git a/ui/src/shared/components/TimeZoneDropdown.tsx b/ui/src/shared/components/TimeZoneDropdown.tsx index 92680cb69f1..9fdace1d084 100644 --- a/ui/src/shared/components/TimeZoneDropdown.tsx +++ b/ui/src/shared/components/TimeZoneDropdown.tsx @@ -3,8 +3,9 @@ import React, {FunctionComponent} from 'react' import {connect} from 'react-redux' import {SelectDropdown, IconFont} from '@influxdata/clockface' -// Actions +// Actions & Selectors import {setTimeZone} from 'src/shared/actions/app' +import {getTimeZone} from 'src/dashboards/selectors' // Constants import {TIME_ZONES} from 'src/shared/constants/timeZones' @@ -38,7 +39,7 @@ const TimeZoneDropdown: FunctionComponent = ({ } const mstp = (state: AppState): StateProps => { - return {timeZone: state.app.persisted.timeZone || 'Local'} + return {timeZone: getTimeZone(state)} } const mdtp = {onSetTimeZone: setTimeZone} diff --git a/ui/src/timeMachine/actions/queryBuilder.ts b/ui/src/timeMachine/actions/queryBuilder.ts index ef9290babb8..023b574f0af 100644 --- a/ui/src/timeMachine/actions/queryBuilder.ts +++ b/ui/src/timeMachine/actions/queryBuilder.ts @@ -6,7 +6,8 @@ import {fetchDemoDataBuckets} from 'src/cloud/apis/demodata' // Utils import {getActiveQuery, getActiveTimeMachine} from 'src/timeMachine/selectors' -import {getTimeRange} from 'src/dashboards/selectors' +import {getTimeRange, getTimeZone} from 'src/dashboards/selectors' +import {setTimeToUTC} from 'src/variables/selectors' // Types import { @@ -219,6 +220,13 @@ export const loadTagSelector = (index: number) => async ( try { const timeRange = getTimeRange(state) + const timeZone = getTimeZone(state) + const newTimeRange = Object.assign({}, timeRange) + if (timeRange.type === 'custom' && timeZone === 'UTC') { + // check to see if the timeRange has an offset + newTimeRange.lower = setTimeToUTC(newTimeRange.lower) + newTimeRange.upper = setTimeToUTC(newTimeRange.upper) + } const searchTerm = getActiveTimeMachine(state).queryBuilder.tags[index] .keysSearchTerm @@ -267,6 +275,8 @@ const loadTagSelectorValues = (index: number) => async ( ) => { const state = getState() const {buckets, tags} = getActiveQuery(state).builderConfig + console.log('buckets: ', buckets) + console.log('tags: ', tags) const tagsSelections = tags.slice(0, index) const queryURL = state.links.query.self @@ -284,10 +294,20 @@ const loadTagSelectorValues = (index: number) => async ( try { const timeRange = getTimeRange(state) + const timeZone = getTimeZone(state) + const newTimeRange = Object.assign({}, timeRange) + if (timeRange.type === 'custom' && timeZone === 'UTC') { + // check to see if the timeRange has an offset + newTimeRange.lower = setTimeToUTC(newTimeRange.lower) + newTimeRange.upper = setTimeToUTC(newTimeRange.upper) + } const key = getActiveQuery(getState()).builderConfig.tags[index].key const searchTerm = getActiveTimeMachine(getState()).queryBuilder.tags[index] .valuesSearchTerm + console.log('key: ', key) + console.log('tagsSelections: ', tagsSelections) + const values = await queryBuilderFetcher.findValues(index, { url: queryURL, orgID, @@ -295,9 +315,11 @@ const loadTagSelectorValues = (index: number) => async ( tagsSelections, key, searchTerm, - timeRange, + newTimeRange, }) + console.log('values in the action: ', values) + const {values: selectedValues} = tags[index] for (const selectedValue of selectedValues) { @@ -363,6 +385,7 @@ export const selectBuilderFunction = (name: string) => ( dispatch: Dispatch, getState: GetState ) => { + console.log('does this trigger?') const state = getState() const { timeMachines: {activeTimeMachineID}, diff --git a/ui/src/timeMachine/components/Vis.tsx b/ui/src/timeMachine/components/Vis.tsx index 89cc5cc2702..fbc9e831f19 100644 --- a/ui/src/timeMachine/components/Vis.tsx +++ b/ui/src/timeMachine/components/Vis.tsx @@ -21,7 +21,7 @@ import { getFillColumnsSelection, getSymbolColumnsSelection, } from 'src/timeMachine/selectors' -import {getTimeRange} from 'src/dashboards/selectors' +import {getTimeRange, getTimeZone} from 'src/dashboards/selectors' // Types import { @@ -164,7 +164,7 @@ const mstp = (state: AppState): StateProps => { const fillColumns = getFillColumnsSelection(state) const symbolColumns = getSymbolColumnsSelection(state) - const timeZone = state.app.persisted.timeZone + const timeZone = getTimeZone(state) return { loading, diff --git a/ui/src/variables/selectors/index.tsx b/ui/src/variables/selectors/index.tsx index 7c405c63086..33147bd5266 100644 --- a/ui/src/variables/selectors/index.tsx +++ b/ui/src/variables/selectors/index.tsx @@ -115,7 +115,7 @@ export const getAllVariables = ( return vars } -const setTimeToUTC = (date: string): string => { +export const setTimeToUTC = (date: string): string => { const offset = new Date(date).getTimezoneOffset() // check if date has offset if (offset === 0) { From 0502df586f769dfac9e4331fdb36461f00d10384 Mon Sep 17 00:00:00 2001 From: asalem Date: Wed, 6 May 2020 14:08:45 -0700 Subject: [PATCH 03/14] feat(queryBuilder): integrated the timezone dropdown logic into the queryBuilder to correct set keys and values --- ui/src/timeMachine/actions/queryBuilder.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/ui/src/timeMachine/actions/queryBuilder.ts b/ui/src/timeMachine/actions/queryBuilder.ts index 023b574f0af..935e005802f 100644 --- a/ui/src/timeMachine/actions/queryBuilder.ts +++ b/ui/src/timeMachine/actions/queryBuilder.ts @@ -236,7 +236,7 @@ export const loadTagSelector = (index: number) => async ( bucket, tagsSelections, searchTerm, - timeRange, + timeRange: newTimeRange, }) const {key} = tags[index] @@ -275,8 +275,6 @@ const loadTagSelectorValues = (index: number) => async ( ) => { const state = getState() const {buckets, tags} = getActiveQuery(state).builderConfig - console.log('buckets: ', buckets) - console.log('tags: ', tags) const tagsSelections = tags.slice(0, index) const queryURL = state.links.query.self @@ -305,9 +303,6 @@ const loadTagSelectorValues = (index: number) => async ( const searchTerm = getActiveTimeMachine(getState()).queryBuilder.tags[index] .valuesSearchTerm - console.log('key: ', key) - console.log('tagsSelections: ', tagsSelections) - const values = await queryBuilderFetcher.findValues(index, { url: queryURL, orgID, @@ -315,11 +310,9 @@ const loadTagSelectorValues = (index: number) => async ( tagsSelections, key, searchTerm, - newTimeRange, + timeRange: newTimeRange, }) - console.log('values in the action: ', values) - const {values: selectedValues} = tags[index] for (const selectedValue of selectedValues) { @@ -385,7 +378,6 @@ export const selectBuilderFunction = (name: string) => ( dispatch: Dispatch, getState: GetState ) => { - console.log('does this trigger?') const state = getState() const { timeMachines: {activeTimeMachineID}, From 7b3b52cc6a5498111004ce9ee78d206abe6049f1 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 06:14:10 -0700 Subject: [PATCH 04/14] feat(selector_tests): refactored the previous implementation of setting custom timeRanges to UTC by creating a selector to handle that logic wrote tests to test the new selector --- ui/src/dashboards/selectors/index.test.ts | 66 ++++++++++++++++++++-- ui/src/dashboards/selectors/index.ts | 39 ++++++++++++- ui/src/timeMachine/actions/queryBuilder.ts | 26 ++------- ui/src/variables/selectors/index.tsx | 40 +------------ 4 files changed, 107 insertions(+), 64 deletions(-) diff --git a/ui/src/dashboards/selectors/index.test.ts b/ui/src/dashboards/selectors/index.test.ts index 0b4b1fb49b8..0bcd0898192 100644 --- a/ui/src/dashboards/selectors/index.test.ts +++ b/ui/src/dashboards/selectors/index.test.ts @@ -1,10 +1,14 @@ // Funcs -import {getTimeRange} from 'src/dashboards/selectors/index' +import { + getTimeRange, + getTimeRangeWithTimezone, +} from 'src/dashboards/selectors/index' // Types import {RangeState} from 'src/dashboards/reducers/ranges' import {CurrentDashboardState} from 'src/shared/reducers/currentDashboard' -import {TimeRange} from 'src/types' +import {TimeRange, CustomTimeRange} from 'src/types' +import {AppState as AppPresentationState} from 'src/shared/reducers/app' // Constants import { @@ -18,14 +22,30 @@ const untypedGetTimeRangeByDashboardID = getTimeRange as (a: { currentDashboard: CurrentDashboardState }) => TimeRange +const untypedGetTimeRangeWithTimeZone = getTimeRangeWithTimezone as (a: { + ranges: RangeState + currentDashboard: CurrentDashboardState + app: AppPresentationState +}) => TimeRange + describe('Dashboards.Selector', () => { - const dashboardIDs = ['04c6f3976f4b8001', '04c6f3976f4b8000'] + const dashboardIDs = [ + '04c6f3976f4b8001', + '04c6f3976f4b8000', + '04c6f3976f4b8002', + ] + const customTimeRange = { + lower: '2020-05-05T10:00:00-07:00', + upper: '2020-05-05T11:00:00-07:00', + type: 'custom', + } as CustomTimeRange const ranges: RangeState = { [dashboardIDs[0]]: pastFifteenMinTimeRange, [dashboardIDs[1]]: pastHourTimeRange, + [dashboardIDs[2]]: customTimeRange, } - it('should return the the correct range when a matching dashboard ID is found', () => { + it('should return the correct range when a matching dashboard ID is found', () => { const currentDashboard = {id: dashboardIDs[0]} expect( @@ -33,7 +53,7 @@ describe('Dashboards.Selector', () => { ).toEqual(pastFifteenMinTimeRange) }) - it('should return the the default range when no matching dashboard ID is found', () => { + it('should return the default range when no matching dashboard ID is found', () => { const currentDashboard = {id: 'Oogum Boogum'} expect( @@ -41,11 +61,45 @@ describe('Dashboards.Selector', () => { ).toEqual(DEFAULT_TIME_RANGE) }) - it('should return the the default range when no ranges are passed in', () => { + it('should return the default range when no ranges are passed in', () => { const currentDashboard = {id: dashboardIDs[0]} expect( untypedGetTimeRangeByDashboardID({ranges: {}, currentDashboard}) ).toEqual(DEFAULT_TIME_RANGE) }) + + it('should return the an unmodified version of the timeRange when the timeZone is local', () => { + const currentDashboard = {id: dashboardIDs[2]} + + const app = { + persisted: { + timeZone: 'Local', + }, + } as AppPresentationState + + expect( + untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) + ).toEqual(customTimeRange) + }) + + it('should return the timeRange for the same hour with a UTC timezone when the timeZone is UTC', () => { + const currentDashboard = {id: dashboardIDs[2]} + + const app = { + persisted: { + timeZone: 'UTC', + }, + } as AppPresentationState + + const expected = { + lower: '2020-05-05T10:00:00Z', + upper: '2020-05-05T11:00:00Z', + type: 'custom', + } + + expect( + untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) + ).toEqual(expected) + }) }) diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index 7779b6f8d08..6ff0b1374b6 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -1,5 +1,5 @@ import {get} from 'lodash' - +import moment from 'moment' import {AppState, View, Check, ViewType, TimeRange, TimeZone} from 'src/types' import {currentContext} from 'src/shared/selectors/currentContext' @@ -15,6 +15,43 @@ export const getTimeRange = (state: AppState): TimeRange => { return state.ranges[contextID] || DEFAULT_TIME_RANGE } +export const getTimeRangeWithTimezone = (state: AppState): TimeRange => { + const timeRange = getTimeRange(state) + const timeZone = getTimeZone(state) + // create a copy of the timeRange so as not to mutate the original timeRange + const newTimeRange = Object.assign({}, timeRange) + if (timeRange.type === 'custom' && timeZone === 'UTC') { + // check to see if the timeRange has an offset + newTimeRange.lower = setTimeToUTC(newTimeRange.lower) + newTimeRange.upper = setTimeToUTC(newTimeRange.upper) + } + return newTimeRange +} + +export const setTimeToUTC = (date: string): string => { + const offset = new Date(date).getTimezoneOffset() + // check if date has offset + if (offset === 0) { + return date + } + let offsetDate = date + if (offset > 0) { + // subtract tz minute difference + offsetDate = moment + .utc(date) + .subtract(offset, 'minutes') + .format() + } + if (offset < 0) { + // add tz minute difference + offsetDate = moment + .utc(date) + .add(offset, 'minutes') + .format() + } + return offsetDate +} + export const getTimeZone = (state: AppState): TimeZone => { return state.app.persisted.timeZone || 'Local' } diff --git a/ui/src/timeMachine/actions/queryBuilder.ts b/ui/src/timeMachine/actions/queryBuilder.ts index 935e005802f..19e02c0f095 100644 --- a/ui/src/timeMachine/actions/queryBuilder.ts +++ b/ui/src/timeMachine/actions/queryBuilder.ts @@ -6,8 +6,7 @@ import {fetchDemoDataBuckets} from 'src/cloud/apis/demodata' // Utils import {getActiveQuery, getActiveTimeMachine} from 'src/timeMachine/selectors' -import {getTimeRange, getTimeZone} from 'src/dashboards/selectors' -import {setTimeToUTC} from 'src/variables/selectors' +import {getTimeRangeWithTimezone} from 'src/dashboards/selectors' // Types import { @@ -219,14 +218,8 @@ export const loadTagSelector = (index: number) => async ( const orgID = get(foundBucket, 'orgID', getOrg(getState()).id) try { - const timeRange = getTimeRange(state) - const timeZone = getTimeZone(state) - const newTimeRange = Object.assign({}, timeRange) - if (timeRange.type === 'custom' && timeZone === 'UTC') { - // check to see if the timeRange has an offset - newTimeRange.lower = setTimeToUTC(newTimeRange.lower) - newTimeRange.upper = setTimeToUTC(newTimeRange.upper) - } + const timeRange = getTimeRangeWithTimezone(state) + const searchTerm = getActiveTimeMachine(state).queryBuilder.tags[index] .keysSearchTerm @@ -236,7 +229,7 @@ export const loadTagSelector = (index: number) => async ( bucket, tagsSelections, searchTerm, - timeRange: newTimeRange, + timeRange, }) const {key} = tags[index] @@ -291,14 +284,7 @@ const loadTagSelectorValues = (index: number) => async ( dispatch(setBuilderTagValuesStatus(index, RemoteDataState.Loading)) try { - const timeRange = getTimeRange(state) - const timeZone = getTimeZone(state) - const newTimeRange = Object.assign({}, timeRange) - if (timeRange.type === 'custom' && timeZone === 'UTC') { - // check to see if the timeRange has an offset - newTimeRange.lower = setTimeToUTC(newTimeRange.lower) - newTimeRange.upper = setTimeToUTC(newTimeRange.upper) - } + const timeRange = getTimeRangeWithTimezone(state) const key = getActiveQuery(getState()).builderConfig.tags[index].key const searchTerm = getActiveTimeMachine(getState()).queryBuilder.tags[index] .valuesSearchTerm @@ -310,7 +296,7 @@ const loadTagSelectorValues = (index: number) => async ( tagsSelections, key, searchTerm, - timeRange: newTimeRange, + timeRange, }) const {values: selectedValues} = tags[index] diff --git a/ui/src/variables/selectors/index.tsx b/ui/src/variables/selectors/index.tsx index 33147bd5266..cf553c18038 100644 --- a/ui/src/variables/selectors/index.tsx +++ b/ui/src/variables/selectors/index.tsx @@ -4,7 +4,7 @@ import {get} from 'lodash' // Utils import {getActiveQuery} from 'src/timeMachine/selectors' import {getRangeVariable} from 'src/variables/utils/getTimeRangeVars' -import {getTimeRange, getTimeZone} from 'src/dashboards/selectors' +import {getTimeRange, getTimeRangeWithTimezone} from 'src/dashboards/selectors' import {getWindowPeriodVariable} from 'src/variables/utils/getWindowVars' import { TIME_RANGE_START, @@ -22,7 +22,6 @@ import { } from 'src/types' import {VariableAssignment} from 'src/types/ast' import {AppState, VariableArgumentType, Variable} from 'src/types' -import moment from 'moment' export const extractVariableEditorName = (state: AppState): string => { return state.variableEditor.name @@ -115,30 +114,6 @@ export const getAllVariables = ( return vars } -export const setTimeToUTC = (date: string): string => { - const offset = new Date(date).getTimezoneOffset() - // check if date has offset - if (offset === 0) { - return date - } - let offsetDate = date - if (offset > 0) { - // subtract tz minute difference - offsetDate = moment - .utc(date) - .subtract(offset, 'minutes') - .format() - } - if (offset < 0) { - // add tz minute difference - offsetDate = moment - .utc(date) - .add(offset, 'minutes') - .format() - } - return offsetDate -} - export const getVariable = (state: AppState, variableID: string): Variable => { const contextID = currentContext(state) const ctx = get(state, ['resources', 'variables', 'values', contextID]) @@ -149,17 +124,8 @@ export const getVariable = (state: AppState, variableID: string): Variable => { } if (variableID === TIME_RANGE_START || variableID === TIME_RANGE_STOP) { - const timeRange = getTimeRange(state) - const timeZone = getTimeZone(state) - // create a copy of the timeRange so as not to mutate the original timeRange - const newTimeRange = Object.assign({}, timeRange) - if (timeRange.type === 'custom' && timeZone === 'UTC') { - // check to see if the timeRange has an offset - newTimeRange.lower = setTimeToUTC(newTimeRange.lower) - newTimeRange.upper = setTimeToUTC(newTimeRange.upper) - } - - vari = getRangeVariable(variableID, newTimeRange) + const timeRange = getTimeRangeWithTimezone(state) + vari = getRangeVariable(variableID, timeRange) } if (variableID === WINDOW_PERIOD) { From 7f3240e1d5e49005a5065851e8af17c95708a10b Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 06:26:38 -0700 Subject: [PATCH 05/14] chore(CHANGELOG): updated the CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 814b35ead49..20a4d6ce780 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features 1. [17934](https://github.com/influxdata/influxdb/pull/17934): Add ability to delete a stack and all the resources associated with it +1. [17992](https://github.com/influxdata/influxdb/pull/17992): Add ability to specify UTC when making custom time range queries ### Bug Fixes From 2f501dcffc8bce13b4142a8c9d2d38dce37c609c Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 06:37:19 -0700 Subject: [PATCH 06/14] fix(variablesMock): updated variables mock to include app.persisted.timeZone in AppState mock --- ui/src/variables/selectors/index.test.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/src/variables/selectors/index.test.tsx b/ui/src/variables/selectors/index.test.tsx index 7f8b33eb908..eb37d7e8c21 100644 --- a/ui/src/variables/selectors/index.test.tsx +++ b/ui/src/variables/selectors/index.test.tsx @@ -7,6 +7,11 @@ import { import {AppState} from 'src/types' const MOCKSTATE = ({ + app: { + persisted: { + timeZone: 'Local', + }, + }, currentDashboard: { id: '', }, From 08d5fff4f143528d1b04e41993632a30185a074e Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 08:36:17 -0700 Subject: [PATCH 07/14] fix(test): this commit is a test of the the circle test failure --- ui/src/dashboards/selectors/index.test.ts | 9 +++++---- ui/src/variables/selectors/index.test.tsx | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/src/dashboards/selectors/index.test.ts b/ui/src/dashboards/selectors/index.test.ts index 0bcd0898192..3684ae5ad98 100644 --- a/ui/src/dashboards/selectors/index.test.ts +++ b/ui/src/dashboards/selectors/index.test.ts @@ -8,7 +8,7 @@ import { import {RangeState} from 'src/dashboards/reducers/ranges' import {CurrentDashboardState} from 'src/shared/reducers/currentDashboard' import {TimeRange, CustomTimeRange} from 'src/types' -import {AppState as AppPresentationState} from 'src/shared/reducers/app' +import {AppState} from 'src/shared/reducers/app' // Constants import { @@ -25,7 +25,7 @@ const untypedGetTimeRangeByDashboardID = getTimeRange as (a: { const untypedGetTimeRangeWithTimeZone = getTimeRangeWithTimezone as (a: { ranges: RangeState currentDashboard: CurrentDashboardState - app: AppPresentationState + app: AppState }) => TimeRange describe('Dashboards.Selector', () => { @@ -76,7 +76,7 @@ describe('Dashboards.Selector', () => { persisted: { timeZone: 'Local', }, - } as AppPresentationState + } as AppState expect( untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) @@ -90,7 +90,7 @@ describe('Dashboards.Selector', () => { persisted: { timeZone: 'UTC', }, - } as AppPresentationState + } as AppState const expected = { lower: '2020-05-05T10:00:00Z', @@ -98,6 +98,7 @@ describe('Dashboards.Selector', () => { type: 'custom', } + expect(app.persisted.timeZone).toEqual('UTC') expect( untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) ).toEqual(expected) diff --git a/ui/src/variables/selectors/index.test.tsx b/ui/src/variables/selectors/index.test.tsx index eb37d7e8c21..e1fdbd332e7 100644 --- a/ui/src/variables/selectors/index.test.tsx +++ b/ui/src/variables/selectors/index.test.tsx @@ -9,7 +9,7 @@ import {AppState} from 'src/types' const MOCKSTATE = ({ app: { persisted: { - timeZone: 'Local', + timeZone: 'UTC', }, }, currentDashboard: { From 66012ab518abe9c23f7f6240c3220635baad8e04 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 11:56:45 -0700 Subject: [PATCH 08/14] feat(getTimeRangeWithTimeZone): updated to account for PR suggestions. Update the .circleci config file to set the timezone --- ui/src/dashboards/selectors/index.test.ts | 1 - ui/src/dashboards/selectors/index.ts | 24 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ui/src/dashboards/selectors/index.test.ts b/ui/src/dashboards/selectors/index.test.ts index 3684ae5ad98..cb37a7e4035 100644 --- a/ui/src/dashboards/selectors/index.test.ts +++ b/ui/src/dashboards/selectors/index.test.ts @@ -98,7 +98,6 @@ describe('Dashboards.Selector', () => { type: 'custom', } - expect(app.persisted.timeZone).toEqual('UTC') expect( untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) ).toEqual(expected) diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index 6ff0b1374b6..876005d7a75 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -18,10 +18,10 @@ export const getTimeRange = (state: AppState): TimeRange => { export const getTimeRangeWithTimezone = (state: AppState): TimeRange => { const timeRange = getTimeRange(state) const timeZone = getTimeZone(state) - // create a copy of the timeRange so as not to mutate the original timeRange - const newTimeRange = Object.assign({}, timeRange) + + const newTimeRange = {...timeRange} if (timeRange.type === 'custom' && timeZone === 'UTC') { - // check to see if the timeRange has an offset + // conforms dates to account to UTC with proper offset if needed newTimeRange.lower = setTimeToUTC(newTimeRange.lower) newTimeRange.upper = setTimeToUTC(newTimeRange.upper) } @@ -29,27 +29,29 @@ export const getTimeRangeWithTimezone = (state: AppState): TimeRange => { } export const setTimeToUTC = (date: string): string => { + // The purpose of this function is to set a user's custom time range selection + // from the local time to the same time in UTC if UTC is selected from the + // timezone dropdown. This is feature was original requested here: + // https://github.com/influxdata/influxdb/issues/17877 + // Example: user selected 10-11:00am and sets the dropdown to UTC + // Query should run against 10-11:00am UTC rather than querying + // 10-11:00am local time (offset depending on timezone) const offset = new Date(date).getTimezoneOffset() - // check if date has offset - if (offset === 0) { - return date - } - let offsetDate = date if (offset > 0) { // subtract tz minute difference - offsetDate = moment + return moment .utc(date) .subtract(offset, 'minutes') .format() } if (offset < 0) { // add tz minute difference - offsetDate = moment + return moment .utc(date) .add(offset, 'minutes') .format() } - return offsetDate + return date } export const getTimeZone = (state: AppState): TimeZone => { From 13f38e0b347cb8eecc7007e0d440c14b4134b4f4 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 12:01:57 -0700 Subject: [PATCH 09/14] revert(config): reverted config changes to see if tests fail. Also updated mockState to see whether the test failures happen differently --- ui/src/mockState.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/mockState.tsx b/ui/src/mockState.tsx index e9528524178..58e4b524e9c 100644 --- a/ui/src/mockState.tsx +++ b/ui/src/mockState.tsx @@ -21,7 +21,7 @@ export const localState: LocalStorage = { autoRefresh: 0, showTemplateControlBar: false, navBarState: 'expanded', - timeZone: 'Local' as TimeZone, + timeZone: 'UTC' as TimeZone, theme: 'dark', }, }, From 810128ec64cd8d7f62c6f6596ead656881211881 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 13:06:52 -0700 Subject: [PATCH 10/14] chore(test): making slight updates for testing CircleCI --- ui/src/dashboards/selectors/index.test.ts | 34 ++++++++++++++++------- ui/src/dashboards/selectors/index.ts | 2 ++ ui/src/mockState.tsx | 2 +- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/ui/src/dashboards/selectors/index.test.ts b/ui/src/dashboards/selectors/index.test.ts index cb37a7e4035..75a6a6895cb 100644 --- a/ui/src/dashboards/selectors/index.test.ts +++ b/ui/src/dashboards/selectors/index.test.ts @@ -7,8 +7,8 @@ import { // Types import {RangeState} from 'src/dashboards/reducers/ranges' import {CurrentDashboardState} from 'src/shared/reducers/currentDashboard' -import {TimeRange, CustomTimeRange} from 'src/types' -import {AppState} from 'src/shared/reducers/app' +import {TimeRange, TimeZone, CustomTimeRange} from 'src/types' +import {AppState as AppPresentationState} from 'src/shared/reducers/app' // Constants import { @@ -16,6 +16,7 @@ import { pastFifteenMinTimeRange, pastHourTimeRange, } from 'src/shared/constants/timeRanges' +import appReducer from 'src/shared/reducers/app' const untypedGetTimeRangeByDashboardID = getTimeRange as (a: { ranges: RangeState @@ -25,7 +26,7 @@ const untypedGetTimeRangeByDashboardID = getTimeRange as (a: { const untypedGetTimeRangeWithTimeZone = getTimeRangeWithTimezone as (a: { ranges: RangeState currentDashboard: CurrentDashboardState - app: AppState + app: AppPresentationState }) => TimeRange describe('Dashboards.Selector', () => { @@ -71,12 +72,18 @@ describe('Dashboards.Selector', () => { it('should return the an unmodified version of the timeRange when the timeZone is local', () => { const currentDashboard = {id: dashboardIDs[2]} - - const app = { + const app: AppPresentationState = { + ephemeral: { + inPresentationMode: false, + }, persisted: { - timeZone: 'Local', + autoRefresh: 0, + showTemplateControlBar: false, + navBarState: 'expanded', + timeZone: 'Local' as TimeZone, + theme: 'dark', }, - } as AppState + } expect( untypedGetTimeRangeWithTimeZone({ranges, currentDashboard, app}) @@ -86,11 +93,18 @@ describe('Dashboards.Selector', () => { it('should return the timeRange for the same hour with a UTC timezone when the timeZone is UTC', () => { const currentDashboard = {id: dashboardIDs[2]} - const app = { + const app: AppPresentationState = { + ephemeral: { + inPresentationMode: false, + }, persisted: { - timeZone: 'UTC', + autoRefresh: 0, + showTemplateControlBar: false, + navBarState: 'expanded', + timeZone: 'UTC' as TimeZone, + theme: 'dark', }, - } as AppState + } const expected = { lower: '2020-05-05T10:00:00Z', diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index 876005d7a75..912e1c0afd4 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -20,6 +20,8 @@ export const getTimeRangeWithTimezone = (state: AppState): TimeRange => { const timeZone = getTimeZone(state) const newTimeRange = {...timeRange} + console.log('timeZone: ', timeZone) + console.log('timeRange: ', timeRange) if (timeRange.type === 'custom' && timeZone === 'UTC') { // conforms dates to account to UTC with proper offset if needed newTimeRange.lower = setTimeToUTC(newTimeRange.lower) diff --git a/ui/src/mockState.tsx b/ui/src/mockState.tsx index 58e4b524e9c..e9528524178 100644 --- a/ui/src/mockState.tsx +++ b/ui/src/mockState.tsx @@ -21,7 +21,7 @@ export const localState: LocalStorage = { autoRefresh: 0, showTemplateControlBar: false, navBarState: 'expanded', - timeZone: 'UTC' as TimeZone, + timeZone: 'Local' as TimeZone, theme: 'dark', }, }, From 0cdabe75d64a0dec91f8686fd0e59a7d1d4595cf Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 13:20:18 -0700 Subject: [PATCH 11/14] chore(log): added a log to test assumtions --- .circleci/config.yml | 2 +- ui/src/dashboards/selectors/index.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d1440e57996..a70db126724 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -494,7 +494,7 @@ workflows: hourly-e2e: triggers: - schedule: - cron: '0 * * * *' + cron: "0 * * * *" filters: branches: only: diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index 912e1c0afd4..341d3fd05f3 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -20,8 +20,6 @@ export const getTimeRangeWithTimezone = (state: AppState): TimeRange => { const timeZone = getTimeZone(state) const newTimeRange = {...timeRange} - console.log('timeZone: ', timeZone) - console.log('timeRange: ', timeRange) if (timeRange.type === 'custom' && timeZone === 'UTC') { // conforms dates to account to UTC with proper offset if needed newTimeRange.lower = setTimeToUTC(newTimeRange.lower) @@ -39,6 +37,7 @@ export const setTimeToUTC = (date: string): string => { // Query should run against 10-11:00am UTC rather than querying // 10-11:00am local time (offset depending on timezone) const offset = new Date(date).getTimezoneOffset() + console.log('offset: ', offset) if (offset > 0) { // subtract tz minute difference return moment From 144be471972541762d26d2205bbf8ea385b5f432 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 13:37:47 -0700 Subject: [PATCH 12/14] feat(circleci): updated the config to set timezone --- .circleci/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index a70db126724..11ca074c6bc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -159,6 +159,10 @@ jobs: jstest: docker: - image: circleci/golang:1.13-node-browsers + environment: + TZ: "America/Los_Angeles" + environment: + TZ: "America/Los_Angeles" working_directory: /go/src/github.com/influxdata/influxdb parallelism: 8 steps: From ab2e6cefe3fd036fa8a0270ec8ac4cd894c025b5 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 13:54:37 -0700 Subject: [PATCH 13/14] chore(console.log): removed console.log from selector --- ui/src/dashboards/selectors/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/dashboards/selectors/index.ts b/ui/src/dashboards/selectors/index.ts index 341d3fd05f3..876005d7a75 100644 --- a/ui/src/dashboards/selectors/index.ts +++ b/ui/src/dashboards/selectors/index.ts @@ -37,7 +37,6 @@ export const setTimeToUTC = (date: string): string => { // Query should run against 10-11:00am UTC rather than querying // 10-11:00am local time (offset depending on timezone) const offset = new Date(date).getTimezoneOffset() - console.log('offset: ', offset) if (offset > 0) { // subtract tz minute difference return moment From 5e49da9625e4213d241936acc9d736b5923a6053 Mon Sep 17 00:00:00 2001 From: asalem Date: Thu, 7 May 2020 14:01:00 -0700 Subject: [PATCH 14/14] fix(lint): removed unused appReducer from test suite --- ui/src/dashboards/selectors/index.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/dashboards/selectors/index.test.ts b/ui/src/dashboards/selectors/index.test.ts index 75a6a6895cb..617a76d29d0 100644 --- a/ui/src/dashboards/selectors/index.test.ts +++ b/ui/src/dashboards/selectors/index.test.ts @@ -16,7 +16,6 @@ import { pastFifteenMinTimeRange, pastHourTimeRange, } from 'src/shared/constants/timeRanges' -import appReducer from 'src/shared/reducers/app' const untypedGetTimeRangeByDashboardID = getTimeRange as (a: { ranges: RangeState