diff --git a/CHANGELOG.md b/CHANGELOG.md index 264c58312..1ffe3ff93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ NOTE: As semantic versioning states all 0.y.z releases can contain breaking chan ### Fixed - [#1](https://github.com/kobsio/kobs/pull/1): Fix mobile layout for the cluster and namespace filter by using a Toolbar instead of FlexItems. +- [#9](https://github.com/kobsio/kobs/pull/9): Fix time parsing for the datasource options. ### Changed diff --git a/app/src/app.css b/app/src/app.css index e24e04ba0..0db6a66f6 100644 --- a/app/src/app.css +++ b/app/src/app.css @@ -63,8 +63,12 @@ width: 100%; } -/* kobsio-options-list-item - * Apply some padding between the list items for smaller screens. */ +/* kobsio-options-list + * Do not center the items vertically and apply some padding between the list items for smaller screens. */ +.kobsio-options-list { + align-items: flex-start; +} + .kobsio-options-list-item { padding-bottom: 16px; } diff --git a/app/src/components/applications/details/metrics/Options.tsx b/app/src/components/applications/details/metrics/Options.tsx index 872dc5a69..bc0834f97 100644 --- a/app/src/components/applications/details/metrics/Options.tsx +++ b/app/src/components/applications/details/metrics/Options.tsx @@ -11,7 +11,7 @@ import { SimpleListItem, TextInput, } from '@patternfly/react-core'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { IDatasourceOptions } from 'utils/proto'; import { formatTime } from 'utils/helpers'; @@ -25,20 +25,30 @@ interface IOptionsProps { // Options is the component, where the user can select various options for the current view. The user can select a time // range for all queries via the quick select option or he can specify a start and end time via the input fields. Later // we can also display datasource specific options within the modal component. -const Options: React.FunctionComponent = ({ options, setOptions }: IOptionsProps) => { +const Options: React.FunctionComponent = ({ type, options, setOptions }: IOptionsProps) => { const [show, setShow] = useState(false); const [timeStart, setTimeStart] = useState(formatTime(options.timeStart)); const [timeEnd, setTimeEnd] = useState(formatTime(options.timeEnd)); const [timeStartError, setTimeStartError] = useState(''); const [timeEndError, setTimeEndError] = useState(''); + const [resolution, setResolution] = useState(options.resolution); + // apply parses the value of the start and end input fields. If the user provided a correct data/time format, we // change the start and end time to the new values. If the string couldn't be parsed, the user will see an error below // the corresponding input field. const apply = (): void => { + // Get a new date object for the users current timezone. This allows us to ignore the timezone, while parsing the + // provided time string. The parsed date object will be in UTC, to transform the parsed date into the users timezone + // we have to add the minutes between UTC and the users timezon (getTimezoneOffset()). + const d = new Date(); + const parsedTimeStart = new Date(timeStart.replace(' ', 'T') + 'Z'); const parsedTimeEnd = new Date(timeEnd.replace(' ', 'T') + 'Z'); + parsedTimeStart.setMinutes(parsedTimeStart.getMinutes() + d.getTimezoneOffset()); + parsedTimeEnd.setMinutes(parsedTimeEnd.getMinutes() + d.getTimezoneOffset()); + if (parsedTimeStart.toString() === 'Invalid Date') { setTimeStartError('Invalid time format.'); setTimeEndError(''); @@ -50,8 +60,9 @@ const Options: React.FunctionComponent = ({ options, setOptions } setTimeEndError(''); setOptions({ ...options, - timeEnd: parsedTimeStart.getTime() / 1000, - timeStart: parsedTimeStart.getTime() / 1000, + resolution: resolution, + timeEnd: Math.floor(parsedTimeEnd.getTime() / 1000), + timeStart: Math.floor(parsedTimeStart.getTime() / 1000), }); setShow(false); } @@ -62,12 +73,21 @@ const Options: React.FunctionComponent = ({ options, setOptions } const quick = (seconds: number): void => { setOptions({ ...options, + resolution: resolution, timeEnd: Math.floor(Date.now() / 1000), timeStart: Math.floor(Date.now() / 1000) - seconds, }); setShow(false); }; + // useEffect is used to update the UI, every time a dasource options changes. + useEffect(() => { + setTimeStart(formatTime(options.timeStart)); + setTimeEnd(formatTime(options.timeEnd)); + + setResolution(options.resolution); + }, [options.timeEnd, options.timeStart, options.resolution]); + return ( , ]} > - +
= ({ options, setOptions } label="End Time" isRequired={false} fieldId="options-time-end" - helperTextInvalid="Age has to be a number" + helperTextInvalid={timeEndError} validated={timeEndError ? 'error' : undefined} > = ({ options, setOptions } quick(31536000)}>Last 1 Year + {type === 'prometheus' ? ( + + + + setResolution(value)} + /> + + + + ) : null}