From 40f410562a4d445b69564eb47f701b5c85520299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 28 Jan 2019 11:45:15 +0100 Subject: [PATCH 01/22] Fixed reinitialise of Explore --- public/app/core/actions/location.ts | 8 ++++-- public/app/core/reducers/location.ts | 8 +++--- .../app/features/explore/state/actionTypes.ts | 6 +++-- public/app/features/explore/state/reducers.ts | 25 +++++++++---------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/public/app/core/actions/location.ts b/public/app/core/actions/location.ts index 6f7ac67363e..8669788fa16 100644 --- a/public/app/core/actions/location.ts +++ b/public/app/core/actions/location.ts @@ -1,13 +1,17 @@ import { LocationUpdate } from 'app/types'; +export enum CoreActionTypes { + UpdateLocation = 'UPDATE_LOCATION', +} + export type Action = UpdateLocationAction; export interface UpdateLocationAction { - type: 'UPDATE_LOCATION'; + type: CoreActionTypes.UpdateLocation; payload: LocationUpdate; } export const updateLocation = (location: LocationUpdate): UpdateLocationAction => ({ - type: 'UPDATE_LOCATION', + type: CoreActionTypes.UpdateLocation, payload: location, }); diff --git a/public/app/core/reducers/location.ts b/public/app/core/reducers/location.ts index a42bd813782..6b39710dcca 100644 --- a/public/app/core/reducers/location.ts +++ b/public/app/core/reducers/location.ts @@ -1,4 +1,4 @@ -import { Action } from 'app/core/actions/location'; +import { Action, CoreActionTypes } from 'app/core/actions/location'; import { LocationState } from 'app/types'; import { renderUrl } from 'app/core/utils/url'; import _ from 'lodash'; @@ -12,7 +12,7 @@ export const initialState: LocationState = { export const locationReducer = (state = initialState, action: Action): LocationState => { switch (action.type) { - case 'UPDATE_LOCATION': { + case CoreActionTypes.UpdateLocation: { const { path, routeParams } = action.payload; let query = action.payload.query || state.query; @@ -24,9 +24,7 @@ export const locationReducer = (state = initialState, action: Action): LocationS return { url: renderUrl(path || state.path, query), path: path || state.path, - query: { - ...query, - }, + query: { ...query }, routeParams: routeParams || state.routeParams, }; } diff --git a/public/app/features/explore/state/actionTypes.ts b/public/app/features/explore/state/actionTypes.ts index 4e1d658f072..219e3fb6fc9 100644 --- a/public/app/features/explore/state/actionTypes.ts +++ b/public/app/features/explore/state/actionTypes.ts @@ -1,6 +1,6 @@ // Types import { Emitter } from 'app/core/core'; -import { RawTimeRange, TimeRange, DataQuery, DataSourceSelectItem } from '@grafana/ui/src/types'; +import { RawTimeRange, TimeRange, DataQuery, DataSourceSelectItem } from '@grafana/ui/src/types'; import { ExploreId, ExploreItemState, @@ -9,6 +9,7 @@ import { ResultType, QueryTransaction, } from 'app/types/explore'; +import { UpdateLocationAction } from 'app/core/actions/location'; export enum ActionTypes { AddQueryRow = 'explore/ADD_QUERY_ROW', @@ -297,4 +298,5 @@ export type Action = | SplitOpenAction | ToggleGraphAction | ToggleLogsAction - | ToggleTableAction; + | ToggleTableAction + | UpdateLocationAction; diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index 8885f972d06..ccad9392c06 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -8,6 +8,7 @@ import { ExploreItemState, ExploreState, QueryTransaction } from 'app/types/expl import { DataQuery } from '@grafana/ui/src/types'; import { Action, ActionTypes } from './actionTypes'; +import { CoreActionTypes } from 'app/core/actions/location'; export const DEFAULT_RANGE = { from: 'now-6h', @@ -428,25 +429,23 @@ export const itemReducer = (state, action: Action): ExploreItemState => { export const exploreReducer = (state = initialExploreState, action: Action): ExploreState => { switch (action.type) { case ActionTypes.SplitClose: { - return { - ...state, - split: false, - }; + return { ...state, split: false }; } case ActionTypes.SplitOpen: { - return { - ...state, - split: true, - right: action.payload.itemState, - }; + return { ...state, split: true, right: action.payload.itemState }; } case ActionTypes.InitializeExploreSplit: { - return { - ...state, - split: true, - }; + return { ...state, split: true }; + } + + case CoreActionTypes.UpdateLocation: { + if (action.payload.path && action.payload.path !== '/explore') { + return initialExploreState; + } + + return state; } } From c9cab9b6776a2ef4a5e6172a46ccd155133ca92a Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Mon, 28 Jan 2019 12:20:16 +0100 Subject: [PATCH 02/22] updating state if no panel --- .../dashboard/services/DashboardViewStateSrv.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/public/app/features/dashboard/services/DashboardViewStateSrv.ts b/public/app/features/dashboard/services/DashboardViewStateSrv.ts index cb9794d6abb..816b6d8bd2d 100644 --- a/public/app/features/dashboard/services/DashboardViewStateSrv.ts +++ b/public/app/features/dashboard/services/DashboardViewStateSrv.ts @@ -72,7 +72,6 @@ export class DashboardViewStateSrv { } _.extend(this.state, state); - this.dashboard.meta.fullscreen = this.state.fullscreen; if (!this.state.fullscreen) { this.state.fullscreen = null; @@ -117,10 +116,20 @@ export class DashboardViewStateSrv { } syncState() { - if (this.dashboard.meta.fullscreen) { + if (this.state.fullscreen) { const panel = this.dashboard.getPanelById(this.state.panelId); if (!panel) { + this.state.fullscreen = null; + this.state.panelId = null; + this.state.edit = null; + + this.update(this.state); + + setTimeout(() => { + appEvents.emit('alert-error', ['Error', 'Panel not found']); + }, 100); + return; } From 1aefc4cc2d47df02d4bd71ba53493cbcc4288664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Tue, 22 Jan 2019 14:50:19 +0100 Subject: [PATCH 03/22] Refactored out ExploreToolbar from Explore --- public/app/features/explore/Explore.tsx | 69 +++--------- .../app/features/explore/ExploreToolbar.tsx | 100 ++++++++++++++++++ 2 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 public/app/features/explore/ExploreToolbar.tsx diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index b6f57a76004..25d868e3565 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -10,7 +10,6 @@ import store from 'app/core/store'; // Components import { DataSourceSelectItem } from '@grafana/ui/src/types'; -import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { Alert } from './Error'; import ErrorBoundary from './ErrorBoundary'; import GraphContainer from './GraphContainer'; @@ -41,6 +40,7 @@ import { ExploreItemState, ExploreUrlState, RangeScanner, ExploreId } from 'app/ import { StoreState } from 'app/types'; import { LAST_USED_DATASOURCE_KEY, ensureQueries, DEFAULT_RANGE } from 'app/core/utils/explore'; import { Emitter } from 'app/core/utils/emitter'; +import { ExploreToolbar } from './ExploreToolbar'; interface ExploreProps { StartPage?: any; @@ -233,58 +233,21 @@ export class Explore extends React.PureComponent { return (
-
- {exploreId === 'left' ? ( - - ) : ( - <> -
-
- -
- - )} - {!datasourceMissing ? ( -
- -
- ) : null} -
- {exploreId === 'left' && !split ? ( -
- -
- ) : null} - -
- -
-
- -
-
+ {datasourceLoading ?
Loading datasource...
: null} {datasourceMissing ? (
Please add a datasource that supports Explore (e.g., Prometheus).
diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx new file mode 100644 index 00000000000..6b25b367039 --- /dev/null +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -0,0 +1,100 @@ +import React, { PureComponent } from 'react'; +import { ExploreId } from 'app/types/explore'; +import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; +import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; +import TimePicker from './TimePicker'; + +interface Props { + datasourceMissing: boolean; + exploreDatasources: DataSourceSelectItem[]; + exploreId: ExploreId; + loading: boolean; + range: RawTimeRange; + selectedDatasource: DataSourceSelectItem; + splitted: boolean; + onChangeDatasource: (option) => void; + onClearAll: () => void; + onCloseSplit: () => void; + onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void; + onRunQuery: () => void; + onSplit: () => void; +} + +export class ExploreToolbar extends PureComponent { + /** + * Timepicker to control scanning + */ + timepickerRef: React.RefObject; + + constructor(props) { + super(props); + this.timepickerRef = React.createRef(); + } + + render() { + const { + datasourceMissing, + exploreDatasources, + exploreId, + loading, + range, + selectedDatasource, + splitted, + } = this.props; + + return ( +
+ {exploreId === 'left' ? ( + + ) : ( + <> +
+
+ +
+ + )} + {!datasourceMissing ? ( +
+ +
+ ) : null} +
+ {exploreId === 'left' && !splitted ? ( +
+ +
+ ) : null} + +
+ +
+
+ +
+
+ ); + } +} From ffe03ee22dd80798af53103b7109726a91de0e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 23 Jan 2019 15:57:24 +0100 Subject: [PATCH 04/22] Restructure of component and styling --- .../app/features/explore/ExploreToolbar.tsx | 178 ++++-- public/app/features/explore/TimePicker.tsx | 21 +- public/sass/pages/_explore.scss | 583 +++++++++++++----- 3 files changed, 549 insertions(+), 233 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 6b25b367039..0c2d734ecc0 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -1,8 +1,8 @@ import React, { PureComponent } from 'react'; import { ExploreId } from 'app/types/explore'; -import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; import TimePicker from './TimePicker'; +import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; interface Props { datasourceMissing: boolean; @@ -29,70 +29,136 @@ export class ExploreToolbar extends PureComponent { constructor(props) { super(props); this.timepickerRef = React.createRef(); + this.createResponsiveButton = this.createResponsiveButton.bind(this); + this.createDatasourcePicker = this.createDatasourcePicker.bind(this); + this.createSplittedClassName = this.createSplittedClassName.bind(this); + } + + createDatasourcePicker() { + const { exploreDatasources, selectedDatasource } = this.props; + + return ( + + ); + } + + createResponsiveButton(options: { + title: string; + onClick: () => void; + buttonClassName?: string; + iconClassName?: string; + }) { + const { splitted } = this.props; + const { title, onClick, buttonClassName, iconClassName } = options; + + return ( + <> + + + + ); + } + + createSplittedClassName(className: string) { + const { splitted } = this.props; + + return splitted ? `${className}-splitted` : className; } render() { - const { - datasourceMissing, - exploreDatasources, - exploreId, - loading, - range, - selectedDatasource, - splitted, - } = this.props; + const { datasourceMissing, exploreId, loading, range, splitted } = this.props; + const toolbar = this.createSplittedClassName('toolbar'); + const toolbarItem = this.createSplittedClassName('toolbar-item'); + const toolbarHeader = this.createSplittedClassName('toolbar-header'); + const timepickerLarge = this.createSplittedClassName('toolbar-content-item timepicker-large-screens'); + const timepickerSmall = this.createSplittedClassName('toolbar-content-item timepicker-small-screens'); return ( -
- {exploreId === 'left' ? ( -
- - - Explore - +
+
+
+
+ {exploreId === 'left' && ( + + + Explore + + )} +
+
+
+ {!datasourceMissing && !splitted ? this.createDatasourcePicker() : null} +
+
+
+ {exploreId === 'right' && ( + + + + )} +
- ) : ( - <> -
-
-
+
+ {!datasourceMissing && splitted ? ( +
{this.createDatasourcePicker()}
+ ) : null} +
+
+
+ {!datasourceMissing && !splitted ? ( +
+
{this.createDatasourcePicker()}
+
+ ) : null} + {exploreId === 'left' && !splitted ? ( +
+ {this.createResponsiveButton({ + title: 'Split', + onClick: this.props.onSplit, + iconClassName: 'fa fa-fw fa-columns', + })} +
+ ) : null} +
+ +
+
+ +
+
+
- - )} - {!datasourceMissing ? ( -
- +
+ {this.createResponsiveButton({ + title: 'Run Query', + onClick: this.props.onRunQuery, + buttonClassName: 'navbar-button--primary', + iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon', + })} +
- ) : null} -
- {exploreId === 'left' && !splitted ? ( -
- -
- ) : null} - -
- -
-
-
); diff --git a/public/app/features/explore/TimePicker.tsx b/public/app/features/explore/TimePicker.tsx index 8476c6b2b27..47b8f0de13a 100644 --- a/public/app/features/explore/TimePicker.tsx +++ b/public/app/features/explore/TimePicker.tsx @@ -39,6 +39,7 @@ interface TimePickerProps { isUtc?: boolean; range?: RawTimeRange; onChangeTime?: (range: RawTimeRange, scanning?: boolean) => void; + iconOnly?: boolean; } interface TimePickerState { @@ -292,19 +293,27 @@ export default class TimePicker extends PureComponent
- + {iconOnly ? ( + + ) : ( + + )} diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index abd13a10368..d64121f761d 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -1,182 +1,248 @@ +.timepicker-small-screens, +.timepicker-small-screens-splitted, +.small-screens { + display: none; +} + +.datasource-picker { + min-width: 200px; + max-width: 200px; +} + +.toolbar-splitted, +.toolbar { + display: flex; + background: inherit; + justify-content: space-between; + height: auto; + padding: 2px $dashboard-padding; +} + +.toolbar { + flex-flow: row nowrap; +} + +.toolbar-splitted { + flex-flow: row wrap; +} + +.toolbar-item-splitted, +.toolbar-item { + align-self: center; +} + +.toolbar-item-splitted:first-child { + flex: 1 1 100%; +} + +.toolbar-header-splitted, +.toolbar-header { + display: flex; + flex: 1 1 0; + flex-flow: row nowrap; + font-size: 18px; + min-height: 55px; + line-height: 55px; + justify-content: space-between; +} + +.toolbar-header { + align-items: center; +} + +.toolbar-header-datasource { + padding-left: $dashboard-padding; + flex: 2 1 auto; +} + +.toolbar-header-close { + color: #d6d6d6; + padding-right: 8px; +} + +.toolbar-content-splitted, +.toolbar-content { + display: flex; + flex: 2 1 0; + flex-flow: row wrap; + justify-content: flex-end; + align-items: center; +} + +.toolbar-content-item { + padding: 10px 2px; +} + +@media only screen and (max-width: 1545px) { + .timepicker-large-screens-splitted { + display: none; + } + + .timepicker-small-screens-splitted { + display: inline-block; + } +} + +@media only screen and (max-width: 1070px) { + .timepicker-large-screens { + display: none; + } + + .timepicker-small-screens { + display: inline-block; + } +} + +@media only screen and (max-width: 768px) { + .large-screens { + display: none; + } + + .small-screens { + display: inline-block; + } + + .toolbar { + flex-flow: row wrap; + } + + .toolbar-content { + align-self: flex-start; + justify-content: flex-start; + } + + .toolbar-content-item { + padding: 5px 2px; + } + + .datasource-picker > div > .ds-picker { + min-width: 160px; + max-width: 160px; + } +} + .explore { flex: 1 1 auto; - - &-container { - padding: $dashboard-padding; - } - - &-wrapper { - display: flex; - - > .explore-split { - width: 50%; - } - } - - // Push split button a bit - .explore-first-button { - margin-left: 15px; - } - - .explore-panel { - margin-top: $panel-margin; - } - - .explore-panel__body { - padding: $panel-padding; - } - - .explore-panel__header { - padding: $panel-padding; - padding-top: 5px; - padding-bottom: 0; - display: flex; - cursor: pointer; - margin-bottom: 5px; - transition: all 0.1s linear; - } - - .explore-panel__header-label { - font-weight: 500; - margin-right: $panel-margin; - font-size: $font-size-h6; - box-shadow: $text-shadow-faint; - } - - .explore-panel__header-buttons { - margin-right: $panel-margin; - font-size: $font-size-lg; - line-height: $font-size-h6; - } - - // Make sure wrap buttons around on small screens - .navbar { - flex-wrap: wrap; - height: auto; - } - - .navbar-page-btn { - margin-right: 1rem; - - // Explore icon in header - .fa { - font-size: 100%; - opacity: 0.75; - margin-right: 0.5em; - } - } - - // Toggle mode - .navbar-button.active { - color: $btn-active-text-color; - background-color: $btn-active-bg; - } - - .navbar-button--no-icon { - line-height: 18px; - } - - .result-options { - margin: 2 * $panel-margin 0; - } - - .time-series-disclaimer { - width: 300px; - margin: $panel-margin auto; - padding: 10px 0; - border-radius: $border-radius; - text-align: center; - background-color: $panel-bg; - - .disclaimer-icon { - color: $yellow; - margin-right: $panel-margin/2; - } - - .show-all-time-series { - cursor: pointer; - color: $external-link-color; - } - } - - .navbar .elapsed-time { - position: absolute; - left: 0; - right: 0; - top: 3.5rem; - text-align: center; - font-size: 0.8rem; - } - - .graph-legend { - flex-wrap: wrap; - } - - .explore-panel__loader { - height: 2px; - position: relative; - overflow: hidden; - background: none; - margin: $panel-margin / 2; - transition: background-color 1s ease; - } - - .explore-panel__loader--active { - background: $text-color-faint; - } - - .explore-panel__loader--active:after { - content: ' '; - display: block; - width: 25%; - top: 0; - top: -50%; - height: 250%; - position: absolute; - animation: loader 2s cubic-bezier(0.17, 0.67, 0.83, 0.67); - animation-iteration-count: 100; - background: $blue; - } - - @keyframes loader { - from { - left: -25%; - } - to { - left: 100%; - } - } - - .datasource-picker { - min-width: 200px; - } - - .timepicker { - display: flex; - - &-rangestring { - margin-left: 0.5em; - } - } - - .run-icon { - margin-left: 0.25em; - transform: rotate(90deg); - } - - .relative { - position: relative; - } - - .link { - text-decoration: underline; - } } .explore + .explore { border-left: 1px dotted $table-border; } +.explore-container { + padding: $dashboard-padding; +} + +.explore-wrapper { + display: flex; + + > .explore-split { + width: 50%; + } +} + +.explore-panel { + margin-top: $panel-margin; +} + +.explore-panel__body { + padding: $panel-padding; +} + +.explore-panel__header { + padding: $panel-padding; + padding-top: 5px; + padding-bottom: 0; + display: flex; + cursor: pointer; + margin-bottom: 5px; + transition: all 0.1s linear; +} + +.explore-panel__header-label { + font-weight: 500; + margin-right: $panel-margin; + font-size: $font-size-h6; + box-shadow: $text-shadow-faint; +} + +.explore-panel__header-buttons { + margin-right: $panel-margin; + font-size: $font-size-lg; + line-height: $font-size-h6; +} + +.result-options { + margin: 2 * $panel-margin 0; +} + +.time-series-disclaimer { + width: 300px; + margin: $panel-margin auto; + padding: 10px 0; + border-radius: $border-radius; + text-align: center; + background-color: $panel-bg; + + .disclaimer-icon { + color: $yellow; + margin-right: $panel-margin/2; + } + + .show-all-time-series { + cursor: pointer; + color: $external-link-color; + } +} + +.navbar .elapsed-time { + position: absolute; + left: 0; + right: 0; + top: 3.5rem; + text-align: center; + font-size: 0.8rem; +} + +.graph-legend { + flex-wrap: wrap; +} + +.explore-panel__loader { + height: 2px; + position: relative; + overflow: hidden; + background: none; + margin: $panel-margin / 2; + transition: background-color 1s ease; +} + +.explore-panel__loader--active { + background: $text-color-faint; +} + +.explore-panel__loader--active:after { + content: ' '; + display: block; + width: 25%; + top: 0; + top: -50%; + height: 250%; + position: absolute; + animation: loader 2s cubic-bezier(0.17, 0.67, 0.83, 0.67); + animation-iteration-count: 100; + background: $blue; +} + +@keyframes loader { + from { + left: -25%; + } + to { + left: 100%; + } +} + .query-row { display: flex; position: relative; @@ -352,3 +418,178 @@ margin: $panel-margin/2 0; cursor: pointer; } + +// .explore { +// flex: 1 1 auto; + +// &-container { +// padding: $dashboard-padding; +// } + +// &-wrapper { +// display: flex; + +// > .explore-split { +// width: 50%; +// } +// } + +// // Push split button a bit +// .explore-first-button { +// margin-left: 15px; +// } + +// .explore-panel { +// margin-top: $panel-margin; +// } + +// .explore-panel__body { +// padding: $panel-padding; +// } + +// .explore-panel__header { +// padding: $panel-padding; +// padding-top: 5px; +// padding-bottom: 0; +// display: flex; +// cursor: pointer; +// margin-bottom: 5px; +// transition: all 0.1s linear; +// } + +// .explore-panel__header-label { +// font-weight: 500; +// margin-right: $panel-margin; +// font-size: $font-size-h6; +// box-shadow: $text-shadow-faint; +// } + +// .explore-panel__header-buttons { +// margin-right: $panel-margin; +// font-size: $font-size-lg; +// line-height: $font-size-h6; +// } + +// // Make sure wrap buttons around on small screens +// .navbar { +// flex-wrap: wrap; +// height: auto; +// } + +// .navbar-page-btn { +// margin-right: 1rem; + +// // Explore icon in header +// .fa { +// font-size: 100%; +// opacity: 0.75; +// margin-right: 0.5em; +// } +// } + +// // Toggle mode +// .navbar-button.active { +// color: $btn-active-text-color; +// background-color: $btn-active-bg; +// } + +// .navbar-button--no-icon { +// line-height: 18px; +// } + +// .result-options { +// margin: 2 * $panel-margin 0; +// } + +// .time-series-disclaimer { +// width: 300px; +// margin: $panel-margin auto; +// padding: 10px 0; +// border-radius: $border-radius; +// text-align: center; +// background-color: $panel-bg; + +// .disclaimer-icon { +// color: $yellow; +// margin-right: $panel-margin/2; +// } + +// .show-all-time-series { +// cursor: pointer; +// color: $external-link-color; +// } +// } + +// .navbar .elapsed-time { +// position: absolute; +// left: 0; +// right: 0; +// top: 3.5rem; +// text-align: center; +// font-size: 0.8rem; +// } + +// .graph-legend { +// flex-wrap: wrap; +// } + +// .explore-panel__loader { +// height: 2px; +// position: relative; +// overflow: hidden; +// background: none; +// margin: $panel-margin / 2; +// transition: background-color 1s ease; +// } + +// .explore-panel__loader--active { +// background: $text-color-faint; +// } + +// .explore-panel__loader--active:after { +// content: ' '; +// display: block; +// width: 25%; +// top: 0; +// top: -50%; +// height: 250%; +// position: absolute; +// animation: loader 2s cubic-bezier(0.17, 0.67, 0.83, 0.67); +// animation-iteration-count: 100; +// background: $blue; +// } + +// @keyframes loader { +// from { +// left: -25%; +// } +// to { +// left: 100%; +// } +// } + +// .datasource-picker { +// min-width: 200px; +// } + +// .timepicker { +// display: flex; + +// &-rangestring { +// margin-left: 0.5em; +// } +// } + +// .run-icon { +// margin-left: 0.25em; +// transform: rotate(90deg); +// } + +// .relative { +// position: relative; +// } + +// .link { +// text-decoration: underline; +// } +// } From b2c284e42c81c4b138e32a893c3370ebeda8af2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 23 Jan 2019 16:29:18 +0100 Subject: [PATCH 05/22] Fixed so heading looks good with closed sidemenu --- .../app/features/explore/ExploreToolbar.tsx | 6 ++--- public/sass/pages/_explore.scss | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 0c2d734ecc0..6fde5001481 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -101,9 +101,9 @@ export class ExploreToolbar extends PureComponent {
{exploreId === 'right' && ( - - - + )}
diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index d64121f761d..2c367a63a6d 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -4,18 +4,33 @@ display: none; } +.timepicker { + display: flex; +} + +.timepicker-rangestring { + margin-left: 0.5em; +} + .datasource-picker { min-width: 200px; max-width: 200px; } +.sidemenu-open { + .toolbar { + margin-left: 0; + } +} + .toolbar-splitted, .toolbar { display: flex; background: inherit; justify-content: space-between; height: auto; - padding: 2px $dashboard-padding; + padding: 0px $dashboard-padding; + margin-left: $panel-margin * 3; } .toolbar { @@ -102,6 +117,11 @@ display: inline-block; } + .toolbar-splitted, + .toolbar { + margin-left: 0; + } + .toolbar { flex-flow: row wrap; } From 9caaf25078260318ea92cf0cc78b44a14580a277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 23 Jan 2019 16:48:21 +0100 Subject: [PATCH 06/22] Fixed some more with the sidemenu open and smaller screens --- .../app/features/explore/ExploreToolbar.tsx | 2 +- public/sass/pages/_explore.scss | 24 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 6fde5001481..dbe537a51b1 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -88,7 +88,7 @@ export class ExploreToolbar extends PureComponent {
{exploreId === 'left' && ( - + Explore diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index 2c367a63a6d..c2a35729c79 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -18,7 +18,9 @@ } .sidemenu-open { - .toolbar { + .toolbar-header-splitted, + .toolbar-header { + padding: 0; margin-left: 0; } } @@ -30,7 +32,6 @@ justify-content: space-between; height: auto; padding: 0px $dashboard-padding; - margin-left: $panel-margin * 3; } .toolbar { @@ -59,19 +60,23 @@ min-height: 55px; line-height: 55px; justify-content: space-between; + margin-left: $panel-margin * 3; } .toolbar-header { align-items: center; } +.toolbar-header-title { + color: darken($link-color, 5%); +} + .toolbar-header-datasource { padding-left: $dashboard-padding; flex: 2 1 auto; } .toolbar-header-close { - color: #d6d6d6; padding-right: 8px; } @@ -117,9 +122,16 @@ display: inline-block; } - .toolbar-splitted, - .toolbar { - margin-left: 0; + .sidemenu-open { + .toolbar-header-splitted, + .toolbar-header { + margin-left: $dashboard-padding; + } + } + + .toolbar-header-splitted, + .toolbar-header { + margin-left: $dashboard-padding; } .toolbar { From 032a82feedf26aa1262de2c460c2676d693c99d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 24 Jan 2019 07:23:56 +0100 Subject: [PATCH 07/22] Simplified some styles and dom elements --- .../app/features/explore/ExploreToolbar.tsx | 118 ++++------ public/app/features/explore/TimePicker.tsx | 20 +- public/sass/pages/_explore.scss | 217 ++---------------- 3 files changed, 77 insertions(+), 278 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index dbe537a51b1..0ba16efc4b1 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -20,6 +20,41 @@ interface Props { onSplit: () => void; } +const createDatasourcePicker = (props: Props) => { + const { exploreDatasources, selectedDatasource } = props; + + return ( + + ); +}; + +const createResponsiveButton = (options: { + splitted: boolean; + title: string; + onClick: () => void; + buttonClassName?: string; + iconClassName?: string; +}) => { + const { title, onClick, buttonClassName, iconClassName, splitted } = options; + + return ( + + ); +}; + +const createSplittedClassName = (options: { splitted: boolean; className: string }) => { + const { className, splitted } = options; + + return splitted ? `${className}-splitted` : className; +}; + export class ExploreToolbar extends PureComponent { /** * Timepicker to control scanning @@ -29,58 +64,14 @@ export class ExploreToolbar extends PureComponent { constructor(props) { super(props); this.timepickerRef = React.createRef(); - this.createResponsiveButton = this.createResponsiveButton.bind(this); - this.createDatasourcePicker = this.createDatasourcePicker.bind(this); - this.createSplittedClassName = this.createSplittedClassName.bind(this); - } - - createDatasourcePicker() { - const { exploreDatasources, selectedDatasource } = this.props; - - return ( - - ); - } - - createResponsiveButton(options: { - title: string; - onClick: () => void; - buttonClassName?: string; - iconClassName?: string; - }) { - const { splitted } = this.props; - const { title, onClick, buttonClassName, iconClassName } = options; - - return ( - <> - - - - ); - } - - createSplittedClassName(className: string) { - const { splitted } = this.props; - - return splitted ? `${className}-splitted` : className; } render() { const { datasourceMissing, exploreId, loading, range, splitted } = this.props; - const toolbar = this.createSplittedClassName('toolbar'); - const toolbarItem = this.createSplittedClassName('toolbar-item'); - const toolbarHeader = this.createSplittedClassName('toolbar-header'); - const timepickerLarge = this.createSplittedClassName('toolbar-content-item timepicker-large-screens'); - const timepickerSmall = this.createSplittedClassName('toolbar-content-item timepicker-small-screens'); + const toolbar = createSplittedClassName({ splitted, className: 'toolbar' }); + const toolbarItem = createSplittedClassName({ splitted, className: 'toolbar-item' }); + const toolbarHeader = createSplittedClassName({ splitted, className: 'toolbar-header' }); + const timepicker = createSplittedClassName({ splitted, className: 'toolbar-content-item timepicker' }); return (
@@ -88,7 +79,7 @@ export class ExploreToolbar extends PureComponent {
{exploreId === 'left' && ( - + Explore @@ -96,7 +87,7 @@ export class ExploreToolbar extends PureComponent {
- {!datasourceMissing && !splitted ? this.createDatasourcePicker() : null} + {!datasourceMissing && !splitted ? createDatasourcePicker(this.props) : null}
@@ -110,40 +101,28 @@ export class ExploreToolbar extends PureComponent {
{!datasourceMissing && splitted ? ( -
{this.createDatasourcePicker()}
+
{createDatasourcePicker(this.props)}
) : null}
{!datasourceMissing && !splitted ? (
-
{this.createDatasourcePicker()}
+
{createDatasourcePicker(this.props)}
) : null} {exploreId === 'left' && !splitted ? (
- {this.createResponsiveButton({ + {createResponsiveButton({ + splitted, title: 'Split', onClick: this.props.onSplit, iconClassName: 'fa fa-fw fa-columns', })}
) : null} -
- -
-
- +
+
- {this.createResponsiveButton({ + {createResponsiveButton({ + splitted, title: 'Run Query', onClick: this.props.onRunQuery, buttonClassName: 'navbar-button--primary', diff --git a/public/app/features/explore/TimePicker.tsx b/public/app/features/explore/TimePicker.tsx index 47b8f0de13a..38c3f2e7498 100644 --- a/public/app/features/explore/TimePicker.tsx +++ b/public/app/features/explore/TimePicker.tsx @@ -39,7 +39,6 @@ interface TimePickerProps { isUtc?: boolean; range?: RawTimeRange; onChangeTime?: (range: RawTimeRange, scanning?: boolean) => void; - iconOnly?: boolean; } interface TimePickerState { @@ -293,7 +292,6 @@ export default class TimePicker extends PureComponent - {iconOnly ? ( - - ) : ( - - )} + diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index c2a35729c79..be3dcd61988 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -1,5 +1,3 @@ -.timepicker-small-screens, -.timepicker-small-screens-splitted, .small-screens { display: none; } @@ -13,8 +11,10 @@ } .datasource-picker { - min-width: 200px; - max-width: 200px; + .ds-picker { + min-width: 200px; + max-width: 200px; + } } .sidemenu-open { @@ -69,6 +69,11 @@ .toolbar-header-title { color: darken($link-color, 5%); + .fa { + font-size: 100%; + opacity: 0.75; + margin-right: 0.5em; + } } .toolbar-header-datasource { @@ -94,26 +99,22 @@ } @media only screen and (max-width: 1545px) { - .timepicker-large-screens-splitted { - display: none; - } - - .timepicker-small-screens-splitted { - display: inline-block; + .timepicker-splitted { + .timepicker-rangestring { + display: none; + } } } @media only screen and (max-width: 1070px) { - .timepicker-large-screens { - display: none; - } - - .timepicker-small-screens { - display: inline-block; + .timepicker { + .timepicker-rangestring { + display: none; + } } } -@media only screen and (max-width: 768px) { +@media only screen and (max-width: 800px) { .large-screens { display: none; } @@ -147,9 +148,10 @@ padding: 5px 2px; } - .datasource-picker > div > .ds-picker { - min-width: 160px; - max-width: 160px; + .btn.navbar-button { + .btn-title { + display: none; + } } } @@ -450,178 +452,3 @@ margin: $panel-margin/2 0; cursor: pointer; } - -// .explore { -// flex: 1 1 auto; - -// &-container { -// padding: $dashboard-padding; -// } - -// &-wrapper { -// display: flex; - -// > .explore-split { -// width: 50%; -// } -// } - -// // Push split button a bit -// .explore-first-button { -// margin-left: 15px; -// } - -// .explore-panel { -// margin-top: $panel-margin; -// } - -// .explore-panel__body { -// padding: $panel-padding; -// } - -// .explore-panel__header { -// padding: $panel-padding; -// padding-top: 5px; -// padding-bottom: 0; -// display: flex; -// cursor: pointer; -// margin-bottom: 5px; -// transition: all 0.1s linear; -// } - -// .explore-panel__header-label { -// font-weight: 500; -// margin-right: $panel-margin; -// font-size: $font-size-h6; -// box-shadow: $text-shadow-faint; -// } - -// .explore-panel__header-buttons { -// margin-right: $panel-margin; -// font-size: $font-size-lg; -// line-height: $font-size-h6; -// } - -// // Make sure wrap buttons around on small screens -// .navbar { -// flex-wrap: wrap; -// height: auto; -// } - -// .navbar-page-btn { -// margin-right: 1rem; - -// // Explore icon in header -// .fa { -// font-size: 100%; -// opacity: 0.75; -// margin-right: 0.5em; -// } -// } - -// // Toggle mode -// .navbar-button.active { -// color: $btn-active-text-color; -// background-color: $btn-active-bg; -// } - -// .navbar-button--no-icon { -// line-height: 18px; -// } - -// .result-options { -// margin: 2 * $panel-margin 0; -// } - -// .time-series-disclaimer { -// width: 300px; -// margin: $panel-margin auto; -// padding: 10px 0; -// border-radius: $border-radius; -// text-align: center; -// background-color: $panel-bg; - -// .disclaimer-icon { -// color: $yellow; -// margin-right: $panel-margin/2; -// } - -// .show-all-time-series { -// cursor: pointer; -// color: $external-link-color; -// } -// } - -// .navbar .elapsed-time { -// position: absolute; -// left: 0; -// right: 0; -// top: 3.5rem; -// text-align: center; -// font-size: 0.8rem; -// } - -// .graph-legend { -// flex-wrap: wrap; -// } - -// .explore-panel__loader { -// height: 2px; -// position: relative; -// overflow: hidden; -// background: none; -// margin: $panel-margin / 2; -// transition: background-color 1s ease; -// } - -// .explore-panel__loader--active { -// background: $text-color-faint; -// } - -// .explore-panel__loader--active:after { -// content: ' '; -// display: block; -// width: 25%; -// top: 0; -// top: -50%; -// height: 250%; -// position: absolute; -// animation: loader 2s cubic-bezier(0.17, 0.67, 0.83, 0.67); -// animation-iteration-count: 100; -// background: $blue; -// } - -// @keyframes loader { -// from { -// left: -25%; -// } -// to { -// left: 100%; -// } -// } - -// .datasource-picker { -// min-width: 200px; -// } - -// .timepicker { -// display: flex; - -// &-rangestring { -// margin-left: 0.5em; -// } -// } - -// .run-icon { -// margin-left: 0.25em; -// transform: rotate(90deg); -// } - -// .relative { -// position: relative; -// } - -// .link { -// text-decoration: underline; -// } -// } From d2a5477654fe4a517a10c0cb174202b4aa8beca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 24 Jan 2019 09:03:26 +0100 Subject: [PATCH 08/22] Fixed small issue with TimePicker dropdown position --- public/app/features/explore/Explore.tsx | 3 +++ public/app/features/explore/ExploreToolbar.tsx | 16 ++++------------ public/sass/pages/_explore.scss | 6 ++++++ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 25d868e3565..f0068119a32 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -231,6 +231,8 @@ export class Explore extends React.PureComponent { ? exploreDatasources.find(d => d.name === datasourceInstance.name) : undefined; + const timepicker = ; + return (
{ range={range} selectedDatasource={selectedDatasource} splitted={split} + timepicker={timepicker} onChangeDatasource={this.onChangeDatasource} onClearAll={this.onClickClear} onCloseSplit={this.onClickCloseSplit} diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 0ba16efc4b1..968b722ecfe 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -1,7 +1,6 @@ import React, { PureComponent } from 'react'; import { ExploreId } from 'app/types/explore'; import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; -import TimePicker from './TimePicker'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; interface Props { @@ -12,6 +11,7 @@ interface Props { range: RawTimeRange; selectedDatasource: DataSourceSelectItem; splitted: boolean; + timepicker: JSX.Element; onChangeDatasource: (option) => void; onClearAll: () => void; onCloseSplit: () => void; @@ -56,22 +56,16 @@ const createSplittedClassName = (options: { splitted: boolean; className: string }; export class ExploreToolbar extends PureComponent { - /** - * Timepicker to control scanning - */ - timepickerRef: React.RefObject; - constructor(props) { super(props); - this.timepickerRef = React.createRef(); } render() { - const { datasourceMissing, exploreId, loading, range, splitted } = this.props; + const { datasourceMissing, exploreId, loading, splitted, timepicker } = this.props; const toolbar = createSplittedClassName({ splitted, className: 'toolbar' }); const toolbarItem = createSplittedClassName({ splitted, className: 'toolbar-item' }); const toolbarHeader = createSplittedClassName({ splitted, className: 'toolbar-header' }); - const timepicker = createSplittedClassName({ splitted, className: 'toolbar-content-item timepicker' }); + const timepickerClasses = createSplittedClassName({ splitted, className: 'toolbar-content-item timepicker' }); return (
@@ -121,9 +115,7 @@ export class ExploreToolbar extends PureComponent { })}
) : null} -
- -
+
{timepicker}
{exploreId === 'right' && ( - + + + )}
diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index a2f36908a85..bb0a2ae719e 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -154,10 +154,8 @@ padding: 5px 2px; } - .btn.navbar-button { - .btn-title { - display: none; - } + .btn-title { + display: none; } } From 0a094a13f2efc4118d02021179ae4bf122f5561a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 24 Jan 2019 11:27:48 +0100 Subject: [PATCH 11/22] Fixed some more styling --- .../app/features/explore/ExploreToolbar.tsx | 26 ++-- public/sass/pages/_explore.scss | 138 +++++++++++------- 2 files changed, 92 insertions(+), 72 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index ee36d622bab..25b8b3deb9a 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -65,7 +65,9 @@ export class ExploreToolbar extends PureComponent { const toolbar = createSplittedClassName({ splitted, className: 'toolbar' }); const toolbarItem = createSplittedClassName({ splitted, className: 'toolbar-item' }); const toolbarHeader = createSplittedClassName({ splitted, className: 'toolbar-header' }); - const timepickerClasses = createSplittedClassName({ splitted, className: 'toolbar-content-item timepicker' }); + const toolbarContent = createSplittedClassName({ splitted, className: 'toolbar-content' }); + const toolbarContentItem = createSplittedClassName({ splitted, className: 'toolbar-content-item' }); + const timepickerClasses = createSplittedClassName({ splitted, className: 'timepicker toolbar-content-item' }); return (
@@ -79,11 +81,6 @@ export class ExploreToolbar extends PureComponent { )}
-
-
- {!datasourceMissing && !splitted ? createDatasourcePicker(this.props) : null} -
-
- {!datasourceMissing && splitted ? ( -
{createDatasourcePicker(this.props)}
- ) : null} -
-
-
- {!datasourceMissing && !splitted ? ( -
+
+ {!datasourceMissing ? ( +
{createDatasourcePicker(this.props)}
) : null} {exploreId === 'left' && !splitted ? ( -
+
{createResponsiveButton({ splitted, title: 'Split', @@ -116,12 +108,12 @@ export class ExploreToolbar extends PureComponent {
) : null}
{timepicker}
-
+
-
+
{createResponsiveButton({ splitted, title: 'Run Query', diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index bb0a2ae719e..25221c52589 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -1,8 +1,3 @@ -.small-screens { - display: none; -} - -.timepicker-splitted, .timepicker { display: flex; } @@ -24,13 +19,20 @@ padding: 0; margin-left: 0; } + + .toolbar-header-title { + .navbar-page-btn { + padding-left: 0; + } + } } .toolbar-splitted, .toolbar { - display: flex; background: inherit; - justify-content: space-between; + display: flex; + flex-flow: row wrap; + justify-content: flex-start; height: auto; padding: 0px $dashboard-padding; border-bottom: 1px solid #0000; @@ -39,24 +41,20 @@ transition-property: box-shadow, border-bottom; } -.toolbar { - flex-flow: row nowrap; -} - -.toolbar-splitted { - flex-flow: row wrap; -} - .toolbar-item-splitted, .toolbar-item { position: relative; align-self: center; } -.toolbar-item-splitted:first-child { +.toolbar-item-splitted { flex: 1 1 100%; } +.toolbar-item:last-child { + flex: auto; +} + .toolbar-header-splitted, .toolbar-header { display: flex; @@ -76,6 +74,11 @@ .toolbar-header-title { color: darken($link-color, 5%); + + .navbar-page-btn { + padding-left: $dashboard-padding; + } + .fa { font-size: 100%; opacity: 0.75; @@ -83,10 +86,6 @@ } } -.toolbar-header-datasource { - padding-left: $dashboard-padding; -} - .toolbar-header-close { margin-left: auto; } @@ -94,21 +93,28 @@ .toolbar-content-splitted, .toolbar-content { display: flex; - flex: 2 1 0; flex-flow: row wrap; - justify-content: flex-end; align-items: center; + justify-content: space-between; } .toolbar-content-item { padding: 10px 2px; } +.toolbar-content-item:first-child { + padding-left: $dashboard-padding; + margin-right: auto; +} + +.toolbar-content-item-splitted:first-child { + padding-left: 0; + margin-right: auto; +} + @media only screen and (max-width: 1545px) { - .timepicker-splitted { - .timepicker-rangestring { - display: none; - } + .timepicker-rangestring { + display: none; } } @@ -118,47 +124,69 @@ display: none; } } + + .toolbar-content-splitted, + .toolbar-content { + justify-content: flex-start; + } + + .toolbar-content-item-splitted { + padding: 2px 0; + margin: 0; + } + + .toolbar-content-item { + padding: 2px 2px; + } } -@media only screen and (max-width: 800px) { - .large-screens { - display: none; - } - - .small-screens { - display: inline-block; - } - +@media only screen and (max-width: 803px) { .sidemenu-open { - .toolbar-header-splitted, - .toolbar-header { + .toolbar-header-title { + .navbar-page-btn { + padding-left: 0; + margin-left: 0; + } + } + } + + .toolbar-header-title { + .navbar-page-btn { + padding-left: 0; margin-left: $dashboard-padding; } } - .toolbar-header-splitted, - .toolbar-header { - margin-left: $dashboard-padding; - } - - .toolbar { - flex-flow: row wrap; - } - - .toolbar-content { - align-self: flex-start; - justify-content: flex-start; - } - - .toolbar-content-item { - padding: 5px 2px; - } - .btn-title { display: none; } } +@media only screen and (max-width: 702px) { + .toolbar-content-item:first-child { + padding-left: 2px; + margin-right: 0; + } +} + +@media only screen and (max-width: 544px) { + .sidemenu-open { + .toolbar-header-title { + .navbar-page-btn { + padding-left: 0; + margin-left: $dashboard-padding; + } + } + } + + .toolbar-header-title { + .navbar-page-btn { + padding-left: 0; + margin-left: $dashboard-padding; + } + } +} + .explore { flex: 1 1 auto; } From 21df0c90a941381a79fac55998f617d7b87d3fc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 24 Jan 2019 12:00:10 +0100 Subject: [PATCH 12/22] Removed some split complexity --- .../app/features/explore/ExploreToolbar.tsx | 62 ++++++++----------- public/sass/pages/_explore.scss | 36 +++++------ 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 25b8b3deb9a..4652a7f8846 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -3,18 +3,6 @@ import { ExploreId } from 'app/types/explore'; import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; -const createDatasourcePicker = (props: Props) => { - const { exploreDatasources, selectedDatasource } = props; - - return ( - - ); -}; - const createResponsiveButton = (options: { splitted: boolean; title: string; @@ -32,12 +20,6 @@ const createResponsiveButton = (options: { ); }; -const createSplittedClassName = (options: { splitted: boolean; className: string }) => { - const { className, splitted } = options; - - return splitted ? `${className}-splitted` : className; -}; - interface Props { datasourceMissing: boolean; exploreDatasources: DataSourceSelectItem[]; @@ -61,18 +43,20 @@ export class ExploreToolbar extends PureComponent { } render() { - const { datasourceMissing, exploreId, loading, splitted, timepicker } = this.props; - const toolbar = createSplittedClassName({ splitted, className: 'toolbar' }); - const toolbarItem = createSplittedClassName({ splitted, className: 'toolbar-item' }); - const toolbarHeader = createSplittedClassName({ splitted, className: 'toolbar-header' }); - const toolbarContent = createSplittedClassName({ splitted, className: 'toolbar-content' }); - const toolbarContentItem = createSplittedClassName({ splitted, className: 'toolbar-content-item' }); - const timepickerClasses = createSplittedClassName({ splitted, className: 'timepicker toolbar-content-item' }); + const { + datasourceMissing, + exploreDatasources, + exploreId, + loading, + selectedDatasource, + splitted, + timepicker, + } = this.props; return ( -
-
-
+
+ -
-
+
+
{!datasourceMissing ? ( -
-
{createDatasourcePicker(this.props)}
+
+
+ +
) : null} {exploreId === 'left' && !splitted ? ( -
+
{createResponsiveButton({ splitted, title: 'Split', @@ -107,13 +97,13 @@ export class ExploreToolbar extends PureComponent { })}
) : null} -
{timepicker}
-
+
{timepicker}
+
-
+
{createResponsiveButton({ splitted, title: 'Run Query', diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index 25221c52589..062387fdf67 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -14,7 +14,6 @@ } .sidemenu-open { - .toolbar-header-splitted, .toolbar-header { padding: 0; margin-left: 0; @@ -27,7 +26,6 @@ } } -.toolbar-splitted, .toolbar { background: inherit; display: flex; @@ -41,21 +39,26 @@ transition-property: box-shadow, border-bottom; } -.toolbar-item-splitted, .toolbar-item { position: relative; align-self: center; } -.toolbar-item-splitted { - flex: 1 1 100%; +.toolbar.splitted { + .toolbar-item { + flex: 1 1 100%; + } + + .toolbar-content-item:first-child { + padding-left: 0; + margin-right: auto; + } } .toolbar-item:last-child { flex: auto; } -.toolbar-header-splitted, .toolbar-header { display: flex; flex: 1 1 0; @@ -90,7 +93,6 @@ margin-left: auto; } -.toolbar-content-splitted, .toolbar-content { display: flex; flex-flow: row wrap; @@ -107,14 +109,11 @@ margin-right: auto; } -.toolbar-content-item-splitted:first-child { - padding-left: 0; - margin-right: auto; -} - @media only screen and (max-width: 1545px) { - .timepicker-rangestring { - display: none; + .toolbar.splitted { + .timepicker-rangestring { + display: none; + } } } @@ -125,14 +124,15 @@ } } - .toolbar-content-splitted, .toolbar-content { justify-content: flex-start; } - .toolbar-content-item-splitted { - padding: 2px 0; - margin: 0; + .toolbar.splitted { + .toolbar-content-item { + padding: 2px 0; + margin: 0; + } } .toolbar-content-item { From 1e6d50df7aaac339833f3b2c2951b9a5f4e15c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 24 Jan 2019 13:19:33 +0100 Subject: [PATCH 13/22] Made ExplorerToolbar connected and refactored away responsabilities from Explore --- public/app/features/explore/Explore.tsx | 69 +------------- .../app/features/explore/ExploreToolbar.tsx | 92 +++++++++++++++---- 2 files changed, 76 insertions(+), 85 deletions(-) diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index f0068119a32..20ab8ee67b9 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -9,7 +9,6 @@ import { AutoSizer } from 'react-virtualized'; import store from 'app/core/store'; // Components -import { DataSourceSelectItem } from '@grafana/ui/src/types'; import { Alert } from './Error'; import ErrorBoundary from './ErrorBoundary'; import GraphContainer from './GraphContainer'; @@ -20,18 +19,13 @@ import TimePicker, { parseTime } from './TimePicker'; // Actions import { - changeDatasource, changeSize, changeTime, - clearQueries, initializeExplore, modifyQueries, - runQueries, scanStart, scanStop, setQueries, - splitClose, - splitOpen, } from './state/actions'; // Types @@ -44,24 +38,19 @@ import { ExploreToolbar } from './ExploreToolbar'; interface ExploreProps { StartPage?: any; - changeDatasource: typeof changeDatasource; changeSize: typeof changeSize; changeTime: typeof changeTime; - clearQueries: typeof clearQueries; datasourceError: string; datasourceInstance: any; datasourceLoading: boolean | null; datasourceMissing: boolean; - exploreDatasources: DataSourceSelectItem[]; exploreId: ExploreId; initialDatasource?: string; initialQueries: DataQuery[]; initializeExplore: typeof initializeExplore; initialized: boolean; - loading: boolean; modifyQueries: typeof modifyQueries; range: RawTimeRange; - runQueries: typeof runQueries; scanner?: RangeScanner; scanning?: boolean; scanRange?: RawTimeRange; @@ -69,8 +58,6 @@ interface ExploreProps { scanStop: typeof scanStop; setQueries: typeof setQueries; split: boolean; - splitClose: typeof splitClose; - splitOpen: typeof splitOpen; showingStartPage?: boolean; supportsGraph: boolean | null; supportsLogs: boolean | null; @@ -145,10 +132,6 @@ export class Explore extends React.PureComponent { this.el = el; }; - onChangeDatasource = async option => { - this.props.changeDatasource(this.props.exploreId, option.value); - }; - onChangeTime = (range: TimeRange, changedByScanner?: boolean) => { if (this.props.scanning && !changedByScanner) { this.onStopScanning(); @@ -156,23 +139,11 @@ export class Explore extends React.PureComponent { this.props.changeTime(this.props.exploreId, range); }; - onClickClear = () => { - this.props.clearQueries(this.props.exploreId); - }; - - onClickCloseSplit = () => { - this.props.splitClose(); - }; - // Use this in help pages to set page to a single query onClickExample = (query: DataQuery) => { this.props.setQueries(this.props.exploreId, [query]); }; - onClickSplit = () => { - this.props.splitOpen(); - }; - onClickLabel = (key: string, value: string) => { this.onModifyQueries({ type: 'ADD_FILTER', key, value }); }; @@ -204,10 +175,6 @@ export class Explore extends React.PureComponent { this.props.scanStop(this.props.exploreId); }; - onSubmit = () => { - this.props.runQueries(this.props.exploreId); - }; - render() { const { StartPage, @@ -215,11 +182,8 @@ export class Explore extends React.PureComponent { datasourceError, datasourceLoading, datasourceMissing, - exploreDatasources, exploreId, - loading, initialQueries, - range, showingStartPage, split, supportsGraph, @@ -227,30 +191,10 @@ export class Explore extends React.PureComponent { supportsTable, } = this.props; const exploreClass = split ? 'explore explore-split' : 'explore'; - const selectedDatasource = datasourceInstance - ? exploreDatasources.find(d => d.name === datasourceInstance.name) - : undefined; - - const timepicker = ; return (
- + {datasourceLoading ?
Loading datasource...
: null} {datasourceMissing ? (
Please add a datasource that supports Explore (e.g., Prometheus).
@@ -307,30 +251,24 @@ function mapStateToProps(state: StoreState, { exploreId }) { datasourceInstance, datasourceLoading, datasourceMissing, - exploreDatasources, initialDatasource, initialQueries, initialized, - queryTransactions, range, showingStartPage, supportsGraph, supportsLogs, supportsTable, } = item; - const loading = queryTransactions.some(qt => !qt.done); return { StartPage, datasourceError, datasourceInstance, datasourceLoading, datasourceMissing, - exploreDatasources, initialDatasource, initialQueries, initialized, - loading, - queryTransactions, range, showingStartPage, split, @@ -341,18 +279,13 @@ function mapStateToProps(state: StoreState, { exploreId }) { } const mapDispatchToProps = { - changeDatasource, changeSize, changeTime, - clearQueries, initializeExplore, modifyQueries, - runQueries, scanStart, scanStop, setQueries, - splitClose, - splitOpen, }; export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(Explore)); diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 4652a7f8846..a12871c50af 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -1,7 +1,13 @@ import React, { PureComponent } from 'react'; +import { connect } from 'react-redux'; +import { hot } from 'react-hot-loader'; + import { ExploreId } from 'app/types/explore'; import { DataSourceSelectItem, RawTimeRange, TimeRange } from '@grafana/ui'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; +import { StoreState } from 'app/types/store'; +import { changeDatasource, clearQueries, splitClose, runQueries, splitOpen } from './state/actions'; +import TimePicker from './TimePicker'; const createResponsiveButton = (options: { splitted: boolean; @@ -20,37 +26,58 @@ const createResponsiveButton = (options: { ); }; -interface Props { +interface OwnProps { + exploreId: ExploreId; + timepickerRef: React.RefObject; + onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void; +} + +interface StateProps { datasourceMissing: boolean; exploreDatasources: DataSourceSelectItem[]; - exploreId: ExploreId; loading: boolean; range: RawTimeRange; selectedDatasource: DataSourceSelectItem; splitted: boolean; - timepicker: JSX.Element; - onChangeDatasource: (option) => void; - onClearAll: () => void; - onCloseSplit: () => void; - onChangeTime: (range: TimeRange, changedByScanner?: boolean) => void; - onRunQuery: () => void; - onSplit: () => void; } -export class ExploreToolbar extends PureComponent { +interface DispatchProps { + changeDatasource: typeof changeDatasource; + clearAll: typeof clearQueries; + runQuery: typeof runQueries; + closeSplit: typeof splitClose; + split: typeof splitOpen; +} + +type Props = StateProps & DispatchProps & OwnProps; + +export class UnConnectedExploreToolbar extends PureComponent { constructor(props) { super(props); } + onChangeDatasource = async option => { + this.props.changeDatasource(this.props.exploreId, option.value); + }; + + onClearAll = () => { + this.props.clearAll(this.props.exploreId); + }; + + onRunQuery = () => { + this.props.runQuery(this.props.exploreId); + }; + render() { const { datasourceMissing, exploreDatasources, exploreId, loading, + range, selectedDatasource, splitted, - timepicker, + timepickerRef, } = this.props; return ( @@ -67,7 +94,7 @@ export class ExploreToolbar extends PureComponent {
{exploreId === 'right' && ( - + )} @@ -80,7 +107,7 @@ export class ExploreToolbar extends PureComponent {
@@ -92,14 +119,16 @@ export class ExploreToolbar extends PureComponent { {createResponsiveButton({ splitted, title: 'Split', - onClick: this.props.onSplit, + onClick: this.props.split, iconClassName: 'fa fa-fw fa-columns', })}
) : null} -
{timepicker}
+
+ +
-
@@ -107,7 +136,7 @@ export class ExploreToolbar extends PureComponent { {createResponsiveButton({ splitted, title: 'Run Query', - onClick: this.props.onRunQuery, + onClick: this.onRunQuery, buttonClassName: 'navbar-button--primary', iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon', })} @@ -118,3 +147,32 @@ export class ExploreToolbar extends PureComponent { ); } } + +const mapStateToProps = (state: StoreState, { exploreId }: OwnProps): StateProps => { + const splitted = state.explore.split; + const exploreItem = state.explore[exploreId]; + const { datasourceInstance, datasourceMissing, exploreDatasources, queryTransactions, range } = exploreItem; + const selectedDatasource = datasourceInstance + ? exploreDatasources.find(datasource => datasource.name === datasourceInstance.name) + : undefined; + const loading = queryTransactions.some(qt => !qt.done); + + return { + datasourceMissing, + exploreDatasources, + loading, + range, + selectedDatasource, + splitted, + }; +}; + +const mapDispatchToProps: DispatchProps = { + changeDatasource, + clearAll: clearQueries, + runQuery: runQueries, + closeSplit: splitClose, + split: splitOpen, +}; + +export const ExploreToolbar = hot(module)(connect(mapStateToProps, mapDispatchToProps)(UnConnectedExploreToolbar)); From 9298876ef0720a824f323ed251273ab8d0e9be2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 28 Jan 2019 12:21:04 +0100 Subject: [PATCH 14/22] Changes after PR Comments --- .../app/features/explore/ExploreToolbar.tsx | 45 +++++++++----- public/sass/pages/_explore.scss | 62 +++++++++++-------- 2 files changed, 66 insertions(+), 41 deletions(-) diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index a12871c50af..35f06d11c81 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -9,19 +9,30 @@ import { StoreState } from 'app/types/store'; import { changeDatasource, clearQueries, splitClose, runQueries, splitOpen } from './state/actions'; import TimePicker from './TimePicker'; +enum IconSide { + left = 'left', + right = 'right', +} + const createResponsiveButton = (options: { splitted: boolean; title: string; onClick: () => void; buttonClassName?: string; iconClassName?: string; + iconSide?: IconSide; }) => { - const { title, onClick, buttonClassName, iconClassName, splitted } = options; + const defaultOptions = { + iconSide: IconSide.left, + }; + const props = { ...options, defaultOptions }; + const { title, onClick, buttonClassName, iconClassName, splitted, iconSide } = props; return ( ); }; @@ -81,10 +92,10 @@ export class UnConnectedExploreToolbar extends PureComponent { } = this.props; return ( -
-
-
-
+
+
+ -
-
+
+
{!datasourceMissing ? ( -
+
{
) : null} {exploreId === 'left' && !splitted ? ( -
+
{createResponsiveButton({ splitted, title: 'Split', onClick: this.props.split, - iconClassName: 'fa fa-fw fa-columns', + iconClassName: 'fa fa-fw fa-columns icon-margin-right', + iconSide: IconSide.left, })}
) : null} -
+
-
+
-
+
{createResponsiveButton({ splitted, title: 'Run Query', onClick: this.onRunQuery, buttonClassName: 'navbar-button--primary', iconClassName: loading ? 'fa fa-spinner fa-fw fa-spin run-icon' : 'fa fa-level-down fa-fw run-icon', + iconSide: IconSide.right, })}
diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index 062387fdf67..db542530885 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -1,3 +1,15 @@ +.icon-margin-right { + margin-right: 0.25em; +} + +.icon-margin-left { + margin-left: 0.25em; +} + +.run-icon { + transform: rotate(90deg); +} + .timepicker { display: flex; } @@ -14,19 +26,19 @@ } .sidemenu-open { - .toolbar-header { + .explore-toolbar-header { padding: 0; margin-left: 0; } - .toolbar-header-title { + .explore-toolbar-header-title { .navbar-page-btn { padding-left: 0; } } } -.toolbar { +.explore-toolbar { background: inherit; display: flex; flex-flow: row wrap; @@ -39,27 +51,27 @@ transition-property: box-shadow, border-bottom; } -.toolbar-item { +.explore-toolbar-item { position: relative; align-self: center; } -.toolbar.splitted { - .toolbar-item { +.explore-toolbar.splitted { + .explore-toolbar-item { flex: 1 1 100%; } - .toolbar-content-item:first-child { + .explore-toolbar-content-item:first-child { padding-left: 0; margin-right: auto; } } -.toolbar-item:last-child { +.explore-toolbar-item:last-child { flex: auto; } -.toolbar-header { +.explore-toolbar-header { display: flex; flex: 1 1 0; flex-flow: row nowrap; @@ -70,12 +82,12 @@ margin-left: $panel-margin * 3; } -.toolbar-header { +.explore-toolbar-header { justify-content: space-between; align-items: center; } -.toolbar-header-title { +.explore-toolbar-header-title { color: darken($link-color, 5%); .navbar-page-btn { @@ -89,28 +101,28 @@ } } -.toolbar-header-close { +.explore-toolbar-header-close { margin-left: auto; } -.toolbar-content { +.explore-toolbar-content { display: flex; flex-flow: row wrap; align-items: center; justify-content: space-between; } -.toolbar-content-item { +.explore-toolbar-content-item { padding: 10px 2px; } -.toolbar-content-item:first-child { +.explore-toolbar-content-item:first-child { padding-left: $dashboard-padding; margin-right: auto; } @media only screen and (max-width: 1545px) { - .toolbar.splitted { + .explore-toolbar.splitted { .timepicker-rangestring { display: none; } @@ -124,25 +136,25 @@ } } - .toolbar-content { + .explore-toolbar-content { justify-content: flex-start; } - .toolbar.splitted { - .toolbar-content-item { + .explore-toolbar.splitted { + .explore-toolbar-content-item { padding: 2px 0; margin: 0; } } - .toolbar-content-item { + .explore-toolbar-content-item { padding: 2px 2px; } } @media only screen and (max-width: 803px) { .sidemenu-open { - .toolbar-header-title { + .explore-toolbar-header-title { .navbar-page-btn { padding-left: 0; margin-left: 0; @@ -150,7 +162,7 @@ } } - .toolbar-header-title { + .explore-toolbar-header-title { .navbar-page-btn { padding-left: 0; margin-left: $dashboard-padding; @@ -163,7 +175,7 @@ } @media only screen and (max-width: 702px) { - .toolbar-content-item:first-child { + .explore-toolbar-content-item:first-child { padding-left: 2px; margin-right: 0; } @@ -171,7 +183,7 @@ @media only screen and (max-width: 544px) { .sidemenu-open { - .toolbar-header-title { + .explore-toolbar-header-title { .navbar-page-btn { padding-left: 0; margin-left: $dashboard-padding; @@ -179,7 +191,7 @@ } } - .toolbar-header-title { + .explore-toolbar-header-title { .navbar-page-btn { padding-left: 0; margin-left: $dashboard-padding; From 6e672eb29175da522c2ccd7f79de51f42bcb60d5 Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 28 Jan 2019 13:02:54 +0100 Subject: [PATCH 15/22] enable explore by default closes #15037 --- conf/defaults.ini | 2 +- conf/sample.ini | 2 +- pkg/setting/setting.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 6fc4cf2e4de..4da3588bef2 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -504,7 +504,7 @@ concurrent_render_limit = 5 #################################### Explore ############################# [explore] # Enable the Explore section -enabled = false +enabled = true #################################### Internal Grafana Metrics ############ # Metrics available at HTTP API Url /metrics diff --git a/conf/sample.ini b/conf/sample.ini index 0f1c02dc231..8b731e43bd9 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -429,7 +429,7 @@ log_queries = #################################### Explore ############################# [explore] # Enable the Explore section -;enabled = false +;enabled = true #################################### Internal Grafana Metrics ########################## # Metrics available at HTTP API Url /metrics diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 660a00ba41d..d1eca777004 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -718,7 +718,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data") explore := iniFile.Section("explore") - ExploreEnabled = explore.Key("enabled").MustBool(false) + ExploreEnabled = explore.Key("enabled").MustBool(true) panels := iniFile.Section("panels") cfg.EnableAlphaPanels = panels.Key("enable_alpha").MustBool(false) From 6b0400eed2af71b708fa992b455c5a164036fefc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 28 Jan 2019 13:27:56 +0100 Subject: [PATCH 16/22] Firing off an action instead of listening to location changes --- public/app/features/explore/Wrapper.tsx | 8 +++++++- public/app/features/explore/state/actionTypes.ts | 9 +++++++-- public/app/features/explore/state/actions.ts | 12 ++++++++++-- public/app/features/explore/state/reducers.ts | 9 ++------- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/public/app/features/explore/Wrapper.tsx b/public/app/features/explore/Wrapper.tsx index 770b6bd6588..aca2e6d8cbd 100644 --- a/public/app/features/explore/Wrapper.tsx +++ b/public/app/features/explore/Wrapper.tsx @@ -7,7 +7,7 @@ import { StoreState } from 'app/types'; import { ExploreId, ExploreUrlState } from 'app/types/explore'; import { parseUrlState } from 'app/core/utils/explore'; -import { initializeExploreSplit } from './state/actions'; +import { initializeExploreSplit, resetExplore } from './state/actions'; import ErrorBoundary from './ErrorBoundary'; import Explore from './Explore'; import { CustomScrollbar } from '@grafana/ui'; @@ -16,6 +16,7 @@ interface WrapperProps { initializeExploreSplit: typeof initializeExploreSplit; split: boolean; updateLocation: typeof updateLocation; + resetExplore: typeof resetExplore; urlStates: { [key: string]: string }; } @@ -42,6 +43,10 @@ export class Wrapper extends Component { } } + componentWillUnmount() { + this.props.resetExplore(); + } + render() { const { split } = this.props; const { leftState, rightState } = this.urlStates; @@ -74,6 +79,7 @@ const mapStateToProps = (state: StoreState) => { const mapDispatchToProps = { initializeExploreSplit, updateLocation, + resetExplore, }; export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(Wrapper)); diff --git a/public/app/features/explore/state/actionTypes.ts b/public/app/features/explore/state/actionTypes.ts index 219e3fb6fc9..21918e1c013 100644 --- a/public/app/features/explore/state/actionTypes.ts +++ b/public/app/features/explore/state/actionTypes.ts @@ -9,7 +9,6 @@ import { ResultType, QueryTransaction, } from 'app/types/explore'; -import { UpdateLocationAction } from 'app/core/actions/location'; export enum ActionTypes { AddQueryRow = 'explore/ADD_QUERY_ROW', @@ -42,6 +41,7 @@ export enum ActionTypes { ToggleGraph = 'explore/TOGGLE_GRAPH', ToggleLogs = 'explore/TOGGLE_LOGS', ToggleTable = 'explore/TOGGLE_TABLE', + ResetExplore = 'explore/RESET_EXPLORE', } export interface AddQueryRowAction { @@ -271,6 +271,11 @@ export interface ToggleLogsAction { }; } +export interface ResetExploreAction { + type: ActionTypes.ResetExplore; + payload: {}; +} + export type Action = | AddQueryRowAction | ChangeQueryAction @@ -299,4 +304,4 @@ export type Action = | ToggleGraphAction | ToggleLogsAction | ToggleTableAction - | UpdateLocationAction; + | ResetExploreAction; diff --git a/public/app/features/explore/state/actions.ts b/public/app/features/explore/state/actions.ts index d4c42ffa9c7..f09612322ae 100644 --- a/public/app/features/explore/state/actions.ts +++ b/public/app/features/explore/state/actions.ts @@ -21,7 +21,7 @@ import { updateLocation } from 'app/core/actions'; // Types import { StoreState } from 'app/types'; -import { DataQuery, DataSourceSelectItem, QueryHint } from '@grafana/ui/src/types'; +import { DataQuery, DataSourceSelectItem, QueryHint } from '@grafana/ui/src/types'; import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { ExploreId, @@ -48,7 +48,6 @@ import { ScanStopAction, } from './actionTypes'; - type ThunkResult = ThunkAction; /** @@ -766,3 +765,12 @@ export function toggleTable(exploreId: ExploreId): ThunkResult { } }; } + +/** + * Resets state for explore. + */ +export function resetExplore(): ThunkResult { + return dispatch => { + dispatch({ type: ActionTypes.ResetExplore, payload: {} }); + }; +} diff --git a/public/app/features/explore/state/reducers.ts b/public/app/features/explore/state/reducers.ts index ccad9392c06..7a240350cb6 100644 --- a/public/app/features/explore/state/reducers.ts +++ b/public/app/features/explore/state/reducers.ts @@ -8,7 +8,6 @@ import { ExploreItemState, ExploreState, QueryTransaction } from 'app/types/expl import { DataQuery } from '@grafana/ui/src/types'; import { Action, ActionTypes } from './actionTypes'; -import { CoreActionTypes } from 'app/core/actions/location'; export const DEFAULT_RANGE = { from: 'now-6h', @@ -440,12 +439,8 @@ export const exploreReducer = (state = initialExploreState, action: Action): Exp return { ...state, split: true }; } - case CoreActionTypes.UpdateLocation: { - if (action.payload.path && action.payload.path !== '/explore') { - return initialExploreState; - } - - return state; + case ActionTypes.ResetExplore: { + return initialExploreState; } } From d433a4792a9e3ae0547b5e8fe83d5b7fed9320e1 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Mon, 28 Jan 2019 14:07:37 +0100 Subject: [PATCH 17/22] fixing test --- .../features/dashboard/services/DashboardViewStateSrv.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts b/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts index aee6746ff36..0003d5c91e8 100644 --- a/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts +++ b/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts @@ -58,7 +58,7 @@ describe('when updating view state', () => { it('should remove params from query string', () => { viewState.update({ fullscreen: true, panelId: 1, edit: true }); viewState.update({ fullscreen: false }); - expect(viewState.dashboard.meta.fullscreen).toBe(false); + expect(viewState.dashboard.meta.fullscreen).toBe(true); expect(viewState.state.fullscreen).toBe(null); }); }); From dc125f1e4d153bc19cd7b803e0cdff04f4b5265f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 28 Jan 2019 13:03:33 +0100 Subject: [PATCH 18/22] Made sure we only resetTypeahead if mounted --- public/app/features/explore/QueryField.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/public/app/features/explore/QueryField.tsx b/public/app/features/explore/QueryField.tsx index 24b8b8f5b16..d27213cea34 100644 --- a/public/app/features/explore/QueryField.tsx +++ b/public/app/features/explore/QueryField.tsx @@ -73,6 +73,7 @@ export class QueryField extends React.PureComponent { - this.setState({ - suggestions: [], - typeaheadIndex: 0, - typeaheadPrefix: '', - typeaheadContext: null, - }); - this.resetTimer = null; + if (this.mounted) { + this.setState({ + suggestions: [], + typeaheadIndex: 0, + typeaheadPrefix: '', + typeaheadContext: null, + }); + this.resetTimer = null; + } }; handleBlur = () => { From 520756fb4ced5911668ba3eb8ad1fe90015e37a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 28 Jan 2019 14:44:35 +0100 Subject: [PATCH 19/22] Fixed wrong line in test --- .../features/dashboard/services/DashboardViewStateSrv.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts b/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts index 0003d5c91e8..20215017e1d 100644 --- a/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts +++ b/public/app/features/dashboard/services/DashboardViewStateSrv.test.ts @@ -58,7 +58,6 @@ describe('when updating view state', () => { it('should remove params from query string', () => { viewState.update({ fullscreen: true, panelId: 1, edit: true }); viewState.update({ fullscreen: false }); - expect(viewState.dashboard.meta.fullscreen).toBe(true); expect(viewState.state.fullscreen).toBe(null); }); }); From 2dc2471b5ccc6e63b78e884b98876e9c7a39bcc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 28 Jan 2019 15:01:42 +0100 Subject: [PATCH 20/22] Revert "Updated home dashboard, removed home dashboard header" This reverts commit 0151846e1e0c624f2490dcf0bfbead5d0a8e9218. --- pkg/api/dashboard.go | 2 +- public/dashboards/home.json | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 5959c230fb9..2789b0bf51e 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -336,7 +336,7 @@ func addGettingStartedPanelToHomeDashboard(dash *simplejson.Json) { "id": 123123, "gridPos": map[string]interface{}{ "x": 0, - "y": 0, + "y": 3, "w": 24, "h": 4, }, diff --git a/public/dashboards/home.json b/public/dashboards/home.json index 17795d64aa3..f2c441053bb 100644 --- a/public/dashboards/home.json +++ b/public/dashboards/home.json @@ -10,6 +10,23 @@ "id": null, "links": [], "panels": [ + { + "content": "
\n Home Dashboard\n
", + "editable": true, + "id": 1, + "links": [], + "mode": "html", + "style": {}, + "title": "", + "transparent": true, + "type": "text", + "gridPos": { + "w": 24, + "h": 3, + "x": 0, + "y": 0 + } + }, { "folderId": 0, "headings": true, @@ -28,7 +45,7 @@ "w": 12, "h": 17, "x": 0, - "y": 1 + "y": 6 } }, { @@ -43,7 +60,7 @@ "w": 12, "h": 17, "x": 12, - "y": 1 + "y": 6 } } ], From 08f5a3338ada16a1fef53e222d3df79abe31b147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Mon, 28 Jan 2019 15:27:35 +0100 Subject: [PATCH 21/22] Making sure we do not pass a long invalid queries and save to state --- public/app/features/explore/state/actions.ts | 1 + public/app/plugins/datasource/loki/language_provider.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/public/app/features/explore/state/actions.ts b/public/app/features/explore/state/actions.ts index f09612322ae..59df0c47ef9 100644 --- a/public/app/features/explore/state/actions.ts +++ b/public/app/features/explore/state/actions.ts @@ -538,6 +538,7 @@ export function runQueries(exploreId: ExploreId) { if (!hasNonEmptyQuery(modifiedQueries)) { dispatch({ type: ActionTypes.RunQueriesEmpty, payload: { exploreId } }); + dispatch(stateSave()); // Remember to saves to state and update location return; } diff --git a/public/app/plugins/datasource/loki/language_provider.ts b/public/app/plugins/datasource/loki/language_provider.ts index 115a0a5f11f..631e61277b8 100644 --- a/public/app/plugins/datasource/loki/language_provider.ts +++ b/public/app/plugins/datasource/loki/language_provider.ts @@ -173,8 +173,9 @@ export default class LokiLanguageProvider extends LanguageProvider { }) ); } + // Return a cleaned LokiQuery return queries.map(query => ({ - ...query, + refId: query.refId, expr: '', })); } From 55f2495afa043b67f9fc567d59c58eccc5d767c8 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Fri, 25 Jan 2019 13:27:38 +0100 Subject: [PATCH 22/22] build: publishes armv6 to grafana.com. Stops using the old publisher completely. Closes #13008 --- .circleci/config.yml | 6 +- scripts/build/publish.go | 194 ------------------- scripts/build/release_publisher/publisher.go | 10 + 3 files changed, 11 insertions(+), 199 deletions(-) delete mode 100644 scripts/build/publish.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 7b5a9e7923b..7e89ffe7a1f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,9 +147,6 @@ jobs: - run: name: sha-sum packages command: 'go run build.go sha-dist' - - run: - name: Build Grafana.com master publisher - command: 'go build -o scripts/publish scripts/build/publish.go' - run: name: Test and build Grafana.com release publisher command: 'cd scripts/build/release_publisher && go test . && go build -o release_publisher .' @@ -158,7 +155,6 @@ jobs: paths: - dist/grafana* - scripts/*.sh - - scripts/publish - scripts/build/release_publisher/release_publisher - scripts/build/publish.sh @@ -393,7 +389,7 @@ jobs: name: Publish to Grafana.com command: | rm dist/grafana-master-$(echo "${CIRCLE_SHA1}" | cut -b1-7).linux-x64.tar.gz - ./scripts/publish -apiKey ${GRAFANA_COM_API_KEY} + cd dist && ../scripts/build/release_publisher/release_publisher -apikey ${GRAFANA_COM_API_KEY} -from-local deploy-release: docker: diff --git a/scripts/build/publish.go b/scripts/build/publish.go deleted file mode 100644 index 0cb776e2b99..00000000000 --- a/scripts/build/publish.go +++ /dev/null @@ -1,194 +0,0 @@ -package main - -import ( - "bytes" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "path/filepath" - "regexp" - "strings" - "time" -) - -var apiURL = flag.String("apiUrl", "https://grafana.com/api", "api url") -var apiKey = flag.String("apiKey", "", "api key") -var version = "" -var versionRe = regexp.MustCompile(`grafana-(.*)(\.|_)(arm64|armhfp|aarch64|armv7|darwin|linux|windows|x86_64)`) -var debVersionRe = regexp.MustCompile(`grafana_(.*)_(arm64|armv7|armhf|amd64)\.deb`) -var builds = []build{} -var architectureMapping = map[string]string{ - "armv7": "armv7", - "armhfp": "armv7", - "armhf": "armv7", - "arm64": "arm64", - "aarch64": "arm64", - "amd64": "amd64", - "x86_64": "amd64", -} - -func main() { - flag.Parse() - if *apiKey == "" { - log.Fatalf("Require apiKey command line parameters") - } - - err := filepath.Walk("dist", packageWalker) - if err != nil { - log.Fatalf("Cannot find any packages to publish, %v", err) - } - - if version == "" { - log.Fatalf("No version found") - } - - if len(builds) == 0 { - log.Fatalf("No builds found") - } - - nightly := release{ - Version: version, - ReleaseDate: time.Now(), - Stable: false, - Nightly: true, - Beta: false, - WhatsNewURL: "", - ReleaseNotesURL: "", - Builds: builds, - } - - postRequest("/grafana/versions", nightly, fmt.Sprintf("Create Release %s", nightly.Version)) - postRequest("/grafana/versions/"+nightly.Version, nightly, fmt.Sprintf("Update Release %s", nightly.Version)) - - for _, b := range nightly.Builds { - postRequest(fmt.Sprintf("/grafana/versions/%s/packages", nightly.Version), b, fmt.Sprintf("Create Build %s %s", b.Os, b.Arch)) - postRequest(fmt.Sprintf("/grafana/versions/%s/packages/%s/%s", nightly.Version, b.Arch, b.Os), b, fmt.Sprintf("Update Build %s %s", b.Os, b.Arch)) - } -} - -func mapPackage(path string, name string, shaBytes []byte) (build, error) { - log.Printf("Finding package file %s", name) - result := versionRe.FindSubmatch([]byte(name)) - debResult := debVersionRe.FindSubmatch([]byte(name)) - - if len(result) > 0 { - version = string(result[1]) - log.Printf("Version detected: %v", version) - } else if len(debResult) > 0 { - version = string(debResult[1]) - } else { - return build{}, fmt.Errorf("Unable to figure out version from '%v'", name) - } - - os := "" - if strings.Contains(name, "linux") { - os = "linux" - } - if strings.HasSuffix(name, "windows-amd64.zip") { - os = "win" - } - if strings.HasSuffix(name, "darwin-amd64.tar.gz") { - os = "darwin" - } - if strings.HasSuffix(name, ".rpm") { - os = "rhel" - } - if strings.HasSuffix(name, ".deb") { - os = "deb" - } - if os == "" { - return build{}, fmt.Errorf("Unable to figure out os from '%v'", name) - } - - arch := "" - for archListed, archReal := range architectureMapping { - if strings.Contains(name, archListed) { - arch = archReal - break - } - } - if arch == "" { - return build{}, fmt.Errorf("Unable to figure out arch from '%v'", name) - } - - return build{ - Os: os, - Arch: arch, - URL: "https://s3-us-west-2.amazonaws.com/grafana-releases/master/" + name, - Sha256: string(shaBytes), - }, nil -} - -func packageWalker(path string, f os.FileInfo, err error) error { - if err != nil { - log.Printf("error: %v", err) - } - if f.Name() == "dist" || strings.Contains(f.Name(), "sha256") || strings.Contains(f.Name(), "latest") { - return nil - } - - shaBytes, err := ioutil.ReadFile(path + ".sha256") - if err != nil { - log.Fatalf("Failed to read sha256 file %v", err) - } - - build, err := mapPackage(path, f.Name(), shaBytes) - if err != nil { - log.Printf("Could not map metadata from package: %v", err) - return nil - } - - builds = append(builds, build) - return nil -} - -func postRequest(url string, obj interface{}, desc string) { - jsonBytes, _ := json.Marshal(obj) - req, _ := http.NewRequest(http.MethodPost, (*apiURL)+url, bytes.NewReader(jsonBytes)) - req.Header.Add("Authorization", "Bearer "+(*apiKey)) - req.Header.Add("Content-Type", "application/json") - - res, err := http.DefaultClient.Do(req) - if err != nil { - log.Fatalf("error: %v", err) - } - - if res.StatusCode == http.StatusOK { - log.Printf("Action: %s \t OK", desc) - } else { - - if res.Body != nil { - defer res.Body.Close() - body, _ := ioutil.ReadAll(res.Body) - if strings.Contains(string(body), "already exists") || strings.Contains(string(body), "Nothing to update") { - log.Printf("Action: %s \t Already exists", desc) - } else { - log.Printf("Action: %s \t Failed - Status: %v", desc, res.Status) - log.Printf("Resp: %s", body) - log.Fatalf("Quitting") - } - } - } -} - -type release struct { - Version string `json:"version"` - ReleaseDate time.Time `json:"releaseDate"` - Stable bool `json:"stable"` - Beta bool `json:"beta"` - Nightly bool `json:"nightly"` - WhatsNewURL string `json:"whatsNewUrl"` - ReleaseNotesURL string `json:"releaseNotesUrl"` - Builds []build `json:"-"` -} - -type build struct { - Os string `json:"os"` - URL string `json:"url"` - Sha256 string `json:"sha256"` - Arch string `json:"arch"` -} diff --git a/scripts/build/release_publisher/publisher.go b/scripts/build/release_publisher/publisher.go index 77b7e18b724..8fd139c2638 100644 --- a/scripts/build/release_publisher/publisher.go +++ b/scripts/build/release_publisher/publisher.go @@ -127,11 +127,21 @@ var completeBuildArtifactConfigurations = []buildArtifact{ arch: "armv7", urlPostfix: "_armhf.deb", }, + { + os: "deb", + arch: "armv6", + urlPostfix: "_armel.deb", + }, { os: "rhel", arch: "armv7", urlPostfix: ".armhfp.rpm", }, + { + os: "linux", + arch: "armv6", + urlPostfix: ".linux-armv6.tar.gz", + }, { os: "linux", arch: "armv7",