diff --git a/package.json b/package.json index d2760bbad02..c951e5241c1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.1.0", "@rtsao/plugin-proposal-class-properties": "^7.0.1-patch.1", + "@types/angular": "^1.6.6", "@types/chalk": "^2.2.0", "@types/classnames": "^2.2.6", "@types/commander": "^2.12.2", diff --git a/packages/grafana-ui/src/components/FormField/_FormField.scss b/packages/grafana-ui/src/components/FormField/_FormField.scss index 36955e2fca6..0c69e67f82a 100644 --- a/packages/grafana-ui/src/components/FormField/_FormField.scss +++ b/packages/grafana-ui/src/components/FormField/_FormField.scss @@ -1,5 +1,5 @@ .form-field { - margin-bottom: $gf-form-margin; + margin-bottom: $space-xxs; display: flex; flex-direction: row; align-items: center; diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.tsx index d04daae3dab..aa6d2a40258 100644 --- a/packages/grafana-ui/src/components/Gauge/Gauge.tsx +++ b/packages/grafana-ui/src/components/Gauge/Gauge.tsx @@ -30,7 +30,7 @@ const FONT_SCALE = 1; export class Gauge extends PureComponent { canvasElement: any; - static defaultProps = { + static defaultProps: Partial = { maxValue: 100, valueMappings: [], minValue: 0, @@ -41,7 +41,6 @@ export class Gauge extends PureComponent { thresholds: [], unit: 'none', stat: 'avg', - theme: GrafanaThemeType.Dark, }; componentDidMount() { @@ -134,7 +133,7 @@ export class Gauge extends PureComponent { Math.min(dimension / 5, 100) * (formattedValue !== null ? this.getFontScale(formattedValue.length) : 1); const thresholdLabelFontSize = fontSize / 2.5; - const options = { + const options: any = { series: { gauges: { gauge: { diff --git a/packages/grafana-ui/src/components/Select/_Select.scss b/packages/grafana-ui/src/components/Select/_Select.scss index bc18ed9d369..f0270b1422e 100644 --- a/packages/grafana-ui/src/components/Select/_Select.scss +++ b/packages/grafana-ui/src/components/Select/_Select.scss @@ -3,7 +3,7 @@ $select-input-bg-disabled: $input-bg-disabled; @mixin select-control() { width: 100%; - margin-right: $gf-form-margin; + margin-right: $space-xs; @include border-radius($input-border-radius-sm); background-color: $input-bg; } diff --git a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts index 0ce4fac8182..2a879ef17c8 100644 --- a/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts +++ b/packages/grafana-ui/src/themes/_variables.scss.tmpl.ts @@ -17,7 +17,13 @@ $enable-hover-media-query: false !default; // Control the default styling of most Bootstrap elements by modifying these // variables. Mostly focused on spacing. -$spacer: ${theme.spacing.m} !default; +$space-xxs: ${theme.spacing.xxs} !default; +$space-xs: ${theme.spacing.xs} !default; +$space-sm: ${theme.spacing.sm} !default; +$space-md: ${theme.spacing.md} !default; +$space-lg: ${theme.spacing.lg} !default; +$space-xl: ${theme.spacing.xl} !default; +$spacer: ${theme.spacing.d} !default; $spacer-x: $spacer !default; $spacer-y: $spacer !default; $spacers: ( @@ -46,7 +52,7 @@ $spacers: ( ), ), ) !default; -$border-width: ${theme.border.width.s} !default; +$border-width: ${theme.border.width.sm} !default; // Grid breakpoints // @@ -55,9 +61,9 @@ $border-width: ${theme.border.width.s} !default; $grid-breakpoints: ( xs: ${theme.breakpoints.xs}, - sm: ${theme.breakpoints.s}, - md: ${theme.breakpoints.m}, - lg: ${theme.breakpoints.l}, + sm: ${theme.breakpoints.sm}, + md: ${theme.breakpoints.md}, + lg: ${theme.breakpoints.lg}, xl: ${theme.breakpoints.xl}, ) !default; @@ -91,12 +97,12 @@ $font-family-base: $font-family-sans-serif !default; $font-size-root: ${theme.typography.size.root} !default; $font-size-base: ${theme.typography.size.base} !default; -$font-size-lg: ${theme.typography.size.l} !default; -$font-size-md: ${theme.typography.size.m} !default; -$font-size-sm: ${theme.typography.size.s} !default; +$font-size-lg: ${theme.typography.size.lg} !default; +$font-size-md: ${theme.typography.size.md} !default; +$font-size-sm: ${theme.typography.size.sm} !default; $font-size-xs: ${theme.typography.size.xs} !default; -$line-height-base: ${theme.typography.lineHeight.l} !default; +$line-height-base: ${theme.typography.lineHeight.lg} !default; $font-weight-semi-bold: ${theme.typography.weight.semibold}; $font-size-h1: ${theme.typography.heading.h1} !default; @@ -106,10 +112,9 @@ $font-size-h4: ${theme.typography.heading.h4} !default; $font-size-h5: ${theme.typography.heading.h5} !default; $font-size-h6: ${theme.typography.heading.h6} !default; -$headings-margin-bottom: ($spacer / 2) !default; $headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; $headings-font-weight: ${theme.typography.weight.normal} !default; -$headings-line-height: ${theme.typography.lineHeight.s} !default; +$headings-line-height: ${theme.typography.lineHeight.sm} !default; $hr-border-width: $border-width !default; $dt-font-weight: bold !default; @@ -160,7 +165,6 @@ $input-padding-y-lg: 10px !default; $input-height: 35px !default; -$gf-form-margin: 3px; $gf-form-input-height: 35px; $cursor-disabled: not-allowed !default; @@ -207,8 +211,7 @@ $btn-semi-transparent: rgba(0, 0, 0, 0.2) !default; $side-menu-width: 60px; // dashboard -$panel-margin: 10px; -$dashboard-padding: $panel-margin * 2; +$dashboard-padding: 10px * 2; $panel-horizontal-padding: 10; $panel-vertical-padding: 5; $panel-padding: 0px $panel-horizontal-padding + 0px $panel-vertical-padding + 0px $panel-horizontal-padding + 0px; diff --git a/packages/grafana-ui/src/themes/default.ts b/packages/grafana-ui/src/themes/default.ts index 60ebcfa7aa0..f400889e665 100644 --- a/packages/grafana-ui/src/themes/default.ts +++ b/packages/grafana-ui/src/themes/default.ts @@ -11,9 +11,9 @@ const theme: GrafanaThemeCommons = { root: '14px', base: '13px', xs: '10px', - s: '12px', - m: '14px', - l: '18px', + sm: '12px', + md: '14px', + lg: '18px', }, heading: { h1: '28px', @@ -30,33 +30,36 @@ const theme: GrafanaThemeCommons = { }, lineHeight: { xs: 1, - s: 1.1, - m: 4 / 3, - l: 1.5, + sm: 1.1, + md: 4 / 3, + lg: 1.5, }, }, breakpoints: { xs: '0', - s: '544px', - m: '768px', - l: '992px', + sm: '544px', + md: '768px', + lg: '992px', xl: '1200px', }, spacing: { - xs: '0', - s: '3px', - m: '14px', - l: '21px', + d: '14px', + xxs: '2px', + xs: '4px', + sm: '8px', + md: '16px', + lg: '24px', + xl: '32px', gutter: '30px', }, border: { radius: { xs: '2px', - s: '3px', - m: '5px', + sm: '3px', + md: '5px', }, width: { - s: '1px', + sm: '1px', }, }, }; diff --git a/packages/grafana-ui/src/types/theme.ts b/packages/grafana-ui/src/types/theme.ts index 1226b841836..cd90a40e780 100644 --- a/packages/grafana-ui/src/types/theme.ts +++ b/packages/grafana-ui/src/types/theme.ts @@ -8,9 +8,9 @@ export interface GrafanaThemeCommons { // TODO: not sure if should be a part of theme breakpoints: { xs: string; - s: string; - m: string; - l: string; + sm: string; + md: string; + lg: string; xl: string; }; typography: { @@ -22,9 +22,9 @@ export interface GrafanaThemeCommons { root: string; base: string; xs: string; - s: string; - m: string; - l: string; + sm: string; + md: string; + lg: string; }; weight: { light: number; @@ -33,9 +33,9 @@ export interface GrafanaThemeCommons { }; lineHeight: { xs: number; //1 - s: number; //1.1 - m: number; // 4/3 - l: number; // 1.5 + sm: number; //1.1 + md: number; // 4/3 + lg: number; // 1.5 }; // TODO: Refactor to use size instead of custom defs heading: { @@ -48,20 +48,23 @@ export interface GrafanaThemeCommons { }; }; spacing: { + d: string; + xxs: string; xs: string; - s: string; - m: string; - l: string; + sm: string; + md: string; + lg: string; + xl: string; gutter: string; }; border: { radius: { xs: string; - s: string; - m: string; + sm: string; + md: string; }; width: { - s: string; + sm: string; }; }; } diff --git a/public/app/core/components/jsontree/jsontree.ts b/public/app/core/components/jsontree/jsontree.ts index 4bcb2f632c2..a101007f129 100644 --- a/public/app/core/components/jsontree/jsontree.ts +++ b/public/app/core/components/jsontree/jsontree.ts @@ -10,13 +10,13 @@ coreModule.directive('jsonTree', [ startExpanded: '@', rootName: '@', }, - link: (scope, elem) => { + link: (scope: any, elem) => { const jsonExp = new JsonExplorer(scope.object, 3, { animateOpen: true, }); const html = jsonExp.render(true); - elem.html(html); + elem.replaceAll(html); }, }; }, diff --git a/public/app/core/directives/give_focus.ts b/public/app/core/directives/give_focus.ts index 4ef574ec68e..37549ad7229 100644 --- a/public/app/core/directives/give_focus.ts +++ b/public/app/core/directives/give_focus.ts @@ -14,7 +14,7 @@ coreModule.directive('giveFocus', () => { } setTimeout(() => { element.focus(); - const domEl = element[0]; + const domEl: any = element[0]; if (domEl.setSelectionRange) { const pos = element.val().length * 2; domEl.setSelectionRange(pos, pos); diff --git a/public/app/core/specs/kbn.test.ts b/public/app/core/specs/kbn.test.ts deleted file mode 100644 index c97e2e1101a..00000000000 --- a/public/app/core/specs/kbn.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import kbn from '../utils/kbn'; - -describe('stringToJsRegex', () => { - it('should parse the valid regex value', () => { - const output = kbn.stringToJsRegex('/validRegexp/'); - expect(output).toBeInstanceOf(RegExp); - }); - - it('should throw error on invalid regex value', () => { - const input = '/etc/hostname'; - expect(() => { - kbn.stringToJsRegex(input); - }).toThrow(); - }); -}); diff --git a/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss b/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss index 8daf935d918..941e36c5e33 100644 --- a/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss +++ b/public/app/features/dashboard/components/AddPanelWidget/_AddPanelWidget.scss @@ -20,7 +20,7 @@ .gicon { font-size: 30px; - margin-right: $spacer; + margin-right: $space-md; } &:hover { @@ -32,16 +32,16 @@ .add-panel-widget__title { font-size: $font-size-md; font-weight: $font-weight-semi-bold; - margin-right: $spacer * 2; + margin-right: $space-xl; } .add-panel-widget__link { - margin: 0 8px; + margin: 0 $space-sm; width: 154px; } .add-panel-widget__icon { - margin-bottom: 8px; + margin-bottom: $space-sm; .gicon { color: white; @@ -62,7 +62,7 @@ .add-panel-widget__create { display: inherit; - margin-bottom: 24px; + margin-bottom: $space-lg; // this is to have the big button appear centered margin-top: 55px; } @@ -72,7 +72,7 @@ } .add-panel-widget__action { - margin: 0 4px; + margin: 0 $space-xs; } .add-panel-widget__btn-container { diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index 09864d85960..82d94669cd6 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -116,7 +116,7 @@ export class DataPanel extends Component { this.setState({ loading: LoadingState.Loading }); try { - const ds = await this.dataSourceSrv.get(datasource); + const ds = await this.dataSourceSrv.get(datasource, scopedVars); // TODO interpolate variables const minInterval = this.props.minInterval || ds.interval; diff --git a/public/app/features/datasources/settings/HttpSettingsCtrl.ts b/public/app/features/datasources/settings/HttpSettingsCtrl.ts index 47022c283f8..5cdebe7b9ab 100644 --- a/public/app/features/datasources/settings/HttpSettingsCtrl.ts +++ b/public/app/features/datasources/settings/HttpSettingsCtrl.ts @@ -9,7 +9,7 @@ coreModule.directive('datasourceHttpSettings', () => { }, templateUrl: 'public/app/features/datasources/partials/http_settings.html', link: { - pre: ($scope, elem, attrs) => { + pre: ($scope: any, elem, attrs) => { // do not show access option if direct access is disabled $scope.showAccessOption = $scope.noDirectAccess !== 'true'; $scope.showAccessHelp = false; diff --git a/public/app/features/panel/metrics_panel_ctrl.ts b/public/app/features/panel/metrics_panel_ctrl.ts index 028585ae21e..3e217369b15 100644 --- a/public/app/features/panel/metrics_panel_ctrl.ts +++ b/public/app/features/panel/metrics_panel_ctrl.ts @@ -81,7 +81,7 @@ class MetricsPanelCtrl extends PanelCtrl { // load datasource service this.datasourceSrv - .get(this.panel.datasource) + .get(this.panel.datasource, this.panel.scopedVars) .then(this.updateTimeRange.bind(this)) .then(this.issueQueries.bind(this)) .then(this.handleQueryResult.bind(this)) diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 31da05a2d4f..8dff4de5872 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -33,7 +33,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => { template: panelTemplate, transclude: true, scope: { ctrl: '=' }, - link: (scope, elem) => { + link: (scope: any, elem) => { const panelContainer = elem.find('.panel-container'); const panelContent = elem.find('.panel-content'); const cornerInfoElem = elem.find('.panel-info-corner'); @@ -67,7 +67,7 @@ module.directive('grafanaPanel', ($rootScope, $document, $timeout) => { // set initial transparency if (ctrl.panel.transparent) { transparentLastState = true; - panelContainer.addClass('panel-transparent', true); + panelContainer.addClass('panel-transparent'); } // update scrollbar after mounting diff --git a/public/app/features/plugins/datasource_srv.ts b/public/app/features/plugins/datasource_srv.ts index f7dc0da32c4..fde17ba8f48 100644 --- a/public/app/features/plugins/datasource_srv.ts +++ b/public/app/features/plugins/datasource_srv.ts @@ -7,7 +7,7 @@ import config from 'app/core/config'; import { importPluginModule } from './plugin_loader'; // Types -import { DataSourceApi, DataSourceSelectItem } from '@grafana/ui/src/types'; +import { DataSourceApi, DataSourceSelectItem, ScopedVars } from '@grafana/ui/src/types'; export class DatasourceSrv { datasources: { [name: string]: DataSourceApi }; @@ -21,12 +21,18 @@ export class DatasourceSrv { this.datasources = {}; } - get(name?: string): Promise { + get(name?: string, scopedVars?: ScopedVars): Promise { if (!name) { return this.get(config.defaultDatasource); } - name = this.templateSrv.replace(name); + // Interpolation here is to support template variable in data source selection + name = this.templateSrv.replace(name, scopedVars, (value, variable) => { + if (Array.isArray(value)) { + return value[0]; + } + return value; + }); if (name === 'default') { return this.get(config.defaultDatasource); diff --git a/public/app/features/templating/datasource_variable.ts b/public/app/features/templating/datasource_variable.ts index 2b326cb1c5c..30eb0e89589 100644 --- a/public/app/features/templating/datasource_variable.ts +++ b/public/app/features/templating/datasource_variable.ts @@ -6,6 +6,8 @@ export class DatasourceVariable implements Variable { query: string; options: any; current: any; + multi: boolean; + includeAll: boolean; refresh: any; skipUrlSync: boolean; @@ -18,6 +20,8 @@ export class DatasourceVariable implements Variable { regex: '', options: [], query: '', + multi: false, + includeAll: false, refresh: 1, skipUrlSync: false, }; @@ -69,9 +73,16 @@ export class DatasourceVariable implements Variable { } this.options = options; + if (this.includeAll) { + this.addAllOption(); + } return this.variableSrv.validateVariableSelectionState(this); } + addAllOption() { + this.options.unshift({ text: 'All', value: '$__all' }); + } + dependsOn(variable) { if (this.regex) { return containsVariable(this.regex, variable.name); @@ -84,6 +95,9 @@ export class DatasourceVariable implements Variable { } getValueForUrl() { + if (this.current.text === 'All') { + return 'All'; + } return this.current.value; } } @@ -91,5 +105,6 @@ export class DatasourceVariable implements Variable { variableTypes['datasource'] = { name: 'Datasource', ctor: DatasourceVariable, + supportsMulti: true, description: 'Enabled you to dynamically switch the datasource for multiple panels', }; diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index c3fbd7ee1d7..b0fab2564eb 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -1,5 +1,6 @@ import _ from 'lodash'; import TableModel from 'app/core/table_model'; +import { TimeSeries } from '@grafana/ui'; export class ResultTransformer { constructor(private templateSrv) {} @@ -18,10 +19,10 @@ export class ResultTransformer { ]; } else if (prometheusResult && options.format === 'heatmap') { let seriesList = []; - prometheusResult.sort(sortSeriesByLabel); for (const metricData of prometheusResult) { seriesList.push(this.transformMetricData(metricData, options, options.start, options.end)); } + seriesList.sort(sortSeriesByLabel); seriesList = this.transformToHistogramOverTime(seriesList); return seriesList; } else if (prometheusResult) { @@ -197,13 +198,13 @@ export class ResultTransformer { } } -function sortSeriesByLabel(s1, s2): number { +function sortSeriesByLabel(s1: TimeSeries, s2: TimeSeries): number { let le1, le2; try { // fail if not integer. might happen with bad queries - le1 = parseHistogramLabel(s1.metric.le); - le2 = parseHistogramLabel(s2.metric.le); + le1 = parseHistogramLabel(s1.target); + le2 = parseHistogramLabel(s2.target); } catch (err) { console.log(err); return 0; diff --git a/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts b/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts index 889720ad286..0cbd1bac564 100644 --- a/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts +++ b/public/app/plugins/datasource/stackdriver/query_filter_ctrl.ts @@ -2,28 +2,6 @@ import coreModule from 'app/core/core_module'; import _ from 'lodash'; import { FilterSegments, DefaultFilterValue } from './filter_segments'; -export class StackdriverFilter { - /** @ngInject */ - constructor() { - return { - templateUrl: 'public/app/plugins/datasource/stackdriver/partials/query.filter.html', - controller: 'StackdriverFilterCtrl', - controllerAs: 'ctrl', - bindToController: true, - restrict: 'E', - scope: { - labelData: '<', - loading: '<', - groupBys: '<', - filters: '<', - filtersChanged: '&', - groupBysChanged: '&', - hideGroupBys: '<', - }, - }; - } -} - export class StackdriverFilterCtrl { defaultRemoveGroupByValue = '-- remove group by --'; resourceTypeValue = 'resource.type'; @@ -193,5 +171,24 @@ export class StackdriverFilterCtrl { } } -coreModule.directive('stackdriverFilter', StackdriverFilter); -coreModule.controller('StackdriverFilterCtrl', StackdriverFilterCtrl); +/** @ngInject */ +function stackdriverFilter() { + return { + templateUrl: 'public/app/plugins/datasource/stackdriver/partials/query.filter.html', + controller: StackdriverFilterCtrl, + controllerAs: 'ctrl', + bindToController: true, + restrict: 'E', + scope: { + labelData: '<', + loading: '<', + groupBys: '<', + filters: '<', + filtersChanged: '&', + groupBysChanged: '&', + hideGroupBys: '<', + }, + }; +} + +coreModule.directive('stackdriverFilter', stackdriverFilter); diff --git a/public/app/plugins/panel/heatmap/color_legend.ts b/public/app/plugins/panel/heatmap/color_legend.ts index c36fad45cba..c90b394fb02 100644 --- a/public/app/plugins/panel/heatmap/color_legend.ts +++ b/public/app/plugins/panel/heatmap/color_legend.ts @@ -19,7 +19,7 @@ coreModule.directive('colorLegend', () => { return { restrict: 'E', template: '
', - link: (scope, elem, attrs) => { + link: (scope: any, elem, attrs) => { const ctrl = scope.ctrl; const panel = scope.ctrl.panel; @@ -55,7 +55,7 @@ coreModule.directive('heatmapLegend', () => { return { restrict: 'E', template: `
`, - link: (scope, elem, attrs) => { + link: (scope: any, elem, attrs) => { const ctrl = scope.ctrl; const panel = scope.ctrl.panel; diff --git a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts index 71e059a5750..809c6718a9c 100644 --- a/public/app/plugins/panel/heatmap/heatmap_ctrl.ts +++ b/public/app/plugins/panel/heatmap/heatmap_ctrl.ts @@ -55,6 +55,7 @@ const panelDefaults = { showHistogram: false, }, highlightCards: true, + hideZeroBuckets: false, }; const colorModes = ['opacity', 'spectrum']; @@ -97,7 +98,7 @@ const colorSchemes = [ { name: 'YlOrRd', value: 'interpolateYlOrRd', invert: 'dark' }, ]; -const dsSupportHistogramSort = ['prometheus', 'elasticsearch']; +const dsSupportHistogramSort = ['elasticsearch']; export class HeatmapCtrl extends MetricsPanelCtrl { static templateUrl = 'module.html'; @@ -204,7 +205,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl { yBucketSize = 1; } - const { cards, cardStats } = convertToCards(bucketsData); + const { cards, cardStats } = convertToCards(bucketsData, this.panel.hideZeroBuckets); this.data = { buckets: bucketsData, @@ -246,7 +247,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl { // Always let yBucketSize=1 in 'tsbuckets' mode yBucketSize = 1; - const { cards, cardStats } = convertToCards(bucketsData); + const { cards, cardStats } = convertToCards(bucketsData, this.panel.hideZeroBuckets); this.data = { buckets: bucketsData, diff --git a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts index 99b61be40dc..07960f68ae3 100644 --- a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts +++ b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts @@ -93,25 +93,43 @@ function parseHistogramLabel(label: string): number { return value; } +interface HeatmapCard { + x: number; + y: number; + yBounds: { + top: number | null; + bottom: number | null; + }; + values: number[]; + count: number; +} + +interface HeatmapCardStats { + min: number; + max: number; +} + /** * Convert buckets into linear array of "cards" - objects, represented heatmap elements. * @param {Object} buckets - * @return {Array} Array of "card" objects + * @return {Object} Array of "card" objects and stats */ -function convertToCards(buckets) { +function convertToCards(buckets: any, hideZero = false): { cards: HeatmapCard[]; cardStats: HeatmapCardStats } { let min = 0, max = 0; - const cards = []; + const cards: HeatmapCard[] = []; _.forEach(buckets, xBucket => { _.forEach(xBucket.buckets, yBucket => { - const card = { + const card: HeatmapCard = { x: xBucket.x, y: yBucket.y, yBounds: yBucket.bounds, values: yBucket.values, count: yBucket.count, }; - cards.push(card); + if (!hideZero || card.count !== 0) { + cards.push(card); + } if (cards.length === 1) { min = yBucket.count; diff --git a/public/app/plugins/panel/heatmap/partials/display_editor.html b/public/app/plugins/panel/heatmap/partials/display_editor.html index 929cf1fe7d4..7b38061e2ff 100644 --- a/public/app/plugins/panel/heatmap/partials/display_editor.html +++ b/public/app/plugins/panel/heatmap/partials/display_editor.html @@ -63,6 +63,10 @@
Buckets
+ +
diff --git a/public/sass/_variables.generated.scss b/public/sass/_variables.generated.scss index 9a29f9beba9..75d033fcf87 100644 --- a/public/sass/_variables.generated.scss +++ b/public/sass/_variables.generated.scss @@ -20,6 +20,12 @@ $enable-hover-media-query: false !default; // Control the default styling of most Bootstrap elements by modifying these // variables. Mostly focused on spacing. +$space-xxs: 2px !default; +$space-xs: 4px !default; +$space-sm: 8px !default; +$space-md: 16px !default; +$space-lg: 24px !default; +$space-xl: 32px !default; $spacer: 14px !default; $spacer-x: $spacer !default; $spacer-y: $spacer !default; @@ -109,7 +115,6 @@ $font-size-h4: 18px !default; $font-size-h5: 16px !default; $font-size-h6: 14px !default; -$headings-margin-bottom: ($spacer / 2) !default; $headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif; $headings-font-weight: 400 !default; $headings-line-height: 1.1 !default; @@ -163,7 +168,6 @@ $input-padding-y-lg: 10px !default; $input-height: 35px !default; -$gf-form-margin: 3px; $gf-form-input-height: 35px; $cursor-disabled: not-allowed !default; @@ -210,8 +214,7 @@ $btn-semi-transparent: rgba(0, 0, 0, 0.2) !default; $side-menu-width: 60px; // dashboard -$panel-margin: 10px; -$dashboard-padding: $panel-margin * 2; +$dashboard-padding: 10px * 2; $panel-horizontal-padding: 10; $panel-vertical-padding: 5; $panel-padding: 0px $panel-horizontal-padding + 0px $panel-vertical-padding + 0px $panel-horizontal-padding + 0px; diff --git a/public/sass/base/_type.scss b/public/sass/base/_type.scss index ab4fbc33a55..6cf32687188 100644 --- a/public/sass/base/_type.scss +++ b/public/sass/base/_type.scss @@ -109,7 +109,7 @@ h6, .h4, .h5, .h6 { - margin-bottom: $headings-margin-bottom; + margin-bottom: $space-sm; font-family: $headings-font-family; font-weight: $headings-font-weight; line-height: $headings-line-height; diff --git a/public/sass/components/_add_data_source.scss b/public/sass/components/_add_data_source.scss index 508f7f80d8e..4046be2a723 100644 --- a/public/sass/components/_add_data_source.scss +++ b/public/sass/components/_add_data_source.scss @@ -1,5 +1,5 @@ .add-data-source-header { - margin-bottom: $spacer * 2; + margin-bottom: $space-xl; padding-top: $spacer; text-align: center; } @@ -7,7 +7,7 @@ .add-data-source-search { display: flex; justify-content: center; - margin-bottom: $panel-margin * 2; + margin-bottom: $space-lg; } .add-data-source-grid { @@ -41,6 +41,6 @@ } .add-data-source-grid-item-logo { - margin: 0 15px; + margin: 0 $space-md; width: 55px; } diff --git a/public/sass/components/_alerts.scss b/public/sass/components/_alerts.scss index 1c4f1b7fcb7..da3ebf7fa7b 100644 --- a/public/sass/components/_alerts.scss +++ b/public/sass/components/_alerts.scss @@ -7,7 +7,7 @@ .alert { padding: 15px 20px; - margin-bottom: $panel-margin / 2; + margin-bottom: $space-xs; text-shadow: 0 2px 0 rgba(255, 255, 255, 0.5); background: $alert-error-bg; position: relative; diff --git a/public/sass/components/_cards.scss b/public/sass/components/_cards.scss index 80a4cd7c32a..58d4b1ab5d2 100644 --- a/public/sass/components/_cards.scss +++ b/public/sass/components/_cards.scss @@ -1,7 +1,7 @@ .layout-selector { @include clearfix(); - margin-left: $spacer; + margin-left: $space-md; text-align: right; button { @@ -9,7 +9,7 @@ color: $text-color-weak; box-shadow: $card-shadow; border: none; - padding: 0.5rem; + padding: $space-sm; line-height: 1; font-size: 130%; float: right; @@ -35,7 +35,7 @@ } .card-section { - margin-bottom: $spacer * 2; + margin-bottom: $space-xl; } .card-list { @@ -50,7 +50,7 @@ height: 100%; background: $card-background; box-shadow: $card-shadow; - padding: 1rem; + padding: $space-md; border-radius: 4px; &:hover { @@ -58,7 +58,7 @@ } .label-tag { - margin-left: 6px; + margin-left: $space-sm; font-size: 11px; padding: 2px 6px; } @@ -80,15 +80,8 @@ overflow: hidden; } -.card-item-cog { - font-size: 130%; - position: relative; - top: 1rem; - color: $text-muted; -} - .card-item-header { - margin-bottom: $spacer; + margin-bottom: $space-md; } .card-item-type { @@ -110,7 +103,7 @@ } .card-item-label { - margin-left: 8px; + margin-left: $space-sm; } .card-item-sub-name { @@ -123,7 +116,7 @@ .card-item-sub-name--header { color: $text-color-weak; text-transform: uppercase; - margin-bottom: $spacer; + margin-bottom: $space-md; font-size: $font-size-sm; font-weight: bold; } @@ -136,7 +129,7 @@ .card-item-notice { font-size: $font-size-sm; display: inline-block; - margin-left: $spacer; + margin-left: $space-md; } .card-item-header-action { @@ -145,7 +138,7 @@ .card-item-wrapper { width: 100%; - padding: 0 1rem 1rem 0rem; + padding: 0 $space-md $space-md 0; } .card-item-wrapper--clickable { @@ -153,7 +146,7 @@ } .card-item-figure { - margin: 0 $spacer $spacer 0; + margin: 0 $space-md $space-md 0; height: 6rem; img { @@ -195,7 +188,7 @@ .card-item-wrapper { padding: 0; width: 100%; - margin-bottom: 3px; + margin-bottom: $space-xs; } .card-item-wrapper--clickable { @@ -212,9 +205,9 @@ } .card-item-figure { - margin: 0 $spacer 0 0; + margin: 0 $space-md 0 0; img { - width: 3.5rem; + width: 48px; } } diff --git a/public/sass/components/_dashboard_settings.scss b/public/sass/components/_dashboard_settings.scss index de16f0c60b5..173ab1a3935 100644 --- a/public/sass/components/_dashboard_settings.scss +++ b/public/sass/components/_dashboard_settings.scss @@ -41,7 +41,7 @@ font-size: $font-size-h3; padding-right: 60px; white-space: nowrap; - margin-bottom: $spacer; + margin-bottom: $space-md; i { font-size: 25px; @@ -53,7 +53,7 @@ .dashboard-settings__header { font-size: $font-size-h3; - margin-bottom: $spacer * 2; + margin-bottom: $space-xl; } .dashboard-settings__subheader { @@ -89,13 +89,13 @@ flex-direction: column; height: 100%; flex-grow: 1; - margin: $spacer * 3 $spacer * 2 0 0; + margin: 40px $space-xl 0 0; button { - margin-bottom: 10px; + margin-bottom: $space-sm; } } .dashboard-settings__json-save-button { - margin-top: $spacer; + margin-top: $space-md; } diff --git a/public/sass/components/_gf-form.scss b/public/sass/components/_gf-form.scss index c341c686143..2eccdd52e8b 100644 --- a/public/sass/components/_gf-form.scss +++ b/public/sass/components/_gf-form.scss @@ -1,8 +1,7 @@ -$gf-form-margin: 3px; $input-border: 1px solid $input-border-color; .gf-form { - margin-bottom: $gf-form-margin; + margin-bottom: $space-xxs; display: flex; flex-direction: row; align-items: flex-start; @@ -33,7 +32,7 @@ $input-border: 1px solid $input-border-color; .gf-form--has-input-icon { position: relative; - margin-right: $gf-form-margin; + margin-right: $space-xs; .gf-form-input-icon { position: absolute; @@ -82,7 +81,7 @@ $input-border: 1px solid $input-border-color; align-content: flex-start; .gf-form + .gf-form { - margin-left: $gf-form-margin; + margin-left: $space-xs; } &--nowrap { @@ -147,14 +146,14 @@ $input-border: 1px solid $input-border-color; } .gf-form-label + .gf-form-label { - margin-right: $gf-form-margin; + margin-right: $space-xs; } .gf-form-pre { display: block; flex-grow: 1; margin: 0; - margin-right: $gf-form-margin; + margin-right: $space-xs; border: $input-btn-border-width solid transparent; border-left: none; @include border-radius($label-border-radius-sm); @@ -336,7 +335,7 @@ $input-border: 1px solid $input-border-color; .gf-form-btn { padding: $input-padding-y $input-padding-x; - margin-right: $gf-form-margin; + margin-right: $space-xs; line-height: $input-line-height; font-size: $font-size-sm; @@ -354,7 +353,7 @@ $input-border: 1px solid $input-border-color; } .gf-form-dropdown-typeahead { - margin-right: $gf-form-margin; + //margin-right: $space-xs; ? position: relative; &::after { @@ -391,7 +390,7 @@ $input-border: 1px solid $input-border-color; } &--header { - margin-bottom: $gf-form-margin; + margin-bottom: $space-xxs; } &--no-padding { diff --git a/public/sass/components/_infobox.scss b/public/sass/components/_infobox.scss index 6f7a7bf86dc..16e07c68b20 100644 --- a/public/sass/components/_infobox.scss +++ b/public/sass/components/_infobox.scss @@ -5,7 +5,7 @@ margin-bottom: 2rem; border-top: 3px solid $info-box-border-color; margin-bottom: $spacer; - margin-right: $gf-form-margin; + margin-right: $space-xs; box-shadow: $card-shadow; flex-grow: 1; diff --git a/public/sass/components/_page_loader.scss b/public/sass/components/_page_loader.scss index 053a061600f..0a3eac40a0c 100644 --- a/public/sass/components/_page_loader.scss +++ b/public/sass/components/_page_loader.scss @@ -7,7 +7,7 @@ &__spinner { font-size: 32px; - margin-bottom: $panel-margin; + margin-bottom: $space-sm; } &__text { diff --git a/public/sass/components/_panel_editor.scss b/public/sass/components/_panel_editor.scss index 9bd5672e4a8..8acf98be1b2 100644 --- a/public/sass/components/_panel_editor.scss +++ b/public/sass/components/_panel_editor.scss @@ -21,7 +21,7 @@ } .panel-editor-container__editor { - margin-top: $panel-margin * 2; + margin-top: $space-lg; display: flex; flex-direction: row; flex: 1 1 0; @@ -80,7 +80,7 @@ } .submenu-controls { - padding: 0 $dashboard-padding $panel-margin $dashboard-padding; + padding: 0 $dashboard-padding $space-sm $dashboard-padding; } .panel-editor-container__panel { diff --git a/public/sass/components/_panel_logs.scss b/public/sass/components/_panel_logs.scss index 5d35f8fddc0..160a9f78e66 100644 --- a/public/sass/components/_panel_logs.scss +++ b/public/sass/components/_panel_logs.scss @@ -6,7 +6,7 @@ $column-horizontal-spacing: 10px; padding: $panel-padding; padding-top: 10px; border-radius: $border-radius; - margin: 2 * $panel-margin 0 $panel-margin; + margin: $space-md 0 $space-sm; border: $panel-border; flex-direction: column; } diff --git a/public/sass/components/_sidemenu.scss b/public/sass/components/_sidemenu.scss index c16e037c2ad..8ecc7f95205 100644 --- a/public/sass/components/_sidemenu.scss +++ b/public/sass/components/_sidemenu.scss @@ -165,7 +165,7 @@ font-size: $font-size-sm; color: $text-color-weak; border-bottom: 1px solid $dropdownDividerBottom; - margin-bottom: 0.25rem; + margin-bottom: $space-xs; white-space: nowrap; } @@ -190,7 +190,7 @@ li.sidemenu-org-switcher { display: flex; align-items: center; > i.fa.fa-random { - margin-right: 4px; + margin-right: $space-xs; top: 1px; } } @@ -283,8 +283,8 @@ li.sidemenu-org-switcher { position: unset; width: 100%; float: none; - margin-top: 0.5rem; - margin-bottom: 0.5rem; + margin-top: $space-sm; + margin-bottom: $space-sm; > li > a { padding-left: 15px; diff --git a/public/sass/components/_submenu.scss b/public/sass/components/_submenu.scss index 6c450f7e6dd..514aa44525e 100644 --- a/public/sass/components/_submenu.scss +++ b/public/sass/components/_submenu.scss @@ -4,7 +4,7 @@ flex-wrap: wrap; align-content: flex-start; align-items: flex-start; - padding: 0 0 $panel-margin 0; + padding: 0 0 $space-sm 0; } .annotation-disabled, diff --git a/public/sass/pages/_explore.scss b/public/sass/pages/_explore.scss index 0358adb9787..60c1a600014 100644 --- a/public/sass/pages/_explore.scss +++ b/public/sass/pages/_explore.scss @@ -65,6 +65,11 @@ font-size: 18px; min-height: 55px; line-height: 55px; + justify-content: space-between; + margin-left: $space-xl; +} + +.explore-toolbar-header { justify-content: space-between; align-items: center; } @@ -163,7 +168,7 @@ } .explore-panel { - margin-top: $panel-margin; + margin-top: $space-sm; } .explore-panel__body { @@ -182,24 +187,20 @@ .explore-panel__header-label { font-weight: 500; - margin-right: $panel-margin; + margin-right: $space-sm; font-size: $font-size-h6; box-shadow: $text-shadow-faint; } .explore-panel__header-buttons { - margin-right: $panel-margin; + margin-right: $space-sm; 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; + margin: $space-sm auto; padding: 10px 0; border-radius: $border-radius; text-align: center; @@ -207,7 +208,7 @@ .disclaimer-icon { color: $yellow; - margin-right: $panel-margin/2; + margin-right: $space-xs; } .show-all-time-series { @@ -234,7 +235,7 @@ position: relative; overflow: hidden; background: none; - margin: $panel-margin / 2; + margin: $space-xs; } .explore-panel__loader--active:after { @@ -377,7 +378,7 @@ .ReactTable .-pagination { border-top: none; box-shadow: none; - margin-top: $panel-margin; + margin-top: $space-sm; } .ReactTable .-pagination .-btn { color: $blue; @@ -418,7 +419,7 @@ // TODO Experimental .cheat-sheet-item { - margin: 2 * $panel-margin 0; + margin: $space-lg 0; width: 50%; } @@ -427,6 +428,6 @@ } .cheat-sheet-item__expression { - margin: $panel-margin/2 0; + margin: $space-xs 0; cursor: pointer; } diff --git a/public/sass/utils/_widths.scss b/public/sass/utils/_widths.scss index b1213e6ea60..0770ba19fc3 100644 --- a/public/sass/utils/_widths.scss +++ b/public/sass/utils/_widths.scss @@ -8,20 +8,20 @@ // widths @for $i from 1 through 30 { .width-#{$i} { - width: ($spacer * $i) - $gf-form-margin !important; + width: ($spacer * $i) - $space-xs !important; } } @for $i from 1 through 30 { .max-width-#{$i} { - max-width: ($spacer * $i) - $gf-form-margin !important; + max-width: ($spacer * $i) - $space-xs !important; flex-grow: 1; } } @for $i from 1 through 30 { .min-width-#{$i} { - min-width: ($spacer * $i) - $gf-form-margin !important; + min-width: ($spacer * $i) - $space-xs !important; } } diff --git a/scripts/circle-metrics.sh b/scripts/circle-metrics.sh new file mode 100755 index 00000000000..849fc0e1339 --- /dev/null +++ b/scripts/circle-metrics.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "Collecting code stats (typescript errors & more)" + +ERROR_COUNT="$(./node_modules/.bin/tsc --project tsconfig.json --noEmit --noImplicitAny true | grep -oP 'Found \K(\d+)')" +DIRECTIVES="$(grep -r -o directive public/app/**/* | wc -l)" +CONTROLLERS="$(grep -r -oP 'class .*Ctrl' public/app/**/* | wc -l)" + +echo "Typescript errors: $ERROR_COUNT" +echo "Directives: $DIRECTIVES" +echo "Controllers: $CONTROLLERS" + +curl \ + -d "{\"metrics\": { + \"ci.code.noImplicitAny\": $ERROR_COUNT, + \"ci.code.directives\": $DIRECTIVES, + \"ci.code.controllers\": $CONTROLLERS + } + }" \ + -H "Content-Type: application/json" \ + -u ci:$CIRCLE_STATS_PWD \ + -X POST https://stats.grafana.org/metric-receiver + diff --git a/scripts/circle-test-frontend.sh b/scripts/circle-test-frontend.sh index cd42dd0b7e9..3366bf3d4fb 100755 --- a/scripts/circle-test-frontend.sh +++ b/scripts/circle-test-frontend.sh @@ -12,3 +12,9 @@ function exit_if_fail { exit_if_fail npm run prettier:check exit_if_fail npm run test + +# On master also collect some and send some metrics +branch="$(git rev-parse --abbrev-ref HEAD)" +if [ "${branch}" == "master" ]; then + exit_if_fail ./scripts/circle-metrics.sh +fi diff --git a/yarn.lock b/yarn.lock index 0a3513595a8..c75b8e5a57b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1514,6 +1514,11 @@ react-input-autosize "^2.2.1" react-transition-group "^2.2.1" +"@types/angular@^1.6.6": + version "1.6.54" + resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.54.tgz#f9d5a03e4da7b021a6dabe5d63e899ed4567a5bd" + integrity sha512-xA1FuozWXeRQ7FClUbvk8ePL+dydBeDoCWRPFTHU5+8uvVtIIfLGiHA8CMkwsbddFCYnTDVbLxG85a/HBx7LtA== + "@types/chalk@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba"