mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* Added RefreshButton * Added RefreshSelect * Added RefreshSelectButton * Added RefreshPicker * Removed the magic string Paused * Minor style changes and using Off instead of Pause * Added HeadlessSelect * Added HeadlessSelect story * Added SelectButton * Removed RefreshSelectButton * Added TimePicker and moved ClickOutsideWrapper to ui/components * Added TimePickerPopOver * Added react-calendar * Missed yarn lock file * Added inputs to popover * Added TimePicker and RefreshPicker to DashNav * Moved TimePicker and RefreshPicker to app/core * Added react-calendar to app and removed from ui/components * Fixed PopOver onClick * Moved everything back to ui components because of typings problems * Exporing RefreshPicker and TimePicker * Added Apply and inputs * Added typings * Added TimePickerInput and logic * Fixed parsing of string to Moments * Fixed range string * Styling and connecting the calendars and inputs * Changed Calendar styling * Added backward forward and zoom * Fixed responsive styles * Moved TimePicker and RefreshPicker into app core * Renamed menuIsOpen to isOpen * Changed from className={} to className="" * Moved Popover to TimePickerOptionGroup * Renamed all PopOver to Popover * Renamed popOver to popover and some minor refactorings * Renamed files with git mv * Added ButtonSelect and refactored RefreshPicker * Refactored TimePicker to use new ButtonSelect * Removed HeadlessSelect as suggested * fix: Fix typings and misc errors after rebase * wip: Enable time picker on dashboard and add tooltip * Merge branch 'master' into hugoh/new-timepicker-and-unified-component # Conflicts: # packages/grafana-ui/package.json # packages/grafana-ui/src/components/Input/Input.test.tsx # packages/grafana-ui/src/components/Input/Input.tsx # packages/grafana-ui/src/utils/validate.ts # public/app/features/dashboard/panel_editor/QueryOptions.tsx # yarn.lock * fix: Snapshot update * Move TimePicker default options into the TimePicker as statics, pass the tooltipContent down the line when wanted and wrap the button in a tooltip element * fix: Override internal state prop if we provide one in a prop * Updated snapshots * Let dashnav control refreshPicker state * feat: Add a stringToMs function * wip: RefreshPicker * wip: Move RefreshPicker to @grafana/ui * wip: Move TimePicker to @grafana/ui * wip: Remove comments * wip: Add refreshPicker to explore * wip: Use default intervals if the prop is missing * wip: Nicer way of setting defaults * fix: Control the select component * wip: Add onMoveForward/onMoveBack * Remove code related to the new time picker and refresh picker from dashnav * Fix: Typings after merge * chore: Minor fix after merge * chore: Remove _.map usage * chore: Moved refresh-picker logic out of the refresh picker since it will work a little differently in explore and dashboards until we have replaced the TimeSrv * feat: Add an Interval component to @grafana/ui * chore: Remove intervalId from redux state and move setInterval logic from ExploreToolbar to its own Interval component * feat: Add refreshInterval to Explore's URL state * feat: Pick up refreshInterval from url on page load * fix: Set default refreshInterval when no value can be retained from URL * fix: Update test initial state with refreshInterval * fix: Handle URLs before RefreshPicker * fix: Move RefreshInterval to url position 3 since the segments can take multiple positions * fix: A better way of detecting urls without RefreshInterval in Explore * chore: Some Explore typings * fix: Attach refresh picker to interval picker * chore: Sass fix for refresh button border radius * fix: Remove refreshInterval from URL * fix: Intervals now start when previous interval is finished * fix: Use clearTimeout instead of clearInterval * fix: Make sure there's a delay set before adding a timeout when we have slow explore queries * wip: Add refresh picker to dashboard * feat: Add util for removing keys with empty values * feat: RefreshPicker in dashboards and tmp rem out old RefreshPicker * fix: Remove the jumpy:ness in the refreshpicker * Changed placement and made it hide when your in dashboard settings * chore: Move logic related to refresh picker out of DashNav to its own component * feat: Add tooltip to refreshpicker * fix: Fix bug with refreshpicker not updating when setting to 'off' * fix: Make it possible to override refresh intervals using the dashboard intervals * chore: Change name of Interval to SetInterval to align with ecmascripts naming since its basically the same but declarative and async * fix: Use default intervals when auto refresh is empty in dashboard settings * fix: Hide time/interval picker when hidden is true on the model, such as on the home dashboard * fix: Interval picker will have to handle location changes since timeSrv wont * RefreshPicker: Refactoring refresh picker * RefreshPicker: minor refactoring
155 lines
3.8 KiB
TypeScript
155 lines
3.8 KiB
TypeScript
// @ts-ignore
|
|
import _ from 'lodash';
|
|
import moment from 'moment';
|
|
|
|
const units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
|
|
|
|
export type Timezone = 'utc';
|
|
|
|
/**
|
|
* Parses different types input to a moment instance. There is a specific formatting language that can be used
|
|
* if text arg is string. See unit tests for examples.
|
|
* @param text
|
|
* @param roundUp See parseDateMath function.
|
|
* @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used.
|
|
*/
|
|
export function parse(
|
|
text: string | moment.Moment | Date,
|
|
roundUp?: boolean,
|
|
timezone?: Timezone
|
|
): moment.Moment | undefined {
|
|
if (!text) {
|
|
return undefined;
|
|
}
|
|
|
|
if (typeof text !== 'string') {
|
|
if (moment.isMoment(text)) {
|
|
return text;
|
|
}
|
|
if (_.isDate(text)) {
|
|
return moment(text);
|
|
}
|
|
// We got some non string which is not a moment nor Date. TS should be able to check for that but not always.
|
|
return undefined;
|
|
} else {
|
|
let time;
|
|
let mathString = '';
|
|
let index;
|
|
let parseString;
|
|
|
|
if (text.substring(0, 3) === 'now') {
|
|
if (timezone === 'utc') {
|
|
time = moment.utc();
|
|
} else {
|
|
time = moment();
|
|
}
|
|
mathString = text.substring('now'.length);
|
|
} else {
|
|
index = text.indexOf('||');
|
|
if (index === -1) {
|
|
parseString = text;
|
|
mathString = ''; // nothing else
|
|
} else {
|
|
parseString = text.substring(0, index);
|
|
mathString = text.substring(index + 2);
|
|
}
|
|
// We're going to just require ISO8601 timestamps, k?
|
|
time = moment(parseString, moment.ISO_8601);
|
|
}
|
|
|
|
if (!mathString.length) {
|
|
return time;
|
|
}
|
|
|
|
return parseDateMath(mathString, time, roundUp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed
|
|
* by parse function. See parse function to see what is considered acceptable.
|
|
* @param text
|
|
*/
|
|
export function isValid(text: string | moment.Moment): boolean {
|
|
const date = parse(text);
|
|
if (!date) {
|
|
return false;
|
|
}
|
|
|
|
if (moment.isMoment(date)) {
|
|
return date.isValid();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples.
|
|
* @param mathString
|
|
* @param time
|
|
* @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit.
|
|
*/
|
|
// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any`
|
|
export function parseDateMath(mathString: string, time: any, roundUp?: boolean): moment.Moment | undefined {
|
|
const dateTime = time;
|
|
let i = 0;
|
|
const len = mathString.length;
|
|
|
|
while (i < len) {
|
|
const c = mathString.charAt(i++);
|
|
let type;
|
|
let num;
|
|
let unit;
|
|
|
|
if (c === '/') {
|
|
type = 0;
|
|
} else if (c === '+') {
|
|
type = 1;
|
|
} else if (c === '-') {
|
|
type = 2;
|
|
} else {
|
|
return undefined;
|
|
}
|
|
|
|
if (isNaN(parseInt(mathString.charAt(i), 10))) {
|
|
num = 1;
|
|
} else if (mathString.length === 2) {
|
|
num = mathString.charAt(i);
|
|
} else {
|
|
const numFrom = i;
|
|
while (!isNaN(parseInt(mathString.charAt(i), 10))) {
|
|
i++;
|
|
if (i > 10) {
|
|
return undefined;
|
|
}
|
|
}
|
|
num = parseInt(mathString.substring(numFrom, i), 10);
|
|
}
|
|
|
|
if (type === 0) {
|
|
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
|
|
if (num !== 1) {
|
|
return undefined;
|
|
}
|
|
}
|
|
unit = mathString.charAt(i++);
|
|
|
|
if (!_.includes(units, unit)) {
|
|
return undefined;
|
|
} else {
|
|
if (type === 0) {
|
|
if (roundUp) {
|
|
dateTime.endOf(unit);
|
|
} else {
|
|
dateTime.startOf(unit);
|
|
}
|
|
} else if (type === 1) {
|
|
dateTime.add(num, unit);
|
|
} else if (type === 2) {
|
|
dateTime.subtract(num, unit);
|
|
}
|
|
}
|
|
}
|
|
return dateTime;
|
|
}
|