diff --git a/packaging/publish/publish_both.sh b/packaging/publish/publish_both.sh index b1d480567e9..b86c20011e0 100755 --- a/packaging/publish/publish_both.sh +++ b/packaging/publish/publish_both.sh @@ -1,17 +1,17 @@ #! /usr/bin/env bash -version=5.4.1 +version=5.4.2 -wget https://dl.grafana.com/oss/release/grafana_${version}_amd64.deb +# wget https://dl.grafana.com/oss/release/grafana_${version}_amd64.deb +# +# package_cloud push grafana/stable/debian/jessie grafana_${version}_amd64.deb +# package_cloud push grafana/stable/debian/wheezy grafana_${version}_amd64.deb +# package_cloud push grafana/stable/debian/stretch grafana_${version}_amd64.deb +# +# package_cloud push grafana/testing/debian/jessie grafana_${version}_amd64.deb +# package_cloud push grafana/testing/debian/wheezy grafana_${version}_amd64.deb --verbose +# package_cloud push grafana/testing/debian/stretch grafana_${version}_amd64.deb --verbose -package_cloud push grafana/stable/debian/jessie grafana_${version}_amd64.deb -package_cloud push grafana/stable/debian/wheezy grafana_${version}_amd64.deb -package_cloud push grafana/stable/debian/stretch grafana_${version}_amd64.deb - -package_cloud push grafana/testing/debian/jessie grafana_${version}_amd64.deb -package_cloud push grafana/testing/debian/wheezy grafana_${version}_amd64.deb --verbose -package_cloud push grafana/testing/debian/stretch grafana_${version}_amd64.deb --verbose - -wget https://dl.grafana.com/release/grafana-${version}-1.x86_64.rpm +wget https://dl.grafana.com/oss/release/grafana-${version}-1.x86_64.rpm package_cloud push grafana/testing/el/6 grafana-${version}-1.x86_64.rpm --verbose package_cloud push grafana/testing/el/7 grafana-${version}-1.x86_64.rpm --verbose diff --git a/public/app/core/components/Form/Input.tsx b/public/app/core/components/Form/Input.tsx index 6ba58b45e91..7940f3b1104 100644 --- a/public/app/core/components/Form/Input.tsx +++ b/public/app/core/components/Form/Input.tsx @@ -1,4 +1,5 @@ -import React, { PureComponent } from 'react'; +import React, { PureComponent } from 'react'; +import classNames from 'classnames'; import { ValidationEvents, ValidationRule } from 'app/types'; import { validate, hasValidationEvent } from 'app/core/utils/validate'; @@ -31,6 +32,10 @@ interface Props extends React.HTMLProps { } export class Input extends PureComponent { + static defaultProps = { + className: '', + }; + state = { error: null, }; @@ -76,7 +81,7 @@ export class Input extends PureComponent { render() { const { validationEvents, className, hideErrorMessage, ...restProps } = this.props; const { error } = this.state; - const inputClassName = 'gf-form-input' + (this.isInvalid ? ' invalid' : ''); + const inputClassName = classNames('gf-form-input', { invalid: this.isInvalid }, className); const inputElementProps = this.populateEventPropsWithStatus(restProps, validationEvents); return ( diff --git a/public/app/core/components/Picker/Unit/UnitPicker.tsx b/public/app/core/components/Picker/Unit/UnitPicker.tsx index 5d09a82d846..f5c76e43fe4 100644 --- a/public/app/core/components/Picker/Unit/UnitPicker.tsx +++ b/public/app/core/components/Picker/Unit/UnitPicker.tsx @@ -36,25 +36,25 @@ export default class UnitPicker extends PureComponent { }; }); - const styles = { - ...ResetStyles, - menu: () => ({ - maxHeight: '75%', - overflow: 'scroll', - }), - menuList: () => - ({ - overflowY: 'auto', - position: 'relative', - } as React.CSSProperties), - valueContainer: () => - ({ - overflow: 'hidden', - textOverflow: 'ellipsis', - maxWidth: '90px', - whiteSpace: 'nowrap', - } as React.CSSProperties), - }; + // const styles = { + // ...ResetStyles, + // menu: () => ({ + // maxHeight: '75%', + // overflow: 'scroll', + // }), + // menuList: () => + // ({ + // overflowY: 'auto', + // position: 'relative', + // } as React.CSSProperties), + // valueContainer: () => + // ({ + // overflow: 'hidden', + // textOverflow: 'ellipsis', + // maxWidth: '90px', + // whiteSpace: 'nowrap', + // } as React.CSSProperties), + // }; const value = groupOptions.map(group => { return group.options.find(option => option.value === defaultValue); @@ -74,7 +74,7 @@ export default class UnitPicker extends PureComponent { Group: UnitGroup, Option: UnitOption, }} - styles={styles} + styles={ResetStyles} /> ); } diff --git a/public/app/features/alerting/partials/alert_tab.html b/public/app/features/alerting/partials/alert_tab.html index 2ebe2b53a76..2c9b64cf6d2 100644 --- a/public/app/features/alerting/partials/alert_tab.html +++ b/public/app/features/alerting/partials/alert_tab.html @@ -1,187 +1,189 @@ -
- +
+
+ -
-
-
- {{ctrl.error}} -
+
+
+
+ {{ctrl.error}} +
-
-
Alert Config
-
- Name - -
-
-
- Evaluate every - -
-
- - - - If an alert rule has a configured For and the query violates the configured threshold it will first go from OK to Pending. - Going from OK to Pending Grafana will not send any notifications. Once the alert rule has been firing for more than For duration, it will change to Alerting and send alert notifications. - -
-
-
+
+
Alert Config
+
+ Name + +
+
+
+ Evaluate every + +
+
+ + + + If an alert rule has a configured For and the query violates the configured threshold it will first go from OK to Pending. + Going from OK to Pending Grafana will not send any notifications. Once the alert rule has been firing for more than For duration, it will change to Alerting and send alert notifications. + +
+
+
-
-
Conditions
-
-
- - WHEN -
-
- - - OF -
-
- - -
-
- - - - -
-
- -
-
+
+
Conditions
+
+
+ + WHEN +
+
+ + + OF +
+
+ + +
+
+ + + + +
+
+ +
+
-
- -
-
+
+ +
+
-
-
- If no data or all values are null - SET STATE TO -
- -
-
+
+
+ If no data or all values are null + SET STATE TO +
+ +
+
-
- If execution error or timeout - SET STATE TO -
- -
-
+
+ If execution error or timeout + SET STATE TO +
+ +
+
-
- -
-
+
+ +
+
-
- Evaluating rule -
+
+ Evaluating rule +
-
- -
-
+
+ +
+
-
-
Notifications
-
-
- Send to - -  {{nc.name}}  - - - -
-
-
- Message - -
-
+
+
Notifications
+
+
+ Send to + +  {{nc.name}}  + + + +
+
+
+ Message + +
+
-
- -
- State history (last 50 state changes) -
+
+ +
+ State history (last 50 state changes) +
-
-
- No state changes recorded -
+
+
+ No state changes recorded +
-
    -
  1. -
    - -
    -
    -
    -
    - {{al.stateModel.text}} -
    -
    - {{al.info}} -
    -
    - {{al.time}} -
    -
  2. -
-
-
-
+
    +
  1. +
    + +
    +
    +
    +
    + {{al.stateModel.text}} +
    +
    + {{al.info}} +
    +
    + {{al.time}} +
    +
  2. +
+
+
+
-
-
- -
+
+
+ +
+
diff --git a/public/app/features/dashboard/dashboard_migration.ts b/public/app/features/dashboard/dashboard_migration.ts index 9fcf1b8d91b..abd12ab4b13 100644 --- a/public/app/features/dashboard/dashboard_migration.ts +++ b/public/app/features/dashboard/dashboard_migration.ts @@ -141,7 +141,6 @@ export class DashboardMigrator { // ensure query refIds panelUpgrades.push(panel => { - console.log('asdasd', panel); _.each(panel.targets, target => { if (!target.refId) { target.refId = panel.getNextQueryLetter && panel.getNextQueryLetter(); diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 4ae12fc24b4..6ee83d6e5b9 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -76,16 +76,16 @@ export class DashboardPanel extends PureComponent { // unmount angular panel this.cleanUpAngularPanel(); - if (plugin.exports) { - this.setState({ plugin: plugin }); - } else { - plugin.exports = await importPluginModule(plugin.module); - this.setState({ plugin: plugin }); - } - if (panel.type !== pluginId) { this.props.panel.changeType(pluginId, fromAngularPanel); } + + if (plugin.exports) { + this.setState({ plugin: plugin, angularPanel: null }); + } else { + plugin.exports = await importPluginModule(plugin.module); + this.setState({ plugin: plugin, angularPanel: null }); + } } } @@ -106,18 +106,15 @@ export class DashboardPanel extends PureComponent { this.setState({ angularPanel }); } - cleanUpAngularPanel(unmounted?: boolean) { + cleanUpAngularPanel() { if (this.state.angularPanel) { this.state.angularPanel.destroy(); - - if (!unmounted) { - this.setState({ angularPanel: null }); - } + this.element = null; } } componentWillUnmount() { - this.cleanUpAngularPanel(true); + this.cleanUpAngularPanel(); } onMouseEnter = () => { diff --git a/public/app/features/dashboard/dashgrid/EditorTabBody.tsx b/public/app/features/dashboard/dashgrid/EditorTabBody.tsx index 42c6b33764b..7606d327405 100644 --- a/public/app/features/dashboard/dashgrid/EditorTabBody.tsx +++ b/public/app/features/dashboard/dashgrid/EditorTabBody.tsx @@ -1,6 +1,10 @@ +// Libraries import React, { PureComponent } from 'react'; + +// Components import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar'; import { FadeIn } from 'app/core/components/Animations/FadeIn'; +import { PanelOptionSection } from './PanelOptionSection'; interface Props { children: JSX.Element; @@ -10,7 +14,8 @@ interface Props { } export interface EditorToolBarView { - title: string; + title?: string; + heading?: string; imgSrc?: string; icon?: string; disabled?: boolean; @@ -88,12 +93,9 @@ export class EditorTabBody extends PureComponent { renderOpenView(view: EditorToolBarView) { return ( -
- - {view.render(this.onCloseOpenView)} -
+ + {view.render()} + ); } @@ -115,10 +117,10 @@ export class EditorTabBody extends PureComponent {
- -
{openView && this.renderOpenView(openView)}
-
+ + {openView && this.renderOpenView(openView)} + {children} diff --git a/public/app/features/dashboard/dashgrid/PanelOptionSection.tsx b/public/app/features/dashboard/dashgrid/PanelOptionSection.tsx new file mode 100644 index 00000000000..f38d99d2237 --- /dev/null +++ b/public/app/features/dashboard/dashgrid/PanelOptionSection.tsx @@ -0,0 +1,26 @@ +// Libraries +import React, { SFC } from 'react'; + +interface Props { + title?: string; + onClose?: () => void; + children: JSX.Element | JSX.Element[]; +} + +export const PanelOptionSection: SFC = props => { + return ( +
+ {props.title && ( +
+ {props.title} + {props.onClose && ( + + )} +
+ )} +
{props.children}
+
+ ); +}; diff --git a/public/app/features/dashboard/dashgrid/QueriesTab.tsx b/public/app/features/dashboard/dashgrid/QueriesTab.tsx index 31480403743..cd26defbed3 100644 --- a/public/app/features/dashboard/dashgrid/QueriesTab.tsx +++ b/public/app/features/dashboard/dashgrid/QueriesTab.tsx @@ -4,13 +4,13 @@ import Remarkable from 'remarkable'; import _ from 'lodash'; // Components -import DataSourceOption from './DataSourceOption'; +import './../../panel/metrics_tab'; import { EditorTabBody } from './EditorTabBody'; import { DataSourcePicker } from './DataSourcePicker'; import { QueryInspector } from './QueryInspector'; -import { TimeRangeOptions } from './TimeRangeOptions'; -import './../../panel/metrics_tab'; +import { QueryOptions } from './QueryOptions'; import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab'; +import { PanelOptionSection } from './PanelOptionSection'; // Services import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; @@ -157,75 +157,6 @@ export class QueriesTab extends PureComponent { } }; - renderOptions = close => { - const { currentDS } = this.state; - const { queryOptions } = currentDS.meta; - const { panel } = this.props; - - const onChangeFn = (panelKey: string) => { - return (value: string | number) => { - panel[panelKey] = value; - panel.refresh(); - }; - }; - - const allOptions = { - cacheTimeout: { - label: 'Cache timeout', - placeholder: '60', - name: 'cacheTimeout', - value: panel.cacheTimeout, - tooltipInfo: ( - <> - If your time series store has a query cache this option can override the default cache timeout. Specify a - numeric value in seconds. - - ), - }, - maxDataPoints: { - label: 'Max data points', - placeholder: 'auto', - name: 'maxDataPoints', - value: panel.maxDataPoints, - tooltipInfo: ( - <> - The maximum data points the query should return. For graphs this is automatically set to one data point per - pixel. - - ), - }, - minInterval: { - label: 'Min time interval', - placeholder: '0', - name: 'minInterval', - value: panel.interval, - panelKey: 'interval', - tooltipInfo: ( - <> - A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '} - 1m if your data is written every minute. Access auto interval via variable{' '} - $__interval for time range string and $__interval_ms for numeric variable that can - be used in math expressions. - - ), - }, - }; - - const dsOptions = queryOptions - ? Object.keys(queryOptions).map(key => { - const options = allOptions[key]; - return ; - }) - : null; - - return ( - <> - - {dsOptions} - - ); - }; - renderQueryInspector = () => { const { panel } = this.props; return ; @@ -316,46 +247,42 @@ export class QueriesTab extends PureComponent { }; const dsHelp = { - title: '', + heading: 'Help', icon: 'fa fa-question', disabled: !hasQueryHelp, onClick: this.loadHelp, render: this.renderHelp, }; - const options = { - title: 'Time Range', - icon: '', - disabled: false, - render: this.renderOptions, - }; - return ( - -
-
(this.element = element)} /> + + <> + +
+
(this.element = element)} /> -
-
- - {!isAddingMixed && ( - - )} - {isAddingMixed && this.renderMixedPicker()} +
+
+ + {!isAddingMixed && ( + + )} + {isAddingMixed && this.renderMixedPicker()} +
+
-
-
+ + + + + ); } diff --git a/public/app/features/dashboard/dashgrid/QueryInspector.tsx b/public/app/features/dashboard/dashgrid/QueryInspector.tsx index ec618404651..090bc220bc0 100644 --- a/public/app/features/dashboard/dashgrid/QueryInspector.tsx +++ b/public/app/features/dashboard/dashgrid/QueryInspector.tsx @@ -1,4 +1,4 @@ -import React, { PureComponent } from 'react'; +import React, { PureComponent } from 'react'; import { JSONFormatter } from 'app/core/components/JSONFormatter/JSONFormatter'; import appEvents from 'app/core/app_events'; import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard'; @@ -187,16 +187,10 @@ export class QueryInspector extends PureComponent { return ( <> -
- {/* - - */} +
- { + if (!value) { + return true; + } + return isValidTimeSpan(value); + }, + errorMessage: 'Not a valid timespan', + }, + ], +}; + +const emptyToNull = (value: string) => { + return value === '' ? null : value; +}; + +interface Props { + panel: PanelModel; + datasource: DataSourceSelectItem; +} + +export class QueryOptions extends PureComponent { + onOverrideTime = (evt, status: InputStatus) => { + const { value } = evt.target; + const { panel } = this.props; + const emptyToNullValue = emptyToNull(value); + if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) { + panel.timeFrom = emptyToNullValue; + panel.refresh(); + } + }; + + onTimeShift = (evt, status: InputStatus) => { + const { value } = evt.target; + const { panel } = this.props; + const emptyToNullValue = emptyToNull(value); + if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) { + panel.timeShift = emptyToNullValue; + panel.refresh(); + } + }; + + onToggleTimeOverride = () => { + const { panel } = this.props; + panel.hideTimeOverride = !panel.hideTimeOverride; + panel.refresh(); + }; + + renderOptions() { + const { datasource, panel } = this.props; + const { queryOptions } = datasource.meta; + + if (!queryOptions) { + return null; + } + + const onChangeFn = (panelKey: string) => { + return (value: string | number) => { + panel[panelKey] = value; + panel.refresh(); + }; + }; + + const allOptions = { + cacheTimeout: { + label: 'Cache timeout', + placeholder: '60', + name: 'cacheTimeout', + value: panel.cacheTimeout, + tooltipInfo: ( + <> + If your time series store has a query cache this option can override the default cache timeout. Specify a + numeric value in seconds. + + ), + }, + maxDataPoints: { + label: 'Max data points', + placeholder: 'auto', + name: 'maxDataPoints', + value: panel.maxDataPoints, + tooltipInfo: ( + <> + The maximum data points the query should return. For graphs this is automatically set to one data point per + pixel. + + ), + }, + minInterval: { + label: 'Min time interval', + placeholder: '0', + name: 'minInterval', + value: panel.interval, + panelKey: 'interval', + tooltipInfo: ( + <> + A lower limit for the auto group by time interval. Recommended to be set to write frequency, for example{' '} + 1m if your data is written every minute. Access auto interval via variable{' '} + $__interval for time range string and $__interval_ms for numeric variable that can + be used in math expressions. + + ), + }, + }; + + return Object.keys(queryOptions).map(key => { + const options = allOptions[key]; + return ; + }); + } + + render = () => { + const hideTimeOverride = this.props.panel.hideTimeOverride; + return ( +
+ {this.renderOptions()} + +
+ Relative time + +
+ +
+ Time shift + +
+ +
+ +
+
+ ); + }; +} diff --git a/public/app/features/dashboard/dashgrid/TimeRangeOptions.tsx b/public/app/features/dashboard/dashgrid/TimeRangeOptions.tsx deleted file mode 100644 index 00371fa960b..00000000000 --- a/public/app/features/dashboard/dashgrid/TimeRangeOptions.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import React, { PureComponent } from 'react'; -import { Switch } from 'app/core/components/Switch/Switch'; -import { Input } from 'app/core/components/Form'; -import { isValidTimeSpan } from 'app/core/utils/rangeutil'; -import { ValidationEvents } from 'app/types'; -import { EventsWithValidation } from 'app/core/components/Form/Input'; -import { PanelModel } from '../panel_model'; -import { InputStatus } from 'app/core/components/Form/Input'; - -const timeRangeValidationEvents: ValidationEvents = { - [EventsWithValidation.onBlur]: [ - { - rule: value => { - if (!value) { - return true; - } - return isValidTimeSpan(value); - }, - errorMessage: 'Not a valid timespan', - }, - ], -}; - -const emptyToNull = (value: string) => { - return value === '' ? null : value; -}; - -interface Props { - panel: PanelModel; -} - -export class TimeRangeOptions extends PureComponent { - onOverrideTime = (evt, status: InputStatus) => { - const { value } = evt.target; - const { panel } = this.props; - const emptyToNullValue = emptyToNull(value); - if (status === InputStatus.Valid && panel.timeFrom !== emptyToNullValue) { - panel.timeFrom = emptyToNullValue; - panel.refresh(); - } - }; - - onTimeShift = (evt, status: InputStatus) => { - const { value } = evt.target; - const { panel } = this.props; - const emptyToNullValue = emptyToNull(value); - if (status === InputStatus.Valid && panel.timeShift !== emptyToNullValue) { - panel.timeShift = emptyToNullValue; - panel.refresh(); - } - }; - - onToggleTimeOverride = () => { - const { panel } = this.props; - panel.hideTimeOverride = !panel.hideTimeOverride; - panel.refresh(); - }; - - render = () => { - const hideTimeOverride = this.props.panel.hideTimeOverride; - return ( - <> -
Time Range
- -
-
- Override relative time - -
- -
- Add time shift - -
- -
- -
-
- - ); - }; -} diff --git a/public/app/features/dashboard/dashgrid/VisualizationTab.tsx b/public/app/features/dashboard/dashgrid/VisualizationTab.tsx index cad204ce712..b6287bafdac 100644 --- a/public/app/features/dashboard/dashgrid/VisualizationTab.tsx +++ b/public/app/features/dashboard/dashgrid/VisualizationTab.tsx @@ -8,6 +8,7 @@ import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoa import { EditorTabBody } from './EditorTabBody'; import { VizTypePicker } from './VizTypePicker'; import { FadeIn } from 'app/core/components/Animations/FadeIn'; +import { PanelOptionSection } from './PanelOptionSection'; // Types import { PanelModel } from '../panel_model'; @@ -59,11 +60,15 @@ export class VisualizationTab extends PureComponent { return
(this.element = element)} />; } - if (PanelOptions) { - return ; - } else { - return

Visualization has no options

; - } + return ( + + {PanelOptions ? ( + + ) : ( +

Visualization has no options

+ )} +
+ ); } componentDidMount() { @@ -105,9 +110,9 @@ export class VisualizationTab extends PureComponent { for (let i = 0; i < panelCtrl.editorTabs.length; i++) { template += ` -
` + - (i > -1 ? `
{{ctrl.editorTabs[${i}].title}}
` : '') + - `
+
` + + (i > 0 ? `
{{ctrl.editorTabs[${i}].title}}
` : '') + + `
diff --git a/public/app/features/dashboard/panellinks/module.html b/public/app/features/dashboard/panellinks/module.html index 96d9b785a1b..0dcb0ef3ed6 100644 --- a/public/app/features/dashboard/panellinks/module.html +++ b/public/app/features/dashboard/panellinks/module.html @@ -1,8 +1,4 @@
-
- Drilldown / detail linkThese links appear in the dropdown menu in the panel menu.
- -
diff --git a/public/app/features/datasources/settings/DataSourceSettings.tsx b/public/app/features/datasources/settings/DataSourceSettings.tsx index 977d37e35ec..5786bd1db57 100644 --- a/public/app/features/datasources/settings/DataSourceSettings.tsx +++ b/public/app/features/datasources/settings/DataSourceSettings.tsx @@ -177,6 +177,9 @@ export class DataSourceSettings extends PureComponent {
+ {this.isReadOnly() && this.renderIsReadOnlyMessage()} + {this.shouldRenderInfoBox() &&
{this.getInfoText()}
} + { onNameChange={name => setDataSourceName(name)} /> - {this.shouldRenderInfoBox() &&
{this.getInfoText()}
} - - {this.isReadOnly() && this.renderIsReadOnlyMessage()} {dataSourceMeta.module && ( +
+ This plugin is marked as being in alpha state, which means it is in early development phase and updates will include breaking changes. +
-
- This plugin is marked as being in alpha state, which means it is in early development phase and updates will include breaking changes. -
+
+ This plugin is marked as being in a beta development state. This means it is in currently in active development and could be missing important features. +
-
- This plugin is marked as being in a beta development state. This means it is in currently in active development and could be missing important features. -
+
+ This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource. +
-
- This datasource was added by config and cannot be modified using the UI. Please contact your server admin to update this datasource. -
-
-
Info
-
- Title - -
-
- Description - -
- -
- -
-
Repeat
-
- For each value of - -
-
- Direction - -
-
- Min width - -
-
- - +
+ +
+
+
+ Title + +
+ +
+
+
+ Description + +
+
+
+
+
+
Repeating
+
+
+
+ Repat + +
+
+ Direction + +
+
+ Min width + +
+
+
+
+
+
Drildown Links
+
+ +
+
diff --git a/public/app/plugins/panel/graph/tab_display.html b/public/app/plugins/panel/graph/tab_display.html index 2ed600aac70..976b9bcc940 100644 --- a/public/app/plugins/panel/graph/tab_display.html +++ b/public/app/plugins/panel/graph/tab_display.html @@ -22,10 +22,10 @@
-
+
- +
@@ -66,7 +66,7 @@
-
+
@@ -85,16 +85,16 @@
- +
- +
- +