Explore & Dashboard: New Refresh picker (#16505)

* 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
This commit is contained in:
Johannes Schill
2019-04-16 09:15:23 +02:00
committed by Torkel Ödegaard
parent d23f50ab23
commit 406ef962fc
59 changed files with 2554 additions and 540 deletions

View File

@@ -22,6 +22,7 @@ import {
import { updateLocation } from 'app/core/actions';
// Types
import { ResultGetter } from 'app/types/explore';
import { ThunkResult } from 'app/types';
import {
RawTimeRange,
@@ -44,6 +45,8 @@ import {
import {
updateDatasourceInstanceAction,
changeQueryAction,
changeRefreshIntervalAction,
ChangeRefreshIntervalPayload,
changeSizeAction,
ChangeSizePayload,
changeTimeAction,
@@ -164,7 +167,7 @@ export function changeSize(
}
/**
* Change the time range of Explore. Usually called from the Timepicker or a graph interaction.
* Change the time range of Explore. Usually called from the Time picker or a graph interaction.
*/
export function changeTime(exploreId: ExploreId, range: TimeRange): ThunkResult<void> {
return dispatch => {
@@ -173,6 +176,16 @@ export function changeTime(exploreId: ExploreId, range: TimeRange): ThunkResult<
};
}
/**
* Change the refresh interval of Explore. Called from the Refresh picker.
*/
export function changeRefreshInterval(
exploreId: ExploreId,
refreshInterval: string
): ActionOf<ChangeRefreshIntervalPayload> {
return changeRefreshIntervalAction({ exploreId, refreshInterval });
}
/**
* Clear all queries and results.
*/
@@ -526,7 +539,7 @@ export function queryTransactionSuccess(
/**
* Main action to run queries and dispatches sub-actions based on which result viewers are active
*/
export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkResult<void> {
export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkResult<Promise<any>> {
return (dispatch, getState) => {
const {
datasourceInstance,
@@ -543,13 +556,13 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
if (datasourceError) {
// let's not run any queries if data source is in a faulty state
return;
return Promise.resolve();
}
if (!hasNonEmptyQuery(queries)) {
dispatch(clearQueriesAction({ exploreId }));
dispatch(stateSave()); // Remember to saves to state and update location
return;
return Promise.resolve();
}
// Some datasource's query builders allow per-query interval limits,
@@ -558,41 +571,46 @@ export function runQueries(exploreId: ExploreId, ignoreUIState = false): ThunkRe
dispatch(runQueriesAction({ exploreId }));
// Keep table queries first since they need to return quickly
if ((ignoreUIState || showingTable) && supportsTable) {
dispatch(
runQueriesForType(
exploreId,
'Table',
{
interval,
format: 'table',
instant: true,
valueWithRefId: true,
},
(data: any) => data[0]
)
);
}
if ((ignoreUIState || showingGraph) && supportsGraph) {
dispatch(
runQueriesForType(
exploreId,
'Graph',
{
interval,
format: 'time_series',
instant: false,
maxDataPoints: containerWidth,
},
makeTimeSeriesList
)
);
}
if ((ignoreUIState || showingLogs) && supportsLogs) {
dispatch(runQueriesForType(exploreId, 'Logs', { interval, format: 'logs' }));
}
const tableQueriesPromise =
(ignoreUIState || showingTable) && supportsTable
? dispatch(
runQueriesForType(
exploreId,
'Table',
{
interval,
format: 'table',
instant: true,
valueWithRefId: true,
},
(data: any[]) => data[0]
)
)
: undefined;
const typeQueriesPromise =
(ignoreUIState || showingGraph) && supportsGraph
? dispatch(
runQueriesForType(
exploreId,
'Graph',
{
interval,
format: 'time_series',
instant: false,
maxDataPoints: containerWidth,
},
makeTimeSeriesList
)
)
: undefined;
const logsQueriesPromise =
(ignoreUIState || showingLogs) && supportsLogs
? dispatch(runQueriesForType(exploreId, 'Logs', { interval, format: 'logs' }))
: undefined;
dispatch(stateSave());
return Promise.all([tableQueriesPromise, typeQueriesPromise, logsQueriesPromise]);
};
}
@@ -607,14 +625,13 @@ function runQueriesForType(
exploreId: ExploreId,
resultType: ResultType,
queryOptions: QueryOptions,
resultGetter?: any
resultGetter?: ResultGetter
): ThunkResult<void> {
return async (dispatch, getState) => {
const { datasourceInstance, eventBridge, queries, queryIntervals, range, scanning } = getState().explore[exploreId];
const datasourceId = datasourceInstance.meta.id;
// Run all queries concurrently
queries.forEach(async (query, rowIndex) => {
const queryPromises = queries.map(async (query, rowIndex) => {
const transaction = buildQueryTransaction(
query,
rowIndex,
@@ -638,6 +655,8 @@ function runQueriesForType(
dispatch(queryTransactionFailure(exploreId, transaction.id, response, datasourceId));
}
});
return Promise.all(queryPromises);
};
}
@@ -814,7 +833,6 @@ export function refreshExplore(exploreId: ExploreId): ThunkResult<void> {
const { datasource, queries, range, ui } = urlState;
const refreshQueries = queries.map(q => ({ ...q, ...generateEmptyQuery(itemState.queries) }));
const refreshRange = { from: parseTime(range.from), to: parseTime(range.to) };
// need to refresh datasource
if (update.datasource) {
const initialQueries = ensureQueries(queries);