From a8814979081a3a7fa94d349116f96e0d4ffe59c0 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 20 Aug 2018 15:33:49 +0200 Subject: [PATCH 01/17] Max number of repeated panels per row Instead of min width --- docs/sources/reference/dashboard.md | 2 +- docs/sources/reference/templating.md | 6 ++++-- pkg/models/dashboards.go | 2 +- .../features/dashboard/dashboard_migration.ts | 11 +++++++++- .../app/features/dashboard/dashboard_model.ts | 4 ++-- public/app/features/dashboard/panel_model.ts | 2 +- .../specs/dashboard_migration.test.ts | 20 ++++++++++--------- .../features/panel/partials/general_tab.html | 4 ++-- public/dashboards/home.json | 2 +- 9 files changed, 33 insertions(+), 20 deletions(-) diff --git a/docs/sources/reference/dashboard.md b/docs/sources/reference/dashboard.md index 6be12600da5..3d96923bc72 100644 --- a/docs/sources/reference/dashboard.md +++ b/docs/sources/reference/dashboard.md @@ -51,7 +51,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized "list": [] }, "refresh": "5s", - "schemaVersion": 16, + "schemaVersion": 17, "version": 0, "links": [] } diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index f20cc0ccfc9..71ce6bdd2ae 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -292,9 +292,11 @@ The `direction` controls how the panels will be arranged. By choosing `horizontal` the panels will be arranged side-by-side. Grafana will automatically adjust the width of each repeated panel so that the whole row is filled. Currently, you cannot mix other panels on a row with a repeated -panel. Each panel will never be smaller that the provided `Min width` if you have many selected values. +panel. -By choosing `vertical` the panels will be arranged from top to bottom in a column. The `Min width` doesn't have any effect in this case. The width of the repeated panels will be the same as of the first panel (the original template) being repeated. +Set `Max per row` to tell grafana how many panels per row you want at most. It defaults to *4* if you don't set anything. + +By choosing `vertical` the panels will be arranged from top to bottom in a column. The width of the repeated panels will be the same as of the first panel (the original template) being repeated. Only make changes to the first panel (the original template). To have the changes take effect on all panels you need to trigger a dynamic dashboard re-build. You can do this by either changing the variable value (that is the basis for the repeat) or reload the dashboard. diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index 3a8010e797b..0f3f56175fe 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -112,7 +112,7 @@ func NewDashboard(title string) *Dashboard { func NewDashboardFolder(title string) *Dashboard { folder := NewDashboard(title) folder.IsFolder = true - folder.Data.Set("schemaVersion", 16) + folder.Data.Set("schemaVersion", 17) folder.Data.Set("version", 0) folder.IsFolder = true return folder diff --git a/public/app/features/dashboard/dashboard_migration.ts b/public/app/features/dashboard/dashboard_migration.ts index abd12ab4b13..4196456907f 100644 --- a/public/app/features/dashboard/dashboard_migration.ts +++ b/public/app/features/dashboard/dashboard_migration.ts @@ -21,7 +21,7 @@ export class DashboardMigrator { let i, j, k, n; const oldVersion = this.dashboard.schemaVersion; const panelUpgrades = []; - this.dashboard.schemaVersion = 16; + this.dashboard.schemaVersion = 17; if (oldVersion === this.dashboard.schemaVersion) { return; @@ -368,6 +368,15 @@ export class DashboardMigrator { this.upgradeToGridLayout(old); } + if (oldVersion < 17) { + panelUpgrades.push(panel => { + if (panel.minSpan) { + panel.maxPerRow = GRID_COLUMN_COUNT / panel.minSpan; + } + delete panel.minSpan; + }); + } + if (panelUpgrades.length === 0) { return; } diff --git a/public/app/features/dashboard/dashboard_model.ts b/public/app/features/dashboard/dashboard_model.ts index 6f98bc5a17a..33529abdd15 100644 --- a/public/app/features/dashboard/dashboard_model.ts +++ b/public/app/features/dashboard/dashboard_model.ts @@ -442,7 +442,7 @@ export class DashboardModel { } const selectedOptions = this.getSelectedVariableOptions(variable); - const minWidth = panel.minSpan || 6; + const maxPerRow = panel.maxPerRow || 4; let xPos = 0; let yPos = panel.gridPos.y; @@ -462,7 +462,7 @@ export class DashboardModel { } else { // set width based on how many are selected // assumed the repeated panels should take up full row width - copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, minWidth); + copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, GRID_COLUMN_COUNT / maxPerRow); copy.gridPos.x = xPos; copy.gridPos.y = yPos; diff --git a/public/app/features/dashboard/panel_model.ts b/public/app/features/dashboard/panel_model.ts index 2d5a70b47dd..2fec8e379dd 100644 --- a/public/app/features/dashboard/panel_model.ts +++ b/public/app/features/dashboard/panel_model.ts @@ -77,7 +77,7 @@ export class PanelModel { repeatPanelId?: number; repeatDirection?: string; repeatedByRow?: boolean; - minSpan?: number; + maxPerRow?: number; collapsed?: boolean; panels?: any; soloMode?: boolean; diff --git a/public/app/features/dashboard/specs/dashboard_migration.test.ts b/public/app/features/dashboard/specs/dashboard_migration.test.ts index 5f693c9f6d9..e15bd65d5a5 100644 --- a/public/app/features/dashboard/specs/dashboard_migration.test.ts +++ b/public/app/features/dashboard/specs/dashboard_migration.test.ts @@ -127,7 +127,7 @@ describe('DashboardModel', () => { }); it('dashboard schema version should be set to latest', () => { - expect(model.schemaVersion).toBe(16); + expect(model.schemaVersion).toBe(17); }); it('graph thresholds should be migrated', () => { @@ -364,14 +364,6 @@ describe('DashboardModel', () => { expect(dashboard.panels.length).toBe(2); }); - it('minSpan should be twice', () => { - model.rows = [createRow({ height: 8 }, [[6]])]; - model.rows[0].panels[0] = { minSpan: 12 }; - - const dashboard = new DashboardModel(model); - expect(dashboard.panels[0].minSpan).toBe(24); - }); - it('should assign id', () => { model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]])]; model.rows[0].panels[0] = {}; @@ -380,6 +372,16 @@ describe('DashboardModel', () => { expect(dashboard.panels[0].id).toBe(1); }); }); + + describe('when migrating from minSpan to maxPerRow', () => { + it('maxPerRow should be correct', () => { + const model = { + panels: [{ minSpan: 8 }], + }; + const dashboard = new DashboardModel(model); + expect(dashboard.panels[0].maxPerRow).toBe(3); + }); + }); }); function createRow(options, panelDescriptions: any[]) { diff --git a/public/app/features/panel/partials/general_tab.html b/public/app/features/panel/partials/general_tab.html index d6c2d4804a0..76c38f73912 100644 --- a/public/app/features/panel/partials/general_tab.html +++ b/public/app/features/panel/partials/general_tab.html @@ -32,8 +32,8 @@
- Min width -
diff --git a/public/dashboards/home.json b/public/dashboards/home.json index 55cf7242aa6..f2c441053bb 100644 --- a/public/dashboards/home.json +++ b/public/dashboards/home.json @@ -65,7 +65,7 @@ } ], "rows": [], - "schemaVersion": 16, + "schemaVersion": 17, "style": "dark", "tags": [], "templating": { From 97b087f5a561019392bb21053a64e07c91bbbba2 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Tue, 21 Aug 2018 09:22:41 +0200 Subject: [PATCH 02/17] Use factors for max repeated panels per row --- public/app/core/specs/factors.test.ts | 8 ++++++++ public/app/core/utils/factors.ts | 5 +++++ public/app/features/dashboard/dashboard_migration.ts | 12 +++++++++++- public/app/features/panel/panel_ctrl.ts | 5 ++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 public/app/core/specs/factors.test.ts create mode 100644 public/app/core/utils/factors.ts diff --git a/public/app/core/specs/factors.test.ts b/public/app/core/specs/factors.test.ts new file mode 100644 index 00000000000..aed59b5be8b --- /dev/null +++ b/public/app/core/specs/factors.test.ts @@ -0,0 +1,8 @@ +import getFactors from 'app/core/utils/factors'; + +describe('factors', () => { + it('should return factors for 12', () => { + const factors = getFactors(12); + expect(factors).toEqual([1, 2, 3, 4, 6, 12]); + }); +}); diff --git a/public/app/core/utils/factors.ts b/public/app/core/utils/factors.ts new file mode 100644 index 00000000000..e9ce327a631 --- /dev/null +++ b/public/app/core/utils/factors.ts @@ -0,0 +1,5 @@ +// Returns the factors of a number +// Example getFactors(12) -> [1, 2, 3, 4, 6, 12] +export default function getFactors(num: number): number[] { + return Array.from(new Array(num + 1), (_, i) => i).filter(i => num % i === 0); +} diff --git a/public/app/features/dashboard/dashboard_migration.ts b/public/app/features/dashboard/dashboard_migration.ts index 4196456907f..2dbeb6c6e80 100644 --- a/public/app/features/dashboard/dashboard_migration.ts +++ b/public/app/features/dashboard/dashboard_migration.ts @@ -9,6 +9,7 @@ import { } from 'app/core/constants'; import { PanelModel } from './panel_model'; import { DashboardModel } from './dashboard_model'; +import getFactors from 'app/core/utils/factors'; export class DashboardMigrator { dashboard: DashboardModel; @@ -371,7 +372,16 @@ export class DashboardMigrator { if (oldVersion < 17) { panelUpgrades.push(panel => { if (panel.minSpan) { - panel.maxPerRow = GRID_COLUMN_COUNT / panel.minSpan; + const max = GRID_COLUMN_COUNT / panel.minSpan; + const factors = getFactors(GRID_COLUMN_COUNT); + // find the best match compared to factors + // (ie. [1,2,3,4,6,12,24] for 24 columns) + panel.maxPerRow = + factors[ + _.findIndex(factors, o => { + return o > max; + }) - 1 + ]; } delete panel.minSpan; }); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 432d22fecdf..f68423315d7 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -5,6 +5,7 @@ import Remarkable from 'remarkable'; import config from 'app/core/config'; import { profiler } from 'app/core/core'; import { Emitter } from 'app/core/core'; +import getFactors from 'app/core/utils/factors'; import { duplicatePanel, copyPanel as copyPanelUtil, @@ -12,7 +13,7 @@ import { sharePanel as sharePanelUtil, } from 'app/features/dashboard/utils/panel'; -import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants'; +import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants'; export class PanelCtrl { panel: any; @@ -32,6 +33,7 @@ export class PanelCtrl { events: Emitter; timing: any; loading: boolean; + maxPanelsPerRowOptions: number[]; constructor($scope, $injector) { this.$injector = $injector; @@ -92,6 +94,7 @@ export class PanelCtrl { if (!this.editModeInitiated) { this.editModeInitiated = true; this.events.emit('init-edit-mode', null); + this.maxPanelsPerRowOptions = getFactors(GRID_COLUMN_COUNT); } } From f374da032e5cc9a12646c596298a1d8d38200206 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Wed, 9 Jan 2019 11:34:13 +0100 Subject: [PATCH 03/17] Hint for user on when the repeat is applied --- public/app/features/panel/partials/general_tab.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/app/features/panel/partials/general_tab.html b/public/app/features/panel/partials/general_tab.html index 76c38f73912..8881d2c28a4 100644 --- a/public/app/features/panel/partials/general_tab.html +++ b/public/app/features/panel/partials/general_tab.html @@ -37,7 +37,12 @@ +
+
+ Note: You may need to change the variable selection to see this in action. +
+ From 9e3ab71e403298b9ffa7710e84a8e6b47b336dcc Mon Sep 17 00:00:00 2001 From: SamuelToh Date: Thu, 10 Jan 2019 10:47:22 +1000 Subject: [PATCH 04/17] 11503: escape measurement filter regex value --- public/app/plugins/datasource/influxdb/query_builder.ts | 3 ++- .../plugins/datasource/influxdb/specs/query_builder.test.ts | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/influxdb/query_builder.ts b/public/app/plugins/datasource/influxdb/query_builder.ts index a61216787d3..0b3e6f01e74 100644 --- a/public/app/plugins/datasource/influxdb/query_builder.ts +++ b/public/app/plugins/datasource/influxdb/query_builder.ts @@ -1,4 +1,5 @@ import _ from 'lodash'; +import kbn from 'app/core/utils/kbn'; function renderTagCondition(tag, index) { let str = ''; @@ -43,7 +44,7 @@ export class InfluxQueryBuilder { } else if (type === 'MEASUREMENTS') { query = 'SHOW MEASUREMENTS'; if (withMeasurementFilter) { - query += ' WITH MEASUREMENT =~ /' + withMeasurementFilter + '/'; + query += ' WITH MEASUREMENT =~ /' + kbn.regexEscape(withMeasurementFilter) + '/'; } } else if (type === 'FIELDS') { measurement = this.target.measurement; diff --git a/public/app/plugins/datasource/influxdb/specs/query_builder.test.ts b/public/app/plugins/datasource/influxdb/specs/query_builder.test.ts index e21b95ac374..ee617e7e774 100644 --- a/public/app/plugins/datasource/influxdb/specs/query_builder.test.ts +++ b/public/app/plugins/datasource/influxdb/specs/query_builder.test.ts @@ -50,6 +50,12 @@ describe('InfluxQueryBuilder', () => { expect(query).toBe('SHOW MEASUREMENTS WITH MEASUREMENT =~ /something/ LIMIT 100'); }); + it('should escape the regex value in measurement query', () => { + const builder = new InfluxQueryBuilder({ measurement: '', tags: [] }); + const query = builder.buildExploreQuery('MEASUREMENTS', undefined, 'abc/edf/'); + expect(query).toBe('SHOW MEASUREMENTS WITH MEASUREMENT =~ /abc\\/edf\\// LIMIT 100'); + }); + it('should have WITH MEASUREMENT WHERE in measurement query for non-empty query with tags', () => { const builder = new InfluxQueryBuilder({ measurement: '', From fbb3ad5fc45a93e040d1ab90092741612d990696 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 10 Jan 2019 09:35:48 +0100 Subject: [PATCH 05/17] make sure frequency cannot be zero frequency set to zero causes division by zero panics in the alert schedular. closes #14810 --- pkg/services/alerting/extractor.go | 2 +- pkg/services/alerting/rule.go | 21 ++++++-- pkg/services/alerting/rule_test.go | 80 ++++++++++++++++++++++-------- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/pkg/services/alerting/extractor.go b/pkg/services/alerting/extractor.go index e33e3dc2af3..5b911c5a9ad 100644 --- a/pkg/services/alerting/extractor.go +++ b/pkg/services/alerting/extractor.go @@ -112,7 +112,7 @@ func (e *DashAlertExtractor) getAlertFromPanels(jsonWithPanels *simplejson.Json, frequency, err := getTimeDurationStringToSeconds(jsonAlert.Get("frequency").MustString()) if err != nil { - return nil, ValidationError{Reason: "Could not parse frequency"} + return nil, ValidationError{Reason: err.Error()} } rawFor := jsonAlert.Get("for").MustString() diff --git a/pkg/services/alerting/rule.go b/pkg/services/alerting/rule.go index d2a505145ac..4423046d600 100644 --- a/pkg/services/alerting/rule.go +++ b/pkg/services/alerting/rule.go @@ -1,16 +1,21 @@ package alerting import ( + "errors" "fmt" "regexp" "strconv" "time" "github.com/grafana/grafana/pkg/components/simplejson" - m "github.com/grafana/grafana/pkg/models" ) +var ( + ErrFrequencyCannotBeZeroOrLess = errors.New(`"evaluate every" cannot be zero or below`) + ErrFrequencyCouldNotBeParsed = errors.New(`"evaluate every" field could not be parsed`) +) + type Rule struct { Id int64 OrgId int64 @@ -76,7 +81,7 @@ func getTimeDurationStringToSeconds(str string) (int64, error) { matches := ValueFormatRegex.FindAllString(str, 1) if len(matches) <= 0 { - return 0, fmt.Errorf("Frequency could not be parsed") + return 0, ErrFrequencyCouldNotBeParsed } value, err := strconv.Atoi(matches[0]) @@ -84,6 +89,10 @@ func getTimeDurationStringToSeconds(str string) (int64, error) { return 0, err } + if value == 0 { + return 0, ErrFrequencyCannotBeZeroOrLess + } + unit := UnitFormatRegex.FindAllString(str, 1)[0] if val, ok := unitMultiplier[unit]; ok { @@ -101,7 +110,6 @@ func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) { model.PanelId = ruleDef.PanelId model.Name = ruleDef.Name model.Message = ruleDef.Message - model.Frequency = ruleDef.Frequency model.State = ruleDef.State model.LastStateChange = ruleDef.NewStateDate model.For = ruleDef.For @@ -109,6 +117,13 @@ func NewRuleFromDBAlert(ruleDef *m.Alert) (*Rule, error) { model.ExecutionErrorState = m.ExecutionErrorOption(ruleDef.Settings.Get("executionErrorState").MustString("alerting")) model.StateChanges = ruleDef.StateChanges + model.Frequency = ruleDef.Frequency + // frequency cannot be zero since that would not execute the alert rule. + // so we fallback to 60 seconds if `Freqency` is missing + if model.Frequency == 0 { + model.Frequency = 60 + } + for _, v := range ruleDef.Settings.Get("notifications").MustArray() { jsonModel := simplejson.NewFromAny(v) id, err := jsonModel.Get("id").Int64() diff --git a/pkg/services/alerting/rule_test.go b/pkg/services/alerting/rule_test.go index 2a9e95e5723..cf25cc118f4 100644 --- a/pkg/services/alerting/rule_test.go +++ b/pkg/services/alerting/rule_test.go @@ -14,6 +14,36 @@ func (f *FakeCondition) Eval(context *EvalContext) (*ConditionResult, error) { return &ConditionResult{}, nil } +func TestAlertRuleFrequencyParsing(t *testing.T) { + tcs := []struct { + input string + err error + result int64 + }{ + {input: "10s", result: 10}, + {input: "10m", result: 600}, + {input: "1h", result: 3600}, + {input: "1o", result: 1}, + {input: "0s", err: ErrFrequencyCannotBeZeroOrLess}, + {input: "0m", err: ErrFrequencyCannotBeZeroOrLess}, + {input: "0h", err: ErrFrequencyCannotBeZeroOrLess}, + {input: "0", err: ErrFrequencyCannotBeZeroOrLess}, + {input: "-1s", err: ErrFrequencyCouldNotBeParsed}, + } + + for _, tc := range tcs { + r, err := getTimeDurationStringToSeconds(tc.input) + if err != tc.err { + t.Errorf("expected error: '%v' got: '%v'", tc.err, err) + return + } + + if r != tc.result { + t.Errorf("expected result: %d got %d", tc.result, r) + } + } +} + func TestAlertRuleModel(t *testing.T) { Convey("Testing alert rule", t, func() { @@ -21,26 +51,6 @@ func TestAlertRuleModel(t *testing.T) { return &FakeCondition{}, nil }) - Convey("Can parse seconds", func() { - seconds, _ := getTimeDurationStringToSeconds("10s") - So(seconds, ShouldEqual, 10) - }) - - Convey("Can parse minutes", func() { - seconds, _ := getTimeDurationStringToSeconds("10m") - So(seconds, ShouldEqual, 600) - }) - - Convey("Can parse hours", func() { - seconds, _ := getTimeDurationStringToSeconds("1h") - So(seconds, ShouldEqual, 3600) - }) - - Convey("defaults to seconds", func() { - seconds, _ := getTimeDurationStringToSeconds("1o") - So(seconds, ShouldEqual, 1) - }) - Convey("should return err for empty string", func() { _, err := getTimeDurationStringToSeconds("") So(err, ShouldNotBeNil) @@ -89,5 +99,35 @@ func TestAlertRuleModel(t *testing.T) { So(len(alertRule.Notifications), ShouldEqual, 2) }) }) + + Convey("can construct alert rule model with invalid frequency", func() { + json := ` + { + "name": "name2", + "description": "desc2", + "noDataMode": "critical", + "enabled": true, + "frequency": "0s", + "conditions": [ { "type": "test", "prop": 123 } ], + "notifications": [] + }` + + alertJSON, jsonErr := simplejson.NewJson([]byte(json)) + So(jsonErr, ShouldBeNil) + + alert := &m.Alert{ + Id: 1, + OrgId: 1, + DashboardId: 1, + PanelId: 1, + Frequency: 0, + + Settings: alertJSON, + } + + alertRule, err := NewRuleFromDBAlert(alert) + So(err, ShouldBeNil) + So(alertRule.Frequency, ShouldEqual, 60) + }) }) } From 702d4490018dcd41f763f81b7631fef17a873429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20W=C3=BCrbach?= Date: Thu, 20 Dec 2018 22:48:53 +0100 Subject: [PATCH 06/17] Docker image for ARM --- .circleci/config.yml | 44 +++++++++++++------------- build.go | 2 ++ packaging/docker/Dockerfile | 6 ++-- packaging/docker/build.sh | 40 ++++++++++++++++++----- packaging/docker/push_to_docker_hub.sh | 36 +++++++++++++++++---- scripts/build/build.sh | 7 ++++ 6 files changed, 96 insertions(+), 39 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 236d5aec398..3d66a8ef13b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -200,47 +200,47 @@ jobs: - dist/grafana* grafana-docker-master: - docker: - - image: docker:stable-git + machine: + image: circleci/classic:201808-01 steps: - checkout - attach_workspace: at: . - - setup_remote_docker - run: docker info - - run: cp dist/grafana-latest.linux-x64.tar.gz packaging/docker + - run: docker run --privileged linuxkit/binfmt:v0.6 + - run: cp dist/grafana-latest.linux-*.tar.gz packaging/docker - run: cd packaging/docker && ./build-deploy.sh "master-${CIRCLE_SHA1}" - - run: rm packaging/docker/grafana-latest.linux-x64.tar.gz + - run: rm packaging/docker/grafana-latest.linux-*.tar.gz - run: cp enterprise-dist/grafana-enterprise-*.linux-amd64.tar.gz packaging/docker/grafana-latest.linux-x64.tar.gz - run: cd packaging/docker && ./build-enterprise.sh "master" grafana-docker-pr: - docker: - - image: docker:stable-git + machine: + image: circleci/classic:201808-01 steps: - checkout - attach_workspace: at: . - - setup_remote_docker - run: docker info - - run: cp dist/grafana-latest.linux-x64.tar.gz packaging/docker + - run: docker run --privileged linuxkit/binfmt:v0.6 + - run: cp dist/grafana-latest.linux-*.tar.gz packaging/docker - run: cd packaging/docker && ./build.sh "${CIRCLE_SHA1}" grafana-docker-release: - docker: - - image: docker:stable-git - steps: - - checkout - - attach_workspace: - at: . - - setup_remote_docker - - run: docker info - - run: cp dist/grafana-latest.linux-x64.tar.gz packaging/docker - - run: cd packaging/docker && ./build-deploy.sh "${CIRCLE_TAG}" - - run: rm packaging/docker/grafana-latest.linux-x64.tar.gz - - run: cp enterprise-dist/grafana-enterprise-*.linux-amd64.tar.gz packaging/docker/grafana-latest.linux-x64.tar.gz - - run: cd packaging/docker && ./build-enterprise.sh "${CIRCLE_TAG}" + machine: + image: circleci/classic:201808-01 + steps: + - checkout + - attach_workspace: + at: . + - run: docker info + - run: docker run --privileged linuxkit/binfmt:v0.6 + - run: cp dist/grafana-latest.linux-*.tar.gz packaging/docker + - run: cd packaging/docker && ./build-deploy.sh "${CIRCLE_TAG}" + - run: rm packaging/docker/grafana-latest.linux-*.tar.gz + - run: cp enterprise-dist/grafana-enterprise-*.linux-amd64.tar.gz packaging/docker/grafana-latest.linux-x64.tar.gz + - run: cd packaging/docker && ./build-enterprise.sh "${CIRCLE_TAG}" build-enterprise: docker: diff --git a/build.go b/build.go index 9d5216de1d0..4486cd3deb9 100644 --- a/build.go +++ b/build.go @@ -164,6 +164,8 @@ func makeLatestDistCopies() { "_amd64.deb": "dist/grafana_latest_amd64.deb", ".x86_64.rpm": "dist/grafana-latest-1.x86_64.rpm", ".linux-amd64.tar.gz": "dist/grafana-latest.linux-x64.tar.gz", + ".linux-armv7.tar.gz": "dist/grafana-latest.linux-armv7.tar.gz", + ".linux-arm64.tar.gz": "dist/grafana-latest.linux-arm64.tar.gz", } for _, file := range files { diff --git a/packaging/docker/Dockerfile b/packaging/docker/Dockerfile index 4d4f6539972..d4f2f2aa7a3 100644 --- a/packaging/docker/Dockerfile +++ b/packaging/docker/Dockerfile @@ -1,4 +1,5 @@ -FROM debian:stretch-slim +ARG BASE_IMAGE=debian:stretch-slim +FROM ${BASE_IMAGE} ARG GRAFANA_TGZ="grafana-latest.linux-x64.tar.gz" @@ -10,7 +11,8 @@ COPY ${GRAFANA_TGZ} /tmp/grafana.tar.gz RUN mkdir /tmp/grafana && tar xfvz /tmp/grafana.tar.gz --strip-components=1 -C /tmp/grafana -FROM debian:stretch-slim +ARG BASE_IMAGE=debian:stretch-slim +FROM ${BASE_IMAGE} ARG GF_UID="472" ARG GF_GID="472" diff --git a/packaging/docker/build.sh b/packaging/docker/build.sh index c303c71cd5f..1bad2980d34 100755 --- a/packaging/docker/build.sh +++ b/packaging/docker/build.sh @@ -1,25 +1,49 @@ #!/bin/sh -_grafana_tag=$1 +_grafana_tag=${1:-} +_docker_repo=${2:-grafana/grafana} # If the tag starts with v, treat this as a official release if echo "$_grafana_tag" | grep -q "^v"; then _grafana_version=$(echo "${_grafana_tag}" | cut -d "v" -f 2) - _docker_repo=${2:-grafana/grafana} else _grafana_version=$_grafana_tag - _docker_repo=${2:-grafana/grafana-dev} fi echo "Building ${_docker_repo}:${_grafana_version}" -docker build \ - --tag "${_docker_repo}:${_grafana_version}" \ - --no-cache=true . +export DOCKER_CLI_EXPERIMENTAL=enabled + +# Build grafana image for a specific arch +docker_build () { + base_image=$1 + grafana_tgz=$2 + tag=$3 + + docker build \ + --build-arg BASE_IMAGE=${base_image} \ + --build-arg GRAFANA_TGZ=${grafana_tgz} \ + --tag "${tag}" \ + --no-cache=true . +} + +# Tag docker images of all architectures +docker_tag_all () { + repo=$1 + tag=$2 + docker tag "${_docker_repo}:${_grafana_version}" "${repo}:${tag}" + docker tag "${_docker_repo}-arm32v7-linux:${_grafana_version}" "${repo}-arm32v7-linux:${tag}" + docker tag "${_docker_repo}-arm64v8-linux:${_grafana_version}" "${repo}-arm64v8-linux:${tag}" +} + +docker_build "debian:stretch-slim" "grafana-latest.linux-x64.tar.gz" "${_docker_repo}:${_grafana_version}" +docker_build "arm32v7/debian:stretch-slim" "grafana-latest.linux-armv7.tar.gz" "${_docker_repo}-arm32v7-linux:${_grafana_version}" +docker_build "arm64v8/debian:stretch-slim" "grafana-latest.linux-arm64.tar.gz" "${_docker_repo}-arm64v8-linux:${_grafana_version}" # Tag as 'latest' for official release; otherwise tag as grafana/grafana:master if echo "$_grafana_tag" | grep -q "^v"; then - docker tag "${_docker_repo}:${_grafana_version}" "${_docker_repo}:latest" + docker_tag_all "${_docker_repo}" "latest" else - docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana:master" + docker_tag_all "${_docker_repo}" "master" + docker tag "${_docker_repo}:${_grafana_version} grafana/grafana-dev:${_grafana_version}" fi diff --git a/packaging/docker/push_to_docker_hub.sh b/packaging/docker/push_to_docker_hub.sh index 526c216f8fa..cef6d596851 100755 --- a/packaging/docker/push_to_docker_hub.sh +++ b/packaging/docker/push_to_docker_hub.sh @@ -1,24 +1,46 @@ #!/bin/sh set -e -_grafana_tag=$1 +_grafana_tag=${1:-} +_docker_repo=${2:-grafana/grafana} # If the tag starts with v, treat this as a official release if echo "$_grafana_tag" | grep -q "^v"; then _grafana_version=$(echo "${_grafana_tag}" | cut -d "v" -f 2) - _docker_repo=${2:-grafana/grafana} else _grafana_version=$_grafana_tag - _docker_repo=${2:-grafana/grafana-dev} fi +export DOCKER_CLI_EXPERIMENTAL=enabled + echo "pushing ${_docker_repo}:${_grafana_version}" -docker push "${_docker_repo}:${_grafana_version}" + + +docker_push_all () { + repo=$1 + tag=$2 + + # Push each image individually + docker push "${repo}:${tag}" + docker push "${repo}-arm32v7-linux:${tag}" + docker push "${repo}-arm64v8-linux:${tag}" + + # Create and push a multi-arch manifest + docker manifest create "${repo}:${tag}" \ + "${repo}:${tag}" \ + "${repo}-arm32v7-linux:${tag}" \ + "${repo}-arm64v8-linux:${tag}" + + docker manifest push "${repo}:${tag}" +} if echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -vq "beta"; then echo "pushing ${_docker_repo}:latest" - docker push "${_docker_repo}:latest" + docker_push_all "${_docker_repo}" "latest" + docker_push_all "${_docker_repo}" "${_grafana_version}" +elif echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -q "beta"; then + docker_push_all "${_docker_repo}" "${_grafana_version}" elif echo "$_grafana_tag" | grep -q "master"; then - echo "pushing grafana/grafana:master" - docker push grafana/grafana:master + docker_push_all "grafana/grafana" "master" + docker push "grafana/grafana-dev:${_grafana_version}" fi diff --git a/scripts/build/build.sh b/scripts/build/build.sh index 8362942c6cd..1222053f1c8 100755 --- a/scripts/build/build.sh +++ b/scripts/build/build.sh @@ -8,6 +8,8 @@ set -e EXTRA_OPTS="$@" +CCARMV7=arm-linux-gnueabihf-gcc +CCARM64=aarch64-linux-gnu-gcc CCX64=/tmp/x86_64-centos6-linux-gnu/bin/x86_64-centos6-linux-gnu-gcc GOPATH=/go @@ -26,6 +28,9 @@ fi echo "Build arguments: $OPT" +go run build.go -goarch armv7 -cc ${CCARMV7} ${OPT} build +go run build.go -goarch arm64 -cc ${CCARM64} ${OPT} build + CC=${CCX64} go run build.go ${OPT} build yarn install --pure-lockfile --no-progress @@ -44,3 +49,5 @@ source /etc/profile.d/rvm.sh echo "Packaging" go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only latest +go run build.go -goos linux -pkg-arch armv7 ${OPT} package-only latest +go run build.go -goos linux -pkg-arch arm64 ${OPT} package-only latest From a82f0ed393ef14007b4333bcb83b01f8a58c8aeb Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Thu, 10 Jan 2019 13:46:03 +0100 Subject: [PATCH 07/17] build: tags arm as well as amd64 as latest. --- packaging/docker/build.sh | 2 +- packaging/docker/push_to_docker_hub.sh | 2 +- scripts/build/build-all.sh | 3 ++- scripts/build/build.sh | 8 +++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packaging/docker/build.sh b/packaging/docker/build.sh index 1bad2980d34..a522363089b 100755 --- a/packaging/docker/build.sh +++ b/packaging/docker/build.sh @@ -45,5 +45,5 @@ if echo "$_grafana_tag" | grep -q "^v"; then docker_tag_all "${_docker_repo}" "latest" else docker_tag_all "${_docker_repo}" "master" - docker tag "${_docker_repo}:${_grafana_version} grafana/grafana-dev:${_grafana_version}" + docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana-dev:${_grafana_version}" fi diff --git a/packaging/docker/push_to_docker_hub.sh b/packaging/docker/push_to_docker_hub.sh index cef6d596851..37b5ae0095c 100755 --- a/packaging/docker/push_to_docker_hub.sh +++ b/packaging/docker/push_to_docker_hub.sh @@ -41,6 +41,6 @@ if echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -vq "beta" elif echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -q "beta"; then docker_push_all "${_docker_repo}" "${_grafana_version}" elif echo "$_grafana_tag" | grep -q "master"; then - docker_push_all "grafana/grafana" "master" + docker_push_all "${_docker_repo}" "master" docker push "grafana/grafana-dev:${_grafana_version}" fi diff --git a/scripts/build/build-all.sh b/scripts/build/build-all.sh index 3013452a279..980ef5cc4c2 100755 --- a/scripts/build/build-all.sh +++ b/scripts/build/build-all.sh @@ -59,7 +59,7 @@ go run build.go ${OPT} build-frontend source /etc/profile.d/rvm.sh echo "Packaging" -go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only latest +go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only #removing amd64 phantomjs bin for armv7/arm64 packages rm tools/phantomjs/phantomjs go run build.go -goos linux -pkg-arch armv7 ${OPT} package-only @@ -80,3 +80,4 @@ else fi go run build.go -goos windows -pkg-arch amd64 ${OPT} package-only +go run build.go latest \ No newline at end of file diff --git a/scripts/build/build.sh b/scripts/build/build.sh index 1222053f1c8..ac6aab0b867 100755 --- a/scripts/build/build.sh +++ b/scripts/build/build.sh @@ -48,6 +48,8 @@ go run build.go ${OPT} build-frontend source /etc/profile.d/rvm.sh echo "Packaging" -go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only latest -go run build.go -goos linux -pkg-arch armv7 ${OPT} package-only latest -go run build.go -goos linux -pkg-arch arm64 ${OPT} package-only latest +go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only +go run build.go -goos linux -pkg-arch armv7 ${OPT} package-only +go run build.go -goos linux -pkg-arch arm64 ${OPT} package-only + +go run build.go latest From c22ef628f32d5d7d29e44db634a48868d48d740b Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Thu, 10 Jan 2019 15:11:51 +0100 Subject: [PATCH 08/17] build: removes curl install from build. --- packaging/docker/build-deploy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/packaging/docker/build-deploy.sh b/packaging/docker/build-deploy.sh index ac3226a4a61..22655bead8c 100755 --- a/packaging/docker/build-deploy.sh +++ b/packaging/docker/build-deploy.sh @@ -8,6 +8,5 @@ docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" ./push_to_docker_hub.sh "$_grafana_version" if echo "$_grafana_version" | grep -q "^master-"; then - apk add --no-cache curl ./deploy_to_k8s.sh "grafana/grafana-dev:$_grafana_version" fi From cdfdc676ae5e25b03736438dccd9e8b309bf9238 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Thu, 10 Jan 2019 16:50:36 +0100 Subject: [PATCH 09/17] changelog: docker images for arm. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 671740f7225..46b7381cba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ * **OAuth**: Support OAuth providers that are not RFC6749 compliant [#14562](https://github.com/grafana/grafana/issues/14562), thx [@tdabasinskas](https://github.com/tdabasinskas) * **Units**: Add blood glucose level units mg/dL and mmol/L [#14519](https://github.com/grafana/grafana/issues/14519), thx [@kjedamzik](https://github.com/kjedamzik) * **Stackdriver**: Aggregating series returns more than one series [#14581](https://github.com/grafana/grafana/issues/14581) and [#13914](https://github.com/grafana/grafana/issues/13914), thx [@kinok](https://github.com/kinok) +* **Docker**: Build and publish docker images for armv7 and arm64 [#14617](https://github.com/grafana/grafana/pull/14617), thx [@johanneswuerbach](https://github.com/johanneswuerbach) ### Bug fixes * **Search**: Fix for issue with scrolling the "tags filter" dropdown, fixes [#14486](https://github.com/grafana/grafana/issues/14486) From 0f82fffed65449299394c109903f1ccac6d268d7 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Thu, 10 Jan 2019 15:22:30 +0100 Subject: [PATCH 10/17] build: makes sure all builds use the latest container. --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3d66a8ef13b..7f9c40bd968 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -127,7 +127,7 @@ jobs: build-all: docker: - - image: grafana/build-container:1.2.1 + - image: grafana/build-container:1.2.2 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -244,7 +244,7 @@ jobs: build-enterprise: docker: - - image: grafana/build-container:1.2.1 + - image: grafana/build-container:1.2.2 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -276,7 +276,7 @@ jobs: build-all-enterprise: docker: - - image: grafana/build-container:1.2.1 + - image: grafana/build-container:1.2.2 working_directory: /go/src/github.com/grafana/grafana steps: - checkout From 60fadcf1e583b1243a2a0334389210a9b7a2807a Mon Sep 17 00:00:00 2001 From: Dominik Prokop Date: Thu, 10 Jan 2019 20:15:03 +0100 Subject: [PATCH 11/17] Fix panel time overrides not being applied fully When both relative and time shift were applied, only time shift was taken into consideration --- public/app/features/dashboard/utils/panel.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/public/app/features/dashboard/utils/panel.ts b/public/app/features/dashboard/utils/panel.ts index f7ed0efd910..cf00a31c71e 100644 --- a/public/app/features/dashboard/utils/panel.ts +++ b/public/app/features/dashboard/utils/panel.ts @@ -143,12 +143,9 @@ export function applyPanelTimeOverrides(panel: PanelModel, timeRange: TimeRange) const timeShift = '-' + timeShiftInterpolated; newTimeData.timeInfo += ' timeshift ' + timeShift; newTimeData.timeRange = { - from: dateMath.parseDateMath(timeShift, timeRange.from, false), - to: dateMath.parseDateMath(timeShift, timeRange.to, true), - raw: { - from: timeRange.from, - to: timeRange.to, - }, + from: dateMath.parseDateMath(timeShift, newTimeData.timeRange.from, false), + to: dateMath.parseDateMath(timeShift, newTimeData.timeRange.to, true), + raw: newTimeData.timeRange.raw, }; } From 08ac2959a4d17a58aaf1f64738d1e442c6de93eb Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Thu, 10 Jan 2019 21:47:09 +0000 Subject: [PATCH 12/17] Moving to grafana ui, fix issue with TestRuleResult --- .../LoadingPlaceholder/LoadingPlaceholder.tsx | 11 ++++++++++ packages/grafana-ui/src/components/index.ts | 1 + public/app/features/alerting/AlertTab.tsx | 21 ++++++------------- .../features/alerting/TestRuleButton.test.tsx | 6 +++--- ...{TestRuleButton.tsx => TestRuleResult.tsx} | 6 ++++-- .../dashboard/dashgrid/QueriesTab.tsx | 11 +++------- 6 files changed, 28 insertions(+), 28 deletions(-) create mode 100644 packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx rename public/app/features/alerting/{TestRuleButton.tsx => TestRuleResult.tsx} (86%) diff --git a/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx new file mode 100644 index 00000000000..01048014f8a --- /dev/null +++ b/packages/grafana-ui/src/components/LoadingPlaceholder/LoadingPlaceholder.tsx @@ -0,0 +1,11 @@ +import React, { SFC } from 'react'; + +interface LoadingPlaceholderProps { + text: string; +} + +export const LoadingPlaceholder: SFC = ({ text }) => ( +
+ {text} +
+); diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index abb1cf1b34c..6fa7de62572 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -2,3 +2,4 @@ export { DeleteButton } from './DeleteButton/DeleteButton'; export { Tooltip } from './Tooltip/Tooltip'; export { Portal } from './Portal/Portal'; export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar'; +export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder'; diff --git a/public/app/features/alerting/AlertTab.tsx b/public/app/features/alerting/AlertTab.tsx index 5623fac95c1..0520cd5e6e8 100644 --- a/public/app/features/alerting/AlertTab.tsx +++ b/public/app/features/alerting/AlertTab.tsx @@ -1,11 +1,12 @@ // Libraries -import React, { PureComponent, SFC } from 'react'; +import React, { PureComponent } from 'react'; // Services & Utils import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoader'; import appEvents from 'app/core/app_events'; // Components +import { LoadingPlaceholder } from '@grafana/ui'; import { EditorTabBody, EditorToolbarView } from '../dashboard/dashgrid/EditorTabBody'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import StateHistory from './StateHistory'; @@ -14,7 +15,7 @@ import 'app/features/alerting/AlertTabCtrl'; // Types import { DashboardModel } from '../dashboard/dashboard_model'; import { PanelModel } from '../dashboard/panel_model'; -import { TestRuleButton } from './TestRuleButton'; +import { TestRuleResult } from './TestRuleResult'; interface Props { angularPanel?: AngularComponent; @@ -22,16 +23,6 @@ interface Props { panel: PanelModel; } -interface LoadingPlaceholderProps { - text: string; -} - -const LoadingPlaceholder: SFC = ({ text }) => ( -
- {text} -
-); - export class AlertTab extends PureComponent { element: any; component: AngularComponent; @@ -120,14 +111,14 @@ export class AlertTab extends PureComponent { }; }; - renderTestRuleButton = () => { + renderTestRuleResult = () => { const { panel, dashboard } = this.props; - return ; + return ; }; testRule = (): EditorToolbarView => ({ title: 'Test Rule', - render: () => this.renderTestRuleButton(), + render: () => this.renderTestRuleResult(), }); onAddAlert = () => { diff --git a/public/app/features/alerting/TestRuleButton.test.tsx b/public/app/features/alerting/TestRuleButton.test.tsx index ae3b570cf43..b762ebf2579 100644 --- a/public/app/features/alerting/TestRuleButton.test.tsx +++ b/public/app/features/alerting/TestRuleButton.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { DashboardModel } from '../dashboard/dashboard_model'; -import { Props, TestRuleButton } from './TestRuleButton'; +import { Props, TestRuleResult } from './TestRuleResult'; jest.mock('app/core/services/backend_srv', () => ({ getBackendSrv: () => ({ @@ -18,9 +18,9 @@ const setup = (propOverrides?: object) => { Object.assign(props, propOverrides); - const wrapper = shallow(); + const wrapper = shallow(); - return { wrapper, instance: wrapper.instance() as TestRuleButton }; + return { wrapper, instance: wrapper.instance() as TestRuleResult }; }; describe('Render', () => { diff --git a/public/app/features/alerting/TestRuleButton.tsx b/public/app/features/alerting/TestRuleResult.tsx similarity index 86% rename from public/app/features/alerting/TestRuleButton.tsx rename to public/app/features/alerting/TestRuleResult.tsx index f9927b1a182..e55dd6aae51 100644 --- a/public/app/features/alerting/TestRuleButton.tsx +++ b/public/app/features/alerting/TestRuleResult.tsx @@ -14,7 +14,7 @@ interface State { testRuleResponse: {}; } -export class TestRuleButton extends PureComponent { +export class TestRuleResult extends PureComponent { readonly state: State = { isLoading: false, testRuleResponse: {}, @@ -27,8 +27,10 @@ export class TestRuleButton extends PureComponent { async testRule() { const { panelId, dashboard } = this.props; const payload = { dashboard: dashboard.getSaveModelClone(), panelId }; + + this.setState({ isLoading: true }); const testRuleResponse = await getBackendSrv().post(`/api/alerts/test`, payload); - this.setState(prevState => ({ ...prevState, isLoading: false, testRuleResponse })); + this.setState({ isLoading: false, testRuleResponse }); } render() { diff --git a/public/app/features/dashboard/dashgrid/QueriesTab.tsx b/public/app/features/dashboard/dashgrid/QueriesTab.tsx index 77ab64b1dba..eab7a95d471 100644 --- a/public/app/features/dashboard/dashgrid/QueriesTab.tsx +++ b/public/app/features/dashboard/dashgrid/QueriesTab.tsx @@ -1,15 +1,16 @@ // Libraries -import React, { PureComponent, SFC } from 'react'; +import React, { PureComponent } from 'react'; import _ from 'lodash'; // Components import 'app/features/panel/metrics_tab'; -import { EditorTabBody, EditorToolbarView} from './EditorTabBody'; +import { EditorTabBody, EditorToolbarView } from './EditorTabBody'; import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker'; import { QueryInspector } from './QueryInspector'; import { QueryOptions } from './QueryOptions'; import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab'; import { PanelOptionSection } from './PanelOptionSection'; +import { LoadingPlaceholder } from '@grafana/ui'; // Services import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; @@ -36,12 +37,6 @@ interface State { isAddingMixed: boolean; } -interface LoadingPlaceholderProps { - text: string; -} - -const LoadingPlaceholder: SFC = ({ text }) =>

{text}

; - export class QueriesTab extends PureComponent { element: HTMLElement; component: AngularComponent; From 2f0ab99ae5e63bc58984b6cc126228962ea38b21 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Thu, 10 Jan 2019 22:15:37 +0000 Subject: [PATCH 13/17] Fixing test and small refactor --- public/app/features/alerting/AlertTab.tsx | 3 +-- ...tRuleButton.test.tsx => TestRuleResult.test.tsx} | 1 - public/app/features/alerting/TestRuleResult.tsx | 3 +-- .../__snapshots__/TestRuleButton.test.tsx.snap | 13 ------------- .../__snapshots__/TestRuleResult.test.tsx.snap | 7 +++++++ .../app/features/dashboard/dashgrid/QueriesTab.tsx | 3 +-- .../features/dashboard/dashgrid/QueryInspector.tsx | 3 +-- 7 files changed, 11 insertions(+), 22 deletions(-) rename public/app/features/alerting/{TestRuleButton.test.tsx => TestRuleResult.test.tsx} (97%) delete mode 100644 public/app/features/alerting/__snapshots__/TestRuleButton.test.tsx.snap create mode 100644 public/app/features/alerting/__snapshots__/TestRuleResult.test.tsx.snap diff --git a/public/app/features/alerting/AlertTab.tsx b/public/app/features/alerting/AlertTab.tsx index 0520cd5e6e8..2a1b3d12ecf 100644 --- a/public/app/features/alerting/AlertTab.tsx +++ b/public/app/features/alerting/AlertTab.tsx @@ -6,7 +6,6 @@ import { AngularComponent, getAngularLoader } from 'app/core/services/AngularLoa import appEvents from 'app/core/app_events'; // Components -import { LoadingPlaceholder } from '@grafana/ui'; import { EditorTabBody, EditorToolbarView } from '../dashboard/dashgrid/EditorTabBody'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; import StateHistory from './StateHistory'; @@ -113,7 +112,7 @@ export class AlertTab extends PureComponent { renderTestRuleResult = () => { const { panel, dashboard } = this.props; - return ; + return ; }; testRule = (): EditorToolbarView => ({ diff --git a/public/app/features/alerting/TestRuleButton.test.tsx b/public/app/features/alerting/TestRuleResult.test.tsx similarity index 97% rename from public/app/features/alerting/TestRuleButton.test.tsx rename to public/app/features/alerting/TestRuleResult.test.tsx index b762ebf2579..9beb5ade632 100644 --- a/public/app/features/alerting/TestRuleButton.test.tsx +++ b/public/app/features/alerting/TestRuleResult.test.tsx @@ -13,7 +13,6 @@ const setup = (propOverrides?: object) => { const props: Props = { panelId: 1, dashboard: new DashboardModel({ panels: [{ id: 1 }] }), - LoadingPlaceholder: {}, }; Object.assign(props, propOverrides); diff --git a/public/app/features/alerting/TestRuleResult.tsx b/public/app/features/alerting/TestRuleResult.tsx index e55dd6aae51..4014e529597 100644 --- a/public/app/features/alerting/TestRuleResult.tsx +++ b/public/app/features/alerting/TestRuleResult.tsx @@ -2,11 +2,11 @@ import React, { PureComponent } from 'react'; import { JSONFormatter } from 'app/core/components/JSONFormatter/JSONFormatter'; import { getBackendSrv } from 'app/core/services/backend_srv'; import { DashboardModel } from '../dashboard/dashboard_model'; +import { LoadingPlaceholder } from '@grafana/ui/src'; export interface Props { panelId: number; dashboard: DashboardModel; - LoadingPlaceholder: any; } interface State { @@ -35,7 +35,6 @@ export class TestRuleResult extends PureComponent { render() { const { testRuleResponse, isLoading } = this.state; - const { LoadingPlaceholder } = this.props; if (isLoading === true) { return ; diff --git a/public/app/features/alerting/__snapshots__/TestRuleButton.test.tsx.snap b/public/app/features/alerting/__snapshots__/TestRuleButton.test.tsx.snap deleted file mode 100644 index d1ed3e64e99..00000000000 --- a/public/app/features/alerting/__snapshots__/TestRuleButton.test.tsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Render should render component 1`] = ` - -`; diff --git a/public/app/features/alerting/__snapshots__/TestRuleResult.test.tsx.snap b/public/app/features/alerting/__snapshots__/TestRuleResult.test.tsx.snap new file mode 100644 index 00000000000..73f85f12354 --- /dev/null +++ b/public/app/features/alerting/__snapshots__/TestRuleResult.test.tsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render should render component 1`] = ` + +`; diff --git a/public/app/features/dashboard/dashgrid/QueriesTab.tsx b/public/app/features/dashboard/dashgrid/QueriesTab.tsx index eab7a95d471..a20f8627fba 100644 --- a/public/app/features/dashboard/dashgrid/QueriesTab.tsx +++ b/public/app/features/dashboard/dashgrid/QueriesTab.tsx @@ -10,7 +10,6 @@ import { QueryInspector } from './QueryInspector'; import { QueryOptions } from './QueryOptions'; import { AngularQueryComponentScope } from 'app/features/panel/metrics_tab'; import { PanelOptionSection } from './PanelOptionSection'; -import { LoadingPlaceholder } from '@grafana/ui'; // Services import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; @@ -129,7 +128,7 @@ export class QueriesTab extends PureComponent { renderQueryInspector = () => { const { panel } = this.props; - return ; + return ; }; renderHelp = () => { diff --git a/public/app/features/dashboard/dashgrid/QueryInspector.tsx b/public/app/features/dashboard/dashgrid/QueryInspector.tsx index 090bc220bc0..8e490f6b622 100644 --- a/public/app/features/dashboard/dashgrid/QueryInspector.tsx +++ b/public/app/features/dashboard/dashgrid/QueryInspector.tsx @@ -2,6 +2,7 @@ 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'; +import { LoadingPlaceholder } from '@grafana/ui'; interface DsQuery { isLoading: boolean; @@ -10,7 +11,6 @@ interface DsQuery { interface Props { panel: any; - LoadingPlaceholder: any; } interface State { @@ -177,7 +177,6 @@ export class QueryInspector extends PureComponent { render() { const { response, isLoading } = this.state.dsQuery; - const { LoadingPlaceholder } = this.props; const { isMocking } = this.state; const openNodes = this.getNrOfOpenNodes(); From d376fae393b099811af036e799738880a2e542ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 10 Jan 2019 13:34:23 +0100 Subject: [PATCH 14/17] Moved colorpicker to ui/components --- packages/grafana-ui/package.json | 4 +- .../ColorPicker}/ColorPalette.test.tsx | 2 +- .../components/ColorPicker}/ColorPalette.tsx | 6 +- .../components/ColorPicker}/ColorPicker.tsx | 10 +- .../ColorPicker}/ColorPickerPopover.tsx | 33 +++---- .../ColorPicker}/SeriesColorPicker.tsx | 4 +- .../ColorPicker}/SeriesColorPickerPopover.tsx | 11 +-- .../ColorPicker}/SpectrumPicker.tsx | 8 +- .../__snapshots__/ColorPalette.test.tsx.snap | 0 packages/grafana-ui/src/components/index.ts | 3 + packages/grafana-ui/src/index.ts | 1 + packages/grafana-ui/src/utils/colors.ts | 94 +++++++++++++++++++ packages/grafana-ui/src/utils/index.ts | 2 + public/app/core/angular_wrappers.ts | 10 ++ public/app/core/core.ts | 4 +- public/app/core/logs_model.ts | 4 +- public/app/core/utils/colors.ts | 94 ------------------- public/app/core/utils/explore.ts | 2 +- .../app/features/annotations/event_manager.ts | 7 +- .../app/features/dashboard/dashboard_model.ts | 2 +- public/app/plugins/panel/gauge/Thresholds.tsx | 2 +- .../panel/graph/Legend/LegendSeriesItem.tsx | 2 +- .../app/plugins/panel/graph/data_processor.ts | 3 +- .../app/plugins/panel/graph2/GraphPanel.tsx | 2 +- public/app/routes/GrafanaCtrl.ts | 4 +- public/app/viz/state/timeSeries.ts | 2 +- 26 files changed, 157 insertions(+), 159 deletions(-) rename {public/app/core/specs => packages/grafana-ui/src/components/ColorPicker}/ColorPalette.test.tsx (80%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/ColorPalette.tsx (90%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/ColorPicker.tsx (85%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/ColorPickerPopover.tsx (83%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/SeriesColorPicker.tsx (96%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/SeriesColorPickerPopover.tsx (86%) rename {public/app/core/components/colorpicker => packages/grafana-ui/src/components/ColorPicker}/SpectrumPicker.tsx (92%) rename {public/app/core/specs => packages/grafana-ui/src/components/ColorPicker}/__snapshots__/ColorPalette.test.tsx.snap (100%) create mode 100644 packages/grafana-ui/src/utils/colors.ts diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 6548f75e91f..5221e1ba02f 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -23,7 +23,9 @@ "react-highlight-words": "0.11.0", "react-popper": "^1.3.0", "react-transition-group": "^2.2.1", - "react-virtualized": "^9.21.0" + "react-virtualized": "^9.21.0", + "tether-drop": "https://github.com/torkelo/drop/tarball/master", + "tinycolor2": "^1.4.1" }, "devDependencies": { "@types/classnames": "^2.2.6", diff --git a/public/app/core/specs/ColorPalette.test.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPalette.test.tsx similarity index 80% rename from public/app/core/specs/ColorPalette.test.tsx rename to packages/grafana-ui/src/components/ColorPicker/ColorPalette.test.tsx index fb1124aa975..0714180de54 100644 --- a/public/app/core/specs/ColorPalette.test.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPalette.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import renderer from 'react-test-renderer'; -import { ColorPalette } from '../components/colorpicker/ColorPalette'; +import { ColorPalette } from './ColorPalette'; describe('CollorPalette', () => { it('renders correctly', () => { diff --git a/public/app/core/components/colorpicker/ColorPalette.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPalette.tsx similarity index 90% rename from public/app/core/components/colorpicker/ColorPalette.tsx rename to packages/grafana-ui/src/components/ColorPicker/ColorPalette.tsx index edb2629d16d..03ed9949361 100644 --- a/public/app/core/components/colorpicker/ColorPalette.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPalette.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { sortedColors } from 'app/core/utils/colors'; +import { sortedColors } from '../../utils'; export interface Props { color: string; @@ -9,13 +9,13 @@ export interface Props { export class ColorPalette extends React.Component { paletteColors: string[]; - constructor(props) { + constructor(props: Props) { super(props); this.paletteColors = sortedColors; this.onColorSelect = this.onColorSelect.bind(this); } - onColorSelect(color) { + onColorSelect(color: string) { return () => { this.props.onColorSelect(color); }; diff --git a/public/app/core/components/colorpicker/ColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx similarity index 85% rename from public/app/core/components/colorpicker/ColorPicker.tsx rename to packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx index 9541001b0a8..fbe14d4eb8c 100644 --- a/public/app/core/components/colorpicker/ColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx @@ -2,7 +2,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Drop from 'tether-drop'; import { ColorPickerPopover } from './ColorPickerPopover'; -import { react2AngularDirective } from 'app/core/utils/react2angular'; export interface Props { color: string; @@ -10,7 +9,7 @@ export interface Props { } export class ColorPicker extends React.Component { - pickerElem: HTMLElement; + pickerElem: HTMLElement | null; colorPickerDrop: any; openColorPicker = () => { @@ -45,7 +44,7 @@ export class ColorPicker extends React.Component { }, 100); }; - onColorSelect = color => { + onColorSelect = (color: string) => { this.props.onChange(color); }; @@ -59,8 +58,3 @@ export class ColorPicker extends React.Component { ); } } - -react2AngularDirective('colorPicker', ColorPicker, [ - 'color', - ['onChange', { watchDepth: 'reference', wrapApply: true }], -]); diff --git a/public/app/core/components/colorpicker/ColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx similarity index 83% rename from public/app/core/components/colorpicker/ColorPickerPopover.tsx rename to packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx index c42bcfa1d06..e8305c99319 100644 --- a/public/app/core/components/colorpicker/ColorPickerPopover.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPickerPopover.tsx @@ -14,7 +14,7 @@ export interface Props { export class ColorPickerPopover extends React.Component { pickerNavElem: any; - constructor(props) { + constructor(props: Props) { super(props); this.state = { tab: 'palette', @@ -23,60 +23,51 @@ export class ColorPickerPopover extends React.Component { }; } - setPickerNavElem(elem) { + setPickerNavElem(elem: any) { this.pickerNavElem = $(elem); } - setColor(color) { + setColor(color: string) { const newColor = tinycolor(color); if (newColor.isValid()) { - this.setState({ - color: newColor.toString(), - colorString: newColor.toString(), - }); + this.setState({ color: newColor.toString(), colorString: newColor.toString() }); this.props.onColorSelect(color); } } - sampleColorSelected(color) { + sampleColorSelected(color: string) { this.setColor(color); } - spectrumColorSelected(color) { + spectrumColorSelected(color: any) { const rgbColor = color.toRgbString(); this.setColor(rgbColor); } - onColorStringChange(e) { + onColorStringChange(e: any) { const colorString = e.target.value; - this.setState({ - colorString: colorString, - }); + this.setState({ colorString: colorString }); const newColor = tinycolor(colorString); if (newColor.isValid()) { // Update only color state const newColorString = newColor.toString(); - this.setState({ - color: newColorString, - }); + this.setState({ color: newColorString }); this.props.onColorSelect(newColorString); } } - onColorStringBlur(e) { + onColorStringBlur(e: any) { const colorString = e.target.value; this.setColor(colorString); } componentDidMount() { this.pickerNavElem.find('li:first').addClass('active'); - this.pickerNavElem.on('show', e => { + this.pickerNavElem.on('show', (e: any) => { // use href attr (#name => name) const tab = e.target.hash.slice(1); - this.setState({ - tab: tab, - }); + this.setState({ tab: tab }); }); } diff --git a/public/app/core/components/colorpicker/SeriesColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx similarity index 96% rename from public/app/core/components/colorpicker/SeriesColorPicker.tsx rename to packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx index 32b7554e38d..b8ba03b7feb 100644 --- a/public/app/core/components/colorpicker/SeriesColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx @@ -8,7 +8,7 @@ export interface SeriesColorPickerProps { yaxis?: number; optionalClass?: string; onColorChange: (newColor: string) => void; - onToggleAxis?: () => void; + onToggleAxis: () => void; } export class SeriesColorPicker extends React.Component { @@ -21,7 +21,7 @@ export class SeriesColorPicker extends React.Component { onToggleAxis: () => {}, }; - constructor(props) { + constructor(props: SeriesColorPickerProps) { super(props); } diff --git a/public/app/core/components/colorpicker/SeriesColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx similarity index 86% rename from public/app/core/components/colorpicker/SeriesColorPickerPopover.tsx rename to packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx index 085d554300d..9036a1a2ffd 100644 --- a/public/app/core/components/colorpicker/SeriesColorPickerPopover.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx @@ -1,12 +1,11 @@ import React from 'react'; import { ColorPickerPopover } from './ColorPickerPopover'; -import { react2AngularDirective } from 'app/core/utils/react2angular'; export interface SeriesColorPickerPopoverProps { color: string; yaxis?: number; onColorChange: (color: string) => void; - onToggleAxis?: () => void; + onToggleAxis: () => void; } export class SeriesColorPickerPopover extends React.PureComponent { @@ -30,7 +29,7 @@ interface AxisSelectorState { } export class AxisSelector extends React.PureComponent { - constructor(props) { + constructor(props: AxisSelectorProps) { super(props); this.state = { yaxis: this.props.yaxis, @@ -62,9 +61,3 @@ export class AxisSelector extends React.PureComponent { elem: any; isMoving: boolean; - constructor(props) { + constructor(props: Props) { super(props); this.onSpectrumMove = this.onSpectrumMove.bind(this); this.setComponentElem = this.setComponentElem.bind(this); } - setComponentElem(elem) { + setComponentElem(elem: any) { this.elem = $(elem); } - onSpectrumMove(color) { + onSpectrumMove(color: any) { this.isMoving = true; this.props.onColorSelect(color); } @@ -46,7 +46,7 @@ export class SpectrumPicker extends React.Component { this.elem.spectrum('set', this.props.color); } - componentWillUpdate(nextProps) { + componentWillUpdate(nextProps: any) { // If user move pointer over spectrum field this produce 'move' event and component // may update props.color. We don't want to update spectrum color in this case, so we can use // isMoving flag for tracking moving state. Flag should be cleared in componentDidUpdate() which diff --git a/public/app/core/specs/__snapshots__/ColorPalette.test.tsx.snap b/packages/grafana-ui/src/components/ColorPicker/__snapshots__/ColorPalette.test.tsx.snap similarity index 100% rename from public/app/core/specs/__snapshots__/ColorPalette.test.tsx.snap rename to packages/grafana-ui/src/components/ColorPicker/__snapshots__/ColorPalette.test.tsx.snap diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index abb1cf1b34c..b2b607415b8 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -2,3 +2,6 @@ export { DeleteButton } from './DeleteButton/DeleteButton'; export { Tooltip } from './Tooltip/Tooltip'; export { Portal } from './Portal/Portal'; export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar'; +export { ColorPicker } from './ColorPicker/ColorPicker'; +export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover'; +export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker'; diff --git a/packages/grafana-ui/src/index.ts b/packages/grafana-ui/src/index.ts index b22152497b9..4072052a07d 100644 --- a/packages/grafana-ui/src/index.ts +++ b/packages/grafana-ui/src/index.ts @@ -2,4 +2,5 @@ export * from './components'; export * from './visualizations'; export * from './types'; export * from './utils'; +export { default } from './utils'; export * from './forms'; diff --git a/packages/grafana-ui/src/utils/colors.ts b/packages/grafana-ui/src/utils/colors.ts new file mode 100644 index 00000000000..673b0109f11 --- /dev/null +++ b/packages/grafana-ui/src/utils/colors.ts @@ -0,0 +1,94 @@ +import _ from 'lodash'; +import tinycolor from 'tinycolor2'; + +export const PALETTE_ROWS = 4; +export const PALETTE_COLUMNS = 14; +export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; +export const OK_COLOR = 'rgba(11, 237, 50, 1)'; +export const ALERTING_COLOR = 'rgba(237, 46, 24, 1)'; +export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; +export const PENDING_COLOR = 'rgba(247, 149, 32, 1)'; +export const REGION_FILL_ALPHA = 0.09; + +const colors = [ + '#7EB26D', // 0: pale green + '#EAB839', // 1: mustard + '#6ED0E0', // 2: light blue + '#EF843C', // 3: orange + '#E24D42', // 4: red + '#1F78C1', // 5: ocean + '#BA43A9', // 6: purple + '#705DA0', // 7: violet + '#508642', // 8: dark green + '#CCA300', // 9: dark sand + '#447EBC', + '#C15C17', + '#890F02', + '#0A437C', + '#6D1F62', + '#584477', + '#B7DBAB', + '#F4D598', + '#70DBED', + '#F9BA8F', + '#F29191', + '#82B5D8', + '#E5A8E2', + '#AEA2E0', + '#629E51', + '#E5AC0E', + '#64B0C8', + '#E0752D', + '#BF1B00', + '#0A50A1', + '#962D82', + '#614D93', + '#9AC48A', + '#F2C96D', + '#65C5DB', + '#F9934E', + '#EA6460', + '#5195CE', + '#D683CE', + '#806EB7', + '#3F6833', + '#967302', + '#2F575E', + '#99440A', + '#58140C', + '#052B51', + '#511749', + '#3F2B5B', + '#E0F9D7', + '#FCEACA', + '#CFFAFF', + '#F9E2D2', + '#FCE2DE', + '#BADFF4', + '#F9D9F9', + '#DEDAF7', +]; + +function sortColorsByHue(hexColors: string[]) { + const hslColors = _.map(hexColors, hexToHsl); + + let sortedHSLColors = _.sortBy(hslColors, ['h']); + sortedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); + sortedHSLColors = _.map(sortedHSLColors, chunk => { + return _.sortBy(chunk, 'l'); + }); + sortedHSLColors = _.flattenDeep(_.zip(...sortedHSLColors)); + + return _.map(sortedHSLColors, hslToHex); +} + +function hexToHsl(color: string) { + return tinycolor(color).toHsl(); +} + +function hslToHex(color: string) { + return tinycolor(color).toHexString(); +} + +export let sortedColors = sortColorsByHue(colors); +export default colors; diff --git a/packages/grafana-ui/src/utils/index.ts b/packages/grafana-ui/src/utils/index.ts index 4d9b9a4b948..1a677b1f033 100644 --- a/packages/grafana-ui/src/utils/index.ts +++ b/packages/grafana-ui/src/utils/index.ts @@ -1 +1,3 @@ export * from './processTimeSeries'; +export * from './colors'; +export { default } from './colors'; diff --git a/public/app/core/angular_wrappers.ts b/public/app/core/angular_wrappers.ts index 5609c058a27..d6fc68293c3 100644 --- a/public/app/core/angular_wrappers.ts +++ b/public/app/core/angular_wrappers.ts @@ -6,6 +6,7 @@ import { SearchResult } from './components/search/SearchResult'; import { TagFilter } from './components/TagFilter/TagFilter'; import { SideMenu } from './components/sidemenu/SideMenu'; import AppNotificationList from './components/AppNotifications/AppNotificationList'; +import { ColorPicker, SeriesColorPickerPopover } from '@grafana/ui'; export function registerAngularDirectives() { react2AngularDirective('passwordStrength', PasswordStrength, ['password']); @@ -19,4 +20,13 @@ export function registerAngularDirectives() { ['onChange', { watchDepth: 'reference' }], ['tagOptions', { watchDepth: 'reference' }], ]); + react2AngularDirective('colorPicker', ColorPicker, [ + 'color', + ['onChange', { watchDepth: 'reference', wrapApply: true }], + ]); + react2AngularDirective('seriesColorPickerPopover', SeriesColorPickerPopover, [ + 'series', + 'onColorChange', + 'onToggleAxis', + ]); } diff --git a/public/app/core/core.ts b/public/app/core/core.ts index 257a2077c97..19e9a473e35 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -13,8 +13,6 @@ import './partials'; import './components/jsontree/jsontree'; import './components/code_editor/code_editor'; import './utils/outline'; -import './components/colorpicker/ColorPicker'; -import './components/colorpicker/SeriesColorPickerPopover'; import './components/colorpicker/spectrum_picker'; import './services/search_srv'; import './services/ng_react'; @@ -36,7 +34,7 @@ import 'app/core/services/all'; import './filters/filters'; import coreModule from './core_module'; import appEvents from './app_events'; -import colors from './utils/colors'; +import colors from '@grafana/ui/'; import { assignModelProperties } from './utils/model_utils'; import { contextSrv } from './services/context_srv'; import { KeybindingSrv } from './services/keybindingSrv'; diff --git a/public/app/core/logs_model.ts b/public/app/core/logs_model.ts index 4e8c6207959..8eb8433cd53 100644 --- a/public/app/core/logs_model.ts +++ b/public/app/core/logs_model.ts @@ -1,6 +1,8 @@ import _ from 'lodash'; +import colors from '@grafana/ui'; + import { TimeSeries } from 'app/core/core'; -import colors, { getThemeColor } from 'app/core/utils/colors'; +import { getThemeColor } from 'app/core/utils/colors'; /** * Mapping of log level abbreviation to canonical log level. diff --git a/public/app/core/utils/colors.ts b/public/app/core/utils/colors.ts index 34508e94a9f..6d73ab9fbd8 100644 --- a/public/app/core/utils/colors.ts +++ b/public/app/core/utils/colors.ts @@ -1,99 +1,5 @@ -import _ from 'lodash'; -import tinycolor from 'tinycolor2'; import config from 'app/core/config'; -export const PALETTE_ROWS = 4; -export const PALETTE_COLUMNS = 14; -export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; -export const OK_COLOR = 'rgba(11, 237, 50, 1)'; -export const ALERTING_COLOR = 'rgba(237, 46, 24, 1)'; -export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; -export const PENDING_COLOR = 'rgba(247, 149, 32, 1)'; -export const REGION_FILL_ALPHA = 0.09; - -const colors = [ - '#7EB26D', // 0: pale green - '#EAB839', // 1: mustard - '#6ED0E0', // 2: light blue - '#EF843C', // 3: orange - '#E24D42', // 4: red - '#1F78C1', // 5: ocean - '#BA43A9', // 6: purple - '#705DA0', // 7: violet - '#508642', // 8: dark green - '#CCA300', // 9: dark sand - '#447EBC', - '#C15C17', - '#890F02', - '#0A437C', - '#6D1F62', - '#584477', - '#B7DBAB', - '#F4D598', - '#70DBED', - '#F9BA8F', - '#F29191', - '#82B5D8', - '#E5A8E2', - '#AEA2E0', - '#629E51', - '#E5AC0E', - '#64B0C8', - '#E0752D', - '#BF1B00', - '#0A50A1', - '#962D82', - '#614D93', - '#9AC48A', - '#F2C96D', - '#65C5DB', - '#F9934E', - '#EA6460', - '#5195CE', - '#D683CE', - '#806EB7', - '#3F6833', - '#967302', - '#2F575E', - '#99440A', - '#58140C', - '#052B51', - '#511749', - '#3F2B5B', - '#E0F9D7', - '#FCEACA', - '#CFFAFF', - '#F9E2D2', - '#FCE2DE', - '#BADFF4', - '#F9D9F9', - '#DEDAF7', -]; - -export function sortColorsByHue(hexColors) { - const hslColors = _.map(hexColors, hexToHsl); - - let sortedHSLColors = _.sortBy(hslColors, ['h']); - sortedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); - sortedHSLColors = _.map(sortedHSLColors, chunk => { - return _.sortBy(chunk, 'l'); - }); - sortedHSLColors = _.flattenDeep(_.zip(...sortedHSLColors)); - - return _.map(sortedHSLColors, hslToHex); -} - -export function hexToHsl(color) { - return tinycolor(color).toHsl(); -} - -export function hslToHex(color) { - return tinycolor(color).toHexString(); -} - export function getThemeColor(dark: string, light: string): string { return config.bootData.user.lightTheme ? light : dark; } - -export let sortedColors = sortColorsByHue(colors); -export default colors; diff --git a/public/app/core/utils/explore.ts b/public/app/core/utils/explore.ts index bea166075dc..2cca33620b7 100644 --- a/public/app/core/utils/explore.ts +++ b/public/app/core/utils/explore.ts @@ -1,9 +1,9 @@ import _ from 'lodash'; +import colors from '@grafana/ui'; import { renderUrl } from 'app/core/utils/url'; import kbn from 'app/core/utils/kbn'; import store from 'app/core/store'; -import colors from 'app/core/utils/colors'; import { parse as parseDate } from 'app/core/utils/datemath'; import TimeSeries from 'app/core/time_series2'; diff --git a/public/app/features/annotations/event_manager.ts b/public/app/features/annotations/event_manager.ts index db748e639a1..6966d3cdc82 100644 --- a/public/app/features/annotations/event_manager.ts +++ b/public/app/features/annotations/event_manager.ts @@ -1,8 +1,6 @@ import _ from 'lodash'; import moment from 'moment'; import tinycolor from 'tinycolor2'; -import { MetricsPanelCtrl } from 'app/plugins/sdk'; -import { AnnotationEvent } from './event'; import { OK_COLOR, ALERTING_COLOR, @@ -10,7 +8,10 @@ import { PENDING_COLOR, DEFAULT_ANNOTATION_COLOR, REGION_FILL_ALPHA, -} from 'app/core/utils/colors'; +} from '@grafana/ui'; + +import { MetricsPanelCtrl } from 'app/plugins/sdk'; +import { AnnotationEvent } from './event'; export class EventManager { event: AnnotationEvent; diff --git a/public/app/features/dashboard/dashboard_model.ts b/public/app/features/dashboard/dashboard_model.ts index 6f98bc5a17a..747ea9fecaa 100644 --- a/public/app/features/dashboard/dashboard_model.ts +++ b/public/app/features/dashboard/dashboard_model.ts @@ -1,8 +1,8 @@ import moment from 'moment'; import _ from 'lodash'; +import { DEFAULT_ANNOTATION_COLOR } from '@grafana/ui'; import { GRID_COLUMN_COUNT, REPEAT_DIR_VERTICAL, GRID_CELL_HEIGHT, GRID_CELL_VMARGIN } from 'app/core/constants'; -import { DEFAULT_ANNOTATION_COLOR } from 'app/core/utils/colors'; import { Emitter } from 'app/core/utils/emitter'; import { contextSrv } from 'app/core/services/context_srv'; import sortByKeys from 'app/core/utils/sort_by_keys'; diff --git a/public/app/plugins/panel/gauge/Thresholds.tsx b/public/app/plugins/panel/gauge/Thresholds.tsx index b4d4930e11d..7699a499146 100644 --- a/public/app/plugins/panel/gauge/Thresholds.tsx +++ b/public/app/plugins/panel/gauge/Thresholds.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import tinycolor from 'tinycolor2'; -import { ColorPicker } from 'app/core/components/colorpicker/ColorPicker'; +import { ColorPicker } from '@grafana/ui'; import { BasicGaugeColor, Threshold } from 'app/types'; import { PanelOptionsProps } from '@grafana/ui'; import { Options } from './types'; diff --git a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx index 2105687d8e1..d6df17d9699 100644 --- a/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx +++ b/public/app/plugins/panel/graph/Legend/LegendSeriesItem.tsx @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import classNames from 'classnames'; import { TimeSeries } from 'app/core/core'; -import { SeriesColorPicker } from 'app/core/components/colorpicker/SeriesColorPicker'; +import { SeriesColorPicker } from '@grafana/ui'; export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total']; diff --git a/public/app/plugins/panel/graph/data_processor.ts b/public/app/plugins/panel/graph/data_processor.ts index 4ea1efe1502..ef4ad872753 100644 --- a/public/app/plugins/panel/graph/data_processor.ts +++ b/public/app/plugins/panel/graph/data_processor.ts @@ -1,6 +1,7 @@ import _ from 'lodash'; +import colors from '@grafana/ui'; + import TimeSeries from 'app/core/time_series2'; -import colors from 'app/core/utils/colors'; export class DataProcessor { constructor(private panel) {} diff --git a/public/app/plugins/panel/graph2/GraphPanel.tsx b/public/app/plugins/panel/graph2/GraphPanel.tsx index 020c33f7d38..11be172aaeb 100644 --- a/public/app/plugins/panel/graph2/GraphPanel.tsx +++ b/public/app/plugins/panel/graph2/GraphPanel.tsx @@ -1,7 +1,7 @@ // Libraries import _ from 'lodash'; import React, { PureComponent } from 'react'; -import colors from 'app/core/utils/colors'; +import colors from '@grafana/ui'; // Components & Types import { Graph, PanelProps, NullValueMode, processTimeSeries } from '@grafana/ui'; diff --git a/public/app/routes/GrafanaCtrl.ts b/public/app/routes/GrafanaCtrl.ts index 75a34ac01c0..434a112692e 100644 --- a/public/app/routes/GrafanaCtrl.ts +++ b/public/app/routes/GrafanaCtrl.ts @@ -1,12 +1,12 @@ import config from 'app/core/config'; import _ from 'lodash'; import $ from 'jquery'; +import Drop from 'tether-drop'; +import colors from '@grafana/ui'; import coreModule from 'app/core/core_module'; import { profiler } from 'app/core/profiler'; import appEvents from 'app/core/app_events'; -import Drop from 'tether-drop'; -import colors from 'app/core/utils/colors'; import { BackendSrv, setBackendSrv } from 'app/core/services/backend_srv'; import { TimeSrv, setTimeSrv } from 'app/features/dashboard/time_srv'; import { DatasourceSrv, setDatasourceSrv } from 'app/features/plugins/datasource_srv'; diff --git a/public/app/viz/state/timeSeries.ts b/public/app/viz/state/timeSeries.ts index 782383957bc..2329d6f41af 100644 --- a/public/app/viz/state/timeSeries.ts +++ b/public/app/viz/state/timeSeries.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; // Utils -import colors from 'app/core/utils/colors'; +import colors from '@grafana/ui'; // Types import { TimeSeries, TimeSeriesVMs, NullValueMode } from '@grafana/ui'; From 37dae043d703c9586a9573ae3de1d463d150e4e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 10 Jan 2019 13:38:55 +0100 Subject: [PATCH 15/17] Small change in SeriesColorPickerPopoverProps --- .../src/components/ColorPicker/SeriesColorPicker.tsx | 2 +- .../components/ColorPicker/SeriesColorPickerPopover.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx index b8ba03b7feb..09a53a8fe60 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx @@ -8,7 +8,7 @@ export interface SeriesColorPickerProps { yaxis?: number; optionalClass?: string; onColorChange: (newColor: string) => void; - onToggleAxis: () => void; + onToggleAxis?: () => void; } export class SeriesColorPicker extends React.Component { diff --git a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx index 9036a1a2ffd..541a77ddabc 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPickerPopover.tsx @@ -5,7 +5,7 @@ export interface SeriesColorPickerPopoverProps { color: string; yaxis?: number; onColorChange: (color: string) => void; - onToggleAxis: () => void; + onToggleAxis?: () => void; } export class SeriesColorPickerPopover extends React.PureComponent { @@ -21,7 +21,7 @@ export class SeriesColorPickerPopover extends React.PureComponent void; + onToggleAxis?: () => void; } interface AxisSelectorState { @@ -41,7 +41,10 @@ export class AxisSelector extends React.PureComponent Date: Thu, 10 Jan 2019 16:52:08 +0100 Subject: [PATCH 16/17] Fixed typings --- packages/grafana-ui/package.json | 3 +++ .../components/ColorPicker/ColorPicker.tsx | 3 ++- .../ColorPicker/SeriesColorPicker.tsx | 1 + packages/grafana-ui/src/utils/colors.ts | 12 ++++++------ yarn.lock | 19 ++++++++++++++++++- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 5221e1ba02f..91695dc5647 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -24,6 +24,7 @@ "react-popper": "^1.3.0", "react-transition-group": "^2.2.1", "react-virtualized": "^9.21.0", + "tether": "^1.4.0", "tether-drop": "https://github.com/torkelo/drop/tarball/master", "tinycolor2": "^1.4.1" }, @@ -35,6 +36,8 @@ "@types/react": "^16.7.6", "@types/react-custom-scrollbars": "^4.0.5", "@types/react-test-renderer": "^16.0.3", + "@types/tether-drop": "^1.4.8", + "@types/tinycolor2": "^1.4.1", "react-test-renderer": "^16.7.0", "typescript": "^3.2.2" } diff --git a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx index fbe14d4eb8c..485aa5f03d3 100644 --- a/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/ColorPicker.tsx @@ -19,7 +19,7 @@ export class ColorPicker extends React.Component { ReactDOM.render(dropContent, dropContentElem); const drop = new Drop({ - target: this.pickerElem, + target: this.pickerElem as Element, content: dropContentElem, position: 'top center', classes: 'drop-popover', @@ -27,6 +27,7 @@ export class ColorPicker extends React.Component { hoverCloseDelay: 200, tetherOptions: { constraints: [{ to: 'scrollParent', attachment: 'none both' }], + attachment: 'bottom center', }, }); diff --git a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx index 09a53a8fe60..7c3848f6868 100644 --- a/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx +++ b/packages/grafana-ui/src/components/ColorPicker/SeriesColorPicker.tsx @@ -51,6 +51,7 @@ export class SeriesColorPicker extends React.Component { remove: true, tetherOptions: { constraints: [{ to: 'scrollParent', attachment: 'none both' }], + attachment: 'bottom center', }, }); diff --git a/packages/grafana-ui/src/utils/colors.ts b/packages/grafana-ui/src/utils/colors.ts index 673b0109f11..0b22cd7f81d 100644 --- a/packages/grafana-ui/src/utils/colors.ts +++ b/packages/grafana-ui/src/utils/colors.ts @@ -72,21 +72,21 @@ const colors = [ function sortColorsByHue(hexColors: string[]) { const hslColors = _.map(hexColors, hexToHsl); - let sortedHSLColors = _.sortBy(hslColors, ['h']); - sortedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); - sortedHSLColors = _.map(sortedHSLColors, chunk => { + const sortedHSLColors = _.sortBy(hslColors, ['h']); + const chunkedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); + const sortedChunkedHSLColors = _.map(chunkedHSLColors, chunk => { return _.sortBy(chunk, 'l'); }); - sortedHSLColors = _.flattenDeep(_.zip(...sortedHSLColors)); + const flattenedZippedSortedChunkedHSLColors = _.flattenDeep(_.zip(...sortedChunkedHSLColors)); - return _.map(sortedHSLColors, hslToHex); + return _.map(flattenedZippedSortedChunkedHSLColors, hslToHex); } function hexToHsl(color: string) { return tinycolor(color).toHsl(); } -function hslToHex(color: string) { +function hslToHex(color: any) { return tinycolor(color).toHexString(); } diff --git a/yarn.lock b/yarn.lock index 8eff64ca822..d6342e8dc26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1098,7 +1098,7 @@ dependencies: "@types/react" "*" -"@types/react-transition-group@^2.0.15": +"@types/react-transition-group@*", "@types/react-transition-group@^2.0.15": version "2.0.15" resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-2.0.15.tgz#e5ee3fe558832e141cc6041bdd54caea7b787af8" integrity sha512-S0QnNzbHoWXDbKBl/xk5dxA4FT+BNlBcI3hku991cl8Cz3ytOkUMcCRtzdX11eb86E131bSsQqy5WrPCdJYblw== @@ -1118,6 +1118,23 @@ resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-0.2.5.tgz#2443fc12da514c81346b1a665675559cee21fa75" integrity sha512-dEoVvo/I9QFomyhY+4Q6Qk+I+dhG59TYceZgC6Q0mCifVPErx6Y83PNTKGDS5e9h9Eti6q0S2mm16BU6iQK+3w== +"@types/tether-drop@^1.4.8": + version "1.4.8" + resolved "https://registry.yarnpkg.com/@types/tether-drop/-/tether-drop-1.4.8.tgz#8d64288e673259d1bc28518250b80b5ef43af0bc" + integrity sha512-QzrJDUxnLoqACUm7opxGOwa9mgMBlkyb7hHYWApMLM3ywWif4pWraTiotooiG3ePZmnTe8wQj2nx7GWMX4pb+w== + dependencies: + "@types/tether" "*" + +"@types/tether@*": + version "1.4.4" + resolved "https://registry.yarnpkg.com/@types/tether/-/tether-1.4.4.tgz#0fde1ccbd2f1fad74f8f465fe6227ff3b7bff634" + integrity sha512-6qhsFJVMuMqaQRVyQVi3zUBLfKYyryktL0ZP0Z3zegzeQ7WKm0PZNCdl3JsaitJbzqaoQ9qsFKMfaj5MiMfcSQ== + +"@types/tinycolor2@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.1.tgz#2f5670c9d1d6e558897a810ed284b44918fc1253" + integrity sha512-25L/RL5tqZkquKXVHM1fM2bd23qjfbcPpAZ2N/H05Y45g3UEi+Hw8CbDV28shKY8gH1SHiLpZSxPI1lacqdpGg== + "@types/uglify-js@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.3.tgz#801a5ca1dc642861f47c46d14b700ed2d610840b" From dc9b83030f5ae162b005404abdb9da3d13d7b27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Fri, 11 Jan 2019 06:48:17 +0100 Subject: [PATCH 17/17] Removed default export for colors --- packages/grafana-ui/src/index.ts | 1 - packages/grafana-ui/src/utils/colors.ts | 3 +-- packages/grafana-ui/src/utils/index.ts | 1 - public/app/core/core.ts | 2 +- public/app/core/logs_model.ts | 2 +- public/app/core/utils/explore.ts | 2 +- public/app/plugins/panel/graph/data_processor.ts | 2 +- public/app/plugins/panel/graph2/GraphPanel.tsx | 2 +- public/app/routes/GrafanaCtrl.ts | 2 +- public/app/viz/state/timeSeries.ts | 2 +- 10 files changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/grafana-ui/src/index.ts b/packages/grafana-ui/src/index.ts index 4072052a07d..b22152497b9 100644 --- a/packages/grafana-ui/src/index.ts +++ b/packages/grafana-ui/src/index.ts @@ -2,5 +2,4 @@ export * from './components'; export * from './visualizations'; export * from './types'; export * from './utils'; -export { default } from './utils'; export * from './forms'; diff --git a/packages/grafana-ui/src/utils/colors.ts b/packages/grafana-ui/src/utils/colors.ts index 0b22cd7f81d..263d128aec4 100644 --- a/packages/grafana-ui/src/utils/colors.ts +++ b/packages/grafana-ui/src/utils/colors.ts @@ -10,7 +10,7 @@ export const NO_DATA_COLOR = 'rgba(150, 150, 150, 1)'; export const PENDING_COLOR = 'rgba(247, 149, 32, 1)'; export const REGION_FILL_ALPHA = 0.09; -const colors = [ +export const colors = [ '#7EB26D', // 0: pale green '#EAB839', // 1: mustard '#6ED0E0', // 2: light blue @@ -91,4 +91,3 @@ function hslToHex(color: any) { } export let sortedColors = sortColorsByHue(colors); -export default colors; diff --git a/packages/grafana-ui/src/utils/index.ts b/packages/grafana-ui/src/utils/index.ts index 1a677b1f033..eb67a6f7256 100644 --- a/packages/grafana-ui/src/utils/index.ts +++ b/packages/grafana-ui/src/utils/index.ts @@ -1,3 +1,2 @@ export * from './processTimeSeries'; export * from './colors'; -export { default } from './colors'; diff --git a/public/app/core/core.ts b/public/app/core/core.ts index 19e9a473e35..6713d8bcd14 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -16,6 +16,7 @@ import './utils/outline'; import './components/colorpicker/spectrum_picker'; import './services/search_srv'; import './services/ng_react'; +import { colors } from '@grafana/ui/'; import { searchDirective } from './components/search/search'; import { infoPopover } from './components/info_popover'; @@ -34,7 +35,6 @@ import 'app/core/services/all'; import './filters/filters'; import coreModule from './core_module'; import appEvents from './app_events'; -import colors from '@grafana/ui/'; import { assignModelProperties } from './utils/model_utils'; import { contextSrv } from './services/context_srv'; import { KeybindingSrv } from './services/keybindingSrv'; diff --git a/public/app/core/logs_model.ts b/public/app/core/logs_model.ts index 8eb8433cd53..4cf9a029a2a 100644 --- a/public/app/core/logs_model.ts +++ b/public/app/core/logs_model.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; import { TimeSeries } from 'app/core/core'; import { getThemeColor } from 'app/core/utils/colors'; diff --git a/public/app/core/utils/explore.ts b/public/app/core/utils/explore.ts index 2cca33620b7..f3273ffa16d 100644 --- a/public/app/core/utils/explore.ts +++ b/public/app/core/utils/explore.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; import { renderUrl } from 'app/core/utils/url'; import kbn from 'app/core/utils/kbn'; diff --git a/public/app/plugins/panel/graph/data_processor.ts b/public/app/plugins/panel/graph/data_processor.ts index ef4ad872753..4fe47b70129 100644 --- a/public/app/plugins/panel/graph/data_processor.ts +++ b/public/app/plugins/panel/graph/data_processor.ts @@ -1,5 +1,5 @@ import _ from 'lodash'; -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; import TimeSeries from 'app/core/time_series2'; diff --git a/public/app/plugins/panel/graph2/GraphPanel.tsx b/public/app/plugins/panel/graph2/GraphPanel.tsx index 11be172aaeb..4a3daf77333 100644 --- a/public/app/plugins/panel/graph2/GraphPanel.tsx +++ b/public/app/plugins/panel/graph2/GraphPanel.tsx @@ -1,7 +1,7 @@ // Libraries import _ from 'lodash'; import React, { PureComponent } from 'react'; -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; // Components & Types import { Graph, PanelProps, NullValueMode, processTimeSeries } from '@grafana/ui'; diff --git a/public/app/routes/GrafanaCtrl.ts b/public/app/routes/GrafanaCtrl.ts index 434a112692e..4e4dd8121cf 100644 --- a/public/app/routes/GrafanaCtrl.ts +++ b/public/app/routes/GrafanaCtrl.ts @@ -2,7 +2,7 @@ import config from 'app/core/config'; import _ from 'lodash'; import $ from 'jquery'; import Drop from 'tether-drop'; -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; import coreModule from 'app/core/core_module'; import { profiler } from 'app/core/profiler'; diff --git a/public/app/viz/state/timeSeries.ts b/public/app/viz/state/timeSeries.ts index 2329d6f41af..5f27974a33b 100644 --- a/public/app/viz/state/timeSeries.ts +++ b/public/app/viz/state/timeSeries.ts @@ -2,7 +2,7 @@ import _ from 'lodash'; // Utils -import colors from '@grafana/ui'; +import { colors } from '@grafana/ui'; // Types import { TimeSeries, TimeSeriesVMs, NullValueMode } from '@grafana/ui';