Compare commits

...

104 Commits

Author SHA1 Message Date
Grot (@grafanabot)
a2306d2765 "Release: Updated versions in package to 8.2.0-beta.2" (#39831) 2021-09-30 10:49:00 +02:00
Grot (@grafanabot)
229c45ccda Add fiscal years and search to time picker (#39073) (#39828)
* Add search to time picker

* implement fiscal datemath

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
(cherry picked from commit 738d5e499e)

Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
2021-09-30 10:07:24 +02:00
Grot (@grafanabot)
1126ea6539 Graphite: Ensure only valid queries are used for interpolation (#39761) (#39827)
* Graphite: Ensure only valid queries are used for interpolation

* Add a unit test

(cherry picked from commit 787e5e78dd)

Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
2021-09-30 10:00:06 +02:00
Grot (@grafanabot)
06015fbdaf Explore: Fix displaying rich history saving error message (#39766) (#39826)
* Explore: Fix displaying rich history saving error message

* Keep generic error message

* remove testing snippet

(cherry picked from commit f8ebcaa0d9)

Co-authored-by: Piotr Jamróz <pm.jamroz@gmail.com>
2021-09-30 09:52:18 +02:00
Grot (@grafanabot)
dc363a05ac A11y: Fixes some fastpass errors for /datasources/* routes (#39577) (#39797)
* A11y: Fixes some fastpass errors for /datasources/* routes
See #39429

(cherry picked from commit 75a55379f1)

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2021-09-30 09:24:26 +02:00
Grot (@grafanabot)
70a4fd8a21 Plugins Catalog: Make the catalog the default way to interact with plugins (#39779) (#39822)
* chore(Plugins/Admin): make the Plugins Catalog the default way to interact with plugins

* chore(defaults.ini): change the default value for `plugin_admin_enabled`

* test(Plugins): make the tests pass

(cherry picked from commit c2754eb9cc)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
2021-09-30 09:05:55 +02:00
Torkel Ödegaard
91db8910a7 Chore: Tidy up emotion css with better theme breakpoint (#39340) (#39811)
(cherry picked from commit f3475b864c)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-29 20:41:02 +02:00
Grot (@grafanabot)
e69544b6ea Scatter: support bubble and line charts with out-of-order data (alpha) (#39377) (#39809)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
(cherry picked from commit 4c8c2f6c96)

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2021-09-29 19:42:50 +02:00
Grot (@grafanabot)
c6fb06721f DashboardRow: Prevent unintended editing of DashboardRow with keyboard shortcut 'e' (#39792) (#39803)
(cherry picked from commit ff009bee9f)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-29 18:11:20 +02:00
Grot (@grafanabot)
900c94fd8a Admin: Show licensed roles and unit membership in UI (#39773) (#39802)
* Extend User type

* Render licensed roles and org units

* Combine admin icon with units

* Extract search users to a new service

* Fix wire provider

* remove mock data

* Fix icon margin

* Fix common_test and remove RouteRegister

* Remove old endpoints

* Fix test

* Add indexes to dashboards and orgs tables

* Fix lint

* Revert docs changes

* undo docs formatting

* Change order of input and filters

* Abstract aria-label into a function

* Add accessible info about user's membership

* UI tweaks

Co-authored-by: spinillos <selenepinillos@gmail.com>
(cherry picked from commit 62dc10829a)

Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
2021-09-29 18:00:15 +02:00
Grot (@grafanabot)
d6b00710cb PluginsCatalog: Add support for viewing the plugins list as both table and list (#39466) (#39798)
* working version but with duplications.

* refactor(Plugins/Admin): use "fr" instead of "repeat" for grid columns

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>

* fix(Plugins/Admin): use PluginIconName instead of IconName

* refactor(Plugins/Admin): store the display-mode on the state

* refactor(Plugins/Admin): use && for conditional rendering

* refactor(Plugins/Admin): rename variable

* refactor(Plugins/Admin): share code between card and row components

* test(PluginListItemRow): add tests

* test(Plugins/Admin): add a simple test for the display-mode switching

* fix(Plugins/Admin): compose styles with css``

* refactor(Plugins/Admin): rename "table" to "grid" for display modes

* test(Plugins/Browse): follow up on renaming "table" to "grid"

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
(cherry picked from commit 2dedbcd3c3)

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
2021-09-29 17:56:43 +02:00
Grot (@grafanabot)
4fe38b169c Docs: Add docs for Redis cluster caching backend configuration (#39687) (#39800)
* caching: add docs for redis cluster config

* address PR comments

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>

Co-authored-by: Ursula Kallio <73951760+osg-grafana@users.noreply.github.com>
(cherry picked from commit 9f1de095b7)

Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com>
2021-09-29 17:56:19 +02:00
Grot (@grafanabot)
bd12923c59 E2E: improvements to the importDashboard flow (#39693) (#39790)
* E2E: improvements to the importDashboard flow

(cherry picked from commit aeeaa67b0a)

Co-authored-by: Sarah Zinger <sarahzinger@users.noreply.github.com>
2021-09-29 11:53:32 -04:00
Grot (@grafanabot)
9570495af5 A11y: Fix fastpass issues for /explore page (#39507) (#39796)
* Fix(A11y): add label to explore short url button

* Grafana-UI(A11y): Set Selects images alt attribute to their option label

* Update packages/grafana-ui/src/components/Select/SingleValue.tsx

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
(cherry picked from commit f61c8d3eed)

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2021-09-29 17:46:03 +02:00
Sofia Papagiannaki
368742ab04 Alerting: Remove ngalert feature toggle and introduce two new settings for enabling Grafana 8 alerts and disabling them for specific organisations (#38746) (#39793)
* Remove `ngalert` feature toggle

* Update frontend

Remove all references of ngalert feature toggle

* Update docs

* Disable unified alerting for specific orgs

* Add backend tests

* Apply suggestions from code review

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>

* Disabled unified alerting by default

* Ensure backward compatibility with old ngalert feature toggle

* Apply suggestions from code review

Co-authored-by: gotjosh <josue@grafana.com>
(cherry picked from commit 012d4f0905)
2021-09-29 11:21:25 -04:00
Selene
d07ed05918 Extract search users functions into a service (#39002) (#39770)
* Extract search users to a new service

* Fix wire provider

* Fix common_test and remove RouteRegister

* Remove old endpoints

* Fix test

* Add indexes to dashboards and orgs tables

* Fix lint

(cherry picked from commit 02702eb82d)
2021-09-29 17:02:58 +02:00
Grot (@grafanabot)
4699620e23 Plugin Catalog: support Grafana instances that cannot communicate with gcom (#39638) (#39787)
* added possibility to track if remote plugins could be fetched.

* adding hook to detect if remote plugins are available.

* feat(catalog): disable installed/all filter if remote plugins are unavailable

* feat(Plugins/Admin): hide the install controls if GCOM is not available

* refactor(Plugins/Admin): group `@grafana` dependencies

* fix(Plugins/Admin): don't show an error alert if a remote plugin is not available

* feat(Plugins/Admin): prefer to use the local version of the readme

* chore(Plugins/Admin): type the mocked state properly

* test(Plugins/Admin): add tests for the Plugin Details when GCOM is not available

* test(Plugins/Admin): add tests for the Browse when GCOM is not available

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
(cherry picked from commit fffcee7c1f)

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
2021-09-29 16:44:57 +02:00
Grot (@grafanabot)
09461d03ea Update migration to not delete existing Grafana alerts (#39541) (#39736)
* keep existing unified alert rules untouched
* move silences and other alertmanager files to the organization directory (only if it is a single organization deployment)
* assign the existing notification settings and routes to the first organization
* create default notification settings for each organization in the case of multi org deployment

(cherry picked from commit 5d0d7dcb3a)

Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
2021-09-29 09:27:44 -04:00
Grot (@grafanabot)
c7e9b1685c OrgPage: Minor typo fix (#39764) (#39777)
(cherry picked from commit 630a120a15)

Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
2021-09-29 14:37:20 +02:00
Grot (@grafanabot)
20212aaf97 BarGauge: Improve behaviour when working with streaming data (#39737) (#39765)
* BarGauge: Improve behaviour when working with streaming data

* BarGauge: Refactor default min/max into grafana/data

(cherry picked from commit 2058193e98)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-29 11:39:55 +02:00
Grot (@grafanabot)
832321b405 add support for interaction events (#39752) (#39762)
(cherry picked from commit db8c9122aa)

Co-authored-by: Erik Sundell <erik.sundell@grafana.com>
2021-09-29 11:28:15 +02:00
Grot (@grafanabot)
f4bd6d4f84 Docs: alerting fixes (#39717) (#39730)
* Docs: alerting fixes

(cherry picked from commit eead8cd8e1)

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
2021-09-29 12:22:06 +03:00
Grot (@grafanabot)
805cbba81d TimeSeries: Fix shared cursor (#39738) (#39760)
(cherry picked from commit 4682cf5b7c)

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
2021-09-29 10:58:14 +02:00
Grot (@grafanabot)
f793c0d2fc Table panel: Make filter case insensitive (#39746) (#39757)
* Expose FilterInput from grafana/ui

* Make table filter case insensitive

* Update packages/grafana-ui/src/components/Table/FilterList.tsx

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>

Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
(cherry picked from commit f887576a27)

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
2021-09-29 10:05:50 +02:00
Grot (@grafanabot)
b82bc90180 Hooks: Adding possibility to display banner on the top of the page (#39099) (#39755)
* adding working version of notificaion banner trigger.

* Move it to enterprise

* Fixing csss, none of the pages showed our CustomScrollbar or had double scrollbars

* fixing explore

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
(cherry picked from commit b626ba223f)

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
2021-09-29 08:29:45 +02:00
Grot (@grafanabot)
b37d4152d8 AzureMonitor: move metric deep link code to backend (#39524) (#39727)
(cherry picked from commit bf9be975ac)

Co-authored-by: Isabella Siu <sakurablossom@blueblueworld.com>
2021-09-28 14:31:47 -04:00
Grot (@grafanabot)
2cd112b9da Alerting: Add filtering for Silences (#39109) (#39452)
* Add filtering for Silences page

* Add tests Silences and SilenceEditor

* pr feedback: add field validation and test refactor

* Add test for checking content

* fix overflow for validation error message

* increase login threshold for pa11y

* Make silence filter state its own type and function

(cherry picked from commit d03f75726b)

Co-authored-by: Nathan Rodman <nathanrodman@gmail.com>
2021-09-28 10:35:27 -07:00
Grot (@grafanabot)
e426039d6c Tempo: Improve search form defaults and validation (#39534) (#39749)
* Tempo: add default limit, option to hide Loki search, and run query on hotkey in dropdowns

(cherry picked from commit 06592410b2)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 11:20:49 -06:00
Grot (@grafanabot)
f28d869db2 Tempo: Show warning if search is not available. Add opt-out config (#39489) (#39747)
* Tempo: Show warning if search is not available. Add opt-out config

(cherry picked from commit 24479ff6b0)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 10:52:14 -06:00
Grot (@grafanabot)
618a590a05 Tempo: Improve how Tempo Search fetches autocomplete values (#39371) (#39745)
* Improve how tempo search fetches autocomplete values

* Refetch autocomplete options on menu load

(cherry picked from commit 1865689411)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 10:20:43 -06:00
Grot (@grafanabot)
ce5fe730b8 Tempo: Format tempo search query history text (#39250) (#39743)
* Format tempo search query history text

(cherry picked from commit c57ff8beed)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 10:13:15 -06:00
Grot (@grafanabot)
6648f8c5a1 Tempo: Run search query with keyboard shortcut from input fields (#39247) (#39741)
* Tempo: Run query with keyboard shortcut from duration fields

(cherry picked from commit 9c4e7eb659)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 09:50:05 -06:00
Grot (@grafanabot)
d38782bc94 grafana-ui: Improve PartialHighlighter error handling (#39685) (#39739)
* Improve PartialHighlighter error handling

(cherry picked from commit 05bb451a1d)

Co-authored-by: Connor Lindsey <cblindsey3@gmail.com>
2021-09-28 09:45:15 -06:00
Grot (@grafanabot)
2e86425ed9 Alerting: Move alertmanager default config to UnifiedAlertingSettings (#39597) (#39714)
(cherry picked from commit 05eb30e323)

Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
Co-authored-by: Sofia Papagiannaki <sofia@grafana.com>
2021-09-28 11:01:18 -04:00
Grot (@grafanabot)
5aaef25a33 Alerting: Optimization of fetching data in multiorg alertmanager (#39237) (#39720)
* Add method GetAllLatestAlertmanagerConfiguration to DBStore
* add method ApplyConfig to AlertManager
* update multiorg alert manager to load all alertmanager configs at once

(cherry picked from commit 1910d85ae0)

Co-authored-by: Yuriy Tseretyan <yuriy.tseretyan@grafana.com>
2021-09-28 09:05:22 -04:00
Grot (@grafanabot)
35dad9c267 Provide reader to alertmanager silence instead of file path (#39305) (#39721)
(cherry picked from commit e1aae0549e)

Co-authored-by: Yuriy Tseretyan <tceretian@gmail.com>
2021-09-28 09:04:22 -04:00
Grot (@grafanabot)
c2d95d4d01 Alerting: Prevent preview if no condition is set (#39659) (#39706)
* prevent preview if no condition is set

* fixes after pr feedback

* watch on type and condition

(cherry picked from commit cc94c55e48)

Co-authored-by: Peter Holmberg <peterholmberg@users.noreply.github.com>
2021-09-28 14:24:19 +02:00
Sofia Papagiannaki
c89e1236fe Alerting: tune rule evaluation via configuration (#35623) (#39712)
* Alerting: Configure max evaluation retries

* Alerting: Enforce minimum rule evaluation interval

* Alerting: Disable rule evaluation from configuration

* Update docs

* Alerting: Configure rule evaluation timeout

* Move options on unified_alerting config section

* Apply suggestions from code review

Co-authored-by: gotjosh <josue@grafana.com>
(cherry picked from commit f6f3a54742)
2021-09-28 14:58:31 +03:00
Grot (@grafanabot)
3d76c772be Plugin Catalog: Use routing for PluginDetails Tabs (#39555) (#39680)
* feat(catalog): introduce id and href to PluginDetailsTabs

* feat(catalog): add hrefs and ids to PluginDetails tabs. Pass queryParams to PluginDetailsBody

* feat(catalog): pass queryParams to PluginsDetailsBody and add page param to PluginListCard

* fix(catalog): prevent flicker of content by waiting for fetch details to finish loading

* feat(catalog): add tab icons to PluginDetails page

* feat(catalog): make breadcrumbs in PluginDetailsHeader aware of page queryparam

* fix(catalog): fix deeplinking to PluginDetails by comparing tabs length

* test(catalog): update tests with correct props and wrap in router

(cherry picked from commit 4dc556445c)

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
2021-09-28 12:00:49 +02:00
Grot (@grafanabot)
1feb7ce022 Plugins Catalog: Remove notice asking user to refresh browser (#39592) (#39681)
(cherry picked from commit 6eceb69d43)

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
2021-09-28 12:00:00 +02:00
Grot (@grafanabot)
2089b58def Loki: Fix creating coontext query for logs with parsed labels (#39648) (#39705)
(cherry picked from commit 79c797c232)

Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
2021-09-28 11:14:49 +02:00
Grot (@grafanabot)
f3479aad2b Add orientation prop to Gauge panel (#39682) (#39698)
(cherry picked from commit 0bb426ec33)

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
2021-09-28 09:51:14 +02:00
Grot (@grafanabot)
6c92beb7fe Variables: Prevents enter key from refreshing page or changing focus (#39666) (#39697)
(cherry picked from commit 9a178e7ba9)

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
2021-09-28 06:41:28 +02:00
Grot (@grafanabot)
06cb288848 Alerting: Move spammy log line to debug in the state manager (#39410) (#39434)
(cherry picked from commit fcbcfd232b)

Co-authored-by: gotjosh <josue@grafana.com>
2021-09-27 15:36:52 +01:00
Grot (@grafanabot)
cac03cc7fe Elasticsearch/Prometheus: Set correct service namespace for SigV4 (#39439) (#39652)
Makes sure to set the SigV4 service namespace for Elasticsearch and Prometheus.

Fixes #38440

(cherry picked from commit 45a844e77e)

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
2021-09-27 15:18:35 +02:00
Grot (@grafanabot)
ea57ae7470 Update lockfile to correct output after running yarn install (#39646) (#39651)
* Update lockfile to correct output after running `yarn install`

* Chore: Remove caniuse-db since nothing is using it anymore

(cherry picked from commit bbf64722e4)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-27 15:13:41 +02:00
Grot (@grafanabot)
bbfb211408 Plugins Catalog: update the available panels on install/uninstall (#39293) (#39405)
* feat(Plugins/Admin): add a function to update panels

* fix(Plugins/Admin): update the available panels on plugin install / uninstall

(cherry picked from commit c8e94a2443)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
2021-09-27 13:50:56 +02:00
Grot (@grafanabot)
07de5e5a5d Bump tmpl from 1.0.4 to 1.0.5 (#39475) (#39644)
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 057c9a4fe1)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 13:10:02 +02:00
Grot (@grafanabot)
7d9308113a Bump prismjs from 1.24.0 to 1.25.0 (#39450) (#39645)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.24.0 to 1.25.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.24.0...v1.25.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 0e60abfe00)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-09-27 13:09:31 +02:00
Grot (@grafanabot)
5ce3c48c8c InfluxDB: Flux: make $__interval and $__interval_ms work in alerting (#38889) (#39642)
* influxdb: flux: handle $__interval and $__interval_ms in alert-queries

* influxdb: flux: do not handle interval-variable in the frontend

* $__interval should be rounded

* added comment

(cherry picked from commit 9f027e32b7)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-27 12:32:54 +02:00
Grot (@grafanabot)
e90558d3b3 Fix: State timeline panel tooltip error when data is not in sync (#39438) (#39634)
* Fix: State timeline panel tooltip error when data is not in sync

* Move check from tooltip to panel

(cherry picked from commit 24475cfdda)

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
2021-09-27 10:15:27 +02:00
Grot (@grafanabot)
e7ca31214b Live: disable centrifuge-js debug mode (#39625) (#39626)
(cherry picked from commit 1d1da09568)

Co-authored-by: Alexander Emelin <frvzmb@gmail.com>
2021-09-26 20:48:56 -07:00
Grot (@grafanabot)
fee11227da PanelOptions: fix array with siblings (#39620) (#39623)
(cherry picked from commit c9ae46a9ad)

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2021-09-25 17:58:09 +02:00
Grot (@grafanabot)
258f3eae32 Options: support array value paths for panel options (#39499) (#39596)
(cherry picked from commit 01deae2105)

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2021-09-23 10:58:14 -07:00
Grot (@grafanabot)
ac1ca2e4b5 Update PageToolbar.tsx (#39572) (#39585)
(cherry picked from commit 0229146c3b)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-23 16:02:47 +02:00
Grot (@grafanabot)
1fc22f6e4d BarGauge: Set cell color to off if numeric value is NaN (#39574) (#39580)
* BarGauge: Set cell color to off if numeric value is NaN

* BarGauge: Pull getCellColor out into a pure function and add unit tests

(cherry picked from commit 6948dbe550)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-23 14:59:52 +02:00
Oscar Kilhed
fa6c44b12a Remove ? as header for piechart table legend (#39521) (#39571)
(cherry picked from commit 71122930b9)
2021-09-23 14:21:31 +02:00
Grot (@grafanabot)
53a11de774 Cleanup kv_store alertmanager namespace when disabling unified alerting (#39554) (#39576)
(cherry picked from commit ba4242bdb9)

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
2021-09-23 13:53:51 +02:00
Grot (@grafanabot)
4ffa29d959 Fix alerts with evaluation interval more than 30 seconds resolving in Alertmanager (#39513) (#39523)
(cherry picked from commit 27609dc2c5)

Co-authored-by: George Robinson <george.robinson@grafana.com>
2021-09-23 13:06:27 +02:00
Grot (@grafanabot)
22563454b7 Variables: Prevents panel from crashing when using adhoc variable in data links (#39546) (#39568)
* Variables: Prevents panel from crashing when using adhoc variable in data links

* Refactor: uses isAdhoc instead

* Chore: updates after PR feedback

(cherry picked from commit af5296bee7)

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
2021-09-23 12:24:24 +02:00
Grot (@grafanabot)
345fb89699 Dashboard: Short url generation works for variables values with spaces (#39552) (#39567)
(cherry picked from commit 65d79d9a30)

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
2021-09-23 12:20:47 +02:00
Grot (@grafanabot)
5bf35bd49e influxdb: flux: use more precise start and end timestamps (#39415) (#39520)
* influxdb: flux: use more precise start and end timestamps

* added unit test

(cherry picked from commit bf0dc3ef62)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-23 12:13:55 +02:00
Grot (@grafanabot)
aa2dbd63f3 PieChart: Filter NaN values from total calculation (#39503) (#39509)
* Filter NaN values from total calculation

* remove duplicated code, use missing value string for NaN and hidden series

(cherry picked from commit a1d8d6e95e)

Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
2021-09-23 12:00:36 +02:00
Grot (@grafanabot)
4d1969c9c4 Alerting: fix the migrated silence file content (#39557) (#39564)
(cherry picked from commit 81e82ebbbd)

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
2021-09-23 11:49:22 +02:00
Grot (@grafanabot)
5003b911e2 VersionHistory: Remove global scss causing conflicts elsewhere (#39437) (#39560)
(cherry picked from commit 4aed940738)

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2021-09-23 11:24:55 +02:00
Grot (@grafanabot)
ef7a2bda39 PieChart: Fix sorting for null values in piechart (#39516) (#39556)
* Fix sorting for null values in piechart

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
(cherry picked from commit 4a6e354497)

Co-authored-by: Oscar Kilhed <oscar.kilhed@grafana.com>
2021-09-23 11:10:24 +02:00
Grot (@grafanabot)
1b8255e317 A11y: Fix fastpass issues for /admin/* pages (#39435) (#39535)
* A11y: Fix fastpass issues for /admin/* pages
See #39429

(cherry picked from commit 00dad0f4e8)

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2021-09-22 23:35:05 +01:00
Grot (@grafanabot)
d343d2242d CloudMonitoring: Fix INT64 label unmarshal error (#39441) (#39528)
(cherry picked from commit f76a11c955)

Co-authored-by: Benedikt Spellmeyer <b.spellmeyer@googlemail.com>
2021-09-22 17:42:15 +02:00
Ashley Harrison
a0fe59adef Chore(Navigation): Rename SideMenu -> NavBar (#39483) (#39525)
(cherry picked from commit a4d41d35d0)
2021-09-22 15:38:20 +01:00
Grot (@grafanabot)
04900c63f0 Plugins Catalog: add a few more tests (#39433) (#39470)
* refactor(Plugins/Admin): add an extra line-break between tests

* test(Plugins/Admin): add a couple of more tests for Plugin Details

* fix(Plugins/Admin): fix accidental linting issue

(cherry picked from commit 660afc6279)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
2021-09-22 13:46:22 +02:00
Grot (@grafanabot)
e4862a64f7 Explore: prevent eplore from hiding errors containing refId (#39504) (#39508)
* Explore: prevent eplore from hiding errors containing refId

* Update public/app/features/explore/ResponseErrorContainer.tsx

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
(cherry picked from commit 5f48d0641b)

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2021-09-22 11:59:38 +02:00
Grot (@grafanabot)
036db0f9d0 Plugins Catalog: add unit tests for data-munging (#39338) (#39432)
* test(Plugins/Admin): add tests for the helper functions

* chore(Plugins/Admin): add `error` field to the CatalogPlugin mock

* test(Plugins/Admin): add new properties `error` & `isDisabled` to test expectations

* refactor(Plugins/Admin): make the `errors` param optional everywhere

* fix(Plugins/Admin): fix a rebase bug

(cherry picked from commit fef8e646ea)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
2021-09-22 11:06:07 +02:00
Grot (@grafanabot)
9b9b7e5a45 CloudWatch: Add AWS Gateway ELB metrics and dimensions (#39490) (#39502)
(cherry picked from commit dfb8a4cd13)

Co-authored-by: Ilya Stoliar <52413756+ilyastoli@users.noreply.github.com>
2021-09-22 10:41:48 +02:00
Grot (@grafanabot)
793cd39af3 [v8.2.x] docs: removed nonsense line from standard-options.md (#39383)
* docs: removed nonsense line from standard-options.md (#39381)

(cherry picked from commit 85391c59d0)

* Added extra space.

* Removed space.

Co-authored-by: Nick Reilingh <nreiling@bard.edu>
Co-authored-by: achatterjee-grafana <aparajita.chatterjee@grafana.com>
2021-09-21 10:17:34 -04:00
Grot (@grafanabot)
f5be918e49 Use sdk pkg for gtime (#39354) (#39468)
(cherry picked from commit 64c8d32fe7)

Co-authored-by: Andres Martinez Gotor <andres.martinez@grafana.com>
2021-09-21 13:41:31 +02:00
Grot (@grafanabot)
698c13482a Fix Query Editor Row horizontal overflow (#39419) (#39460)
(cherry picked from commit 42b1fa0f62)

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2021-09-21 12:18:24 +01:00
Grot (@grafanabot)
88ea42ab9c Chore: Add go-redis v8 dependency (#39442) (#39448)
* adds redis v8 client dependency

* remove go-redis v5 dependency

(cherry picked from commit 1781c8ec7d)

Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com>
2021-09-20 22:52:18 +02:00
Grot (@grafanabot)
9ae43a7aaa Schema: unify bar/point/etc visibility modes (#39378) (#39446)
(cherry picked from commit ad3c7529b0)

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2021-09-20 21:52:52 +02:00
Grot (@grafanabot)
ee7c12592d Live: show popup if local changes exist (#36093) (#39440)
* change tracker

* not needed

(cherry picked from commit a6fbb8d724)

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2021-09-20 18:54:51 +02:00
Grot (@grafanabot)
17a5142901 Plugins Catalog: Fix a11y issues (#39407) (#39416)
* refactor(catalog): fix a11y issues in Browse and PluginListCard

* test(catalog): fix failing PluginListCard tests

(cherry picked from commit 4a11d0dab9)

Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
2021-09-20 15:48:28 +02:00
Grot (@grafanabot)
9e825719f6 prometheus: monaco: do not recalculate not-changing function-list (#39406) (#39413)
(cherry picked from commit dc61edc8ac)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-20 14:03:28 +02:00
Grot (@grafanabot)
10c44b4f8d Alerting: Move the unified alerting settings to its own struct (#39350) (#39400)
(cherry picked from commit 2ad82b9354)

Co-authored-by: gotjosh <josue@grafana.com>
2021-09-20 11:02:07 +01:00
Grot (@grafanabot)
395730e2f7 Publishing packages: Add grafana/schema (#39317) (#39325)
(cherry picked from commit 5eb46281a4)

Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
2021-09-20 11:11:53 +02:00
Grot (@grafanabot)
c418e75fcf A11y/Menu: Add keyboard support to Menu component (#38974) (#39403)
(cherry picked from commit d5b885f958)

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
2021-09-20 09:37:22 +01:00
Grot (@grafanabot)
56db5cc071 Plugins Catalog: show a confirmation modal when uninstalling a plugin (#39244) (#39402)
* feat(Plugins/Admin): show a confirmation modal when uninstalling a plugin

* refactor(Plugins/Admin): use a helper function for showing/hiding the modal

* test(Plugins/Admin): test if the modal disappears after an uninstall

(cherry picked from commit 02f9564607)

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
2021-09-20 10:14:11 +02:00
Grot (@grafanabot)
e272e239d0 Explore: Fixed default data source loading (#37059) (#39379)
Co-authored-by: Andrej Ocenas <mr.ocenas@gmail.com>
(cherry picked from commit 64f898c5f6)

Co-authored-by: Assaf Dayan <asfdyn@gmail.com>
2021-09-20 10:11:51 +02:00
Grot (@grafanabot)
972ec9cf85 Variables: Prevents unnecessary duplicate requests (#39394) (#39401)
(cherry picked from commit e696a9ab42)

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
2021-09-20 09:55:25 +02:00
Grot (@grafanabot)
635e489a59 ConfirmModal: Fix confirm button focus on modal open (#39328) (#39397)
(cherry picked from commit 06012a8da0)

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
2021-09-20 09:45:43 +02:00
Grot (@grafanabot)
333c1da5c7 PluginsCatalog: adding error information about disabled plugins. (#39171) (#39399)
* added errors in plugin list.

* added error to details page.

* adding badge on details page.

* added some more tests.

* Renamed to disabled and will handle the scenario in the plugin catalog.

* Update public/app/features/plugins/admin/components/PluginDetailsDisabledError.tsx

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>

* fixing some nits

* added missing isDisabeld to the mock.

* adding tests to verify scenarios when plugin is disabled.

* fixed issue with formatting after file changed on GH.

Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
(cherry picked from commit f3002931f4)

Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com>
2021-09-20 09:43:24 +02:00
Grot (@grafanabot)
cea17c7e49 ValueMappings: Value mapping and specifying only color should not affect value formatting (decimals, unit, etc) (#39315) (#39398)
(cherry picked from commit a899e9be10)

Co-authored-by: Torkel Ödegaard <torkel@grafana.org>
2021-09-20 09:40:42 +02:00
Grot (@grafanabot)
704ba385aa Make "dist" version of dashboard scuemata directly importable in CUE (#39251) (#39372)
* Update embeds with new paths, remove deprefixing

* Add dist dashboard scuemata, in CUE

Also add tests that ensure all panel plugins with models.cue are
imported by this file, so that we can't go out of sync.

* Remove comment detritus

* Check error return

* Remove hardcoded path prefix from cli validator

(cherry picked from commit 39f2ee7692)

Co-authored-by: sam boyer <sam.boyer@grafana.com>
2021-09-17 17:14:36 -04:00
Grot (@grafanabot)
b21ba77c4f GraphNG: uPlot 1.6.16 (#39260) (#39367)
(cherry picked from commit 474461ba15)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
2021-09-17 15:16:36 -05:00
Grot (@grafanabot)
3a002da406 Pipeline: Make Pa11y ci not mandatory on PR stage (#39285) (#39368)
(cherry picked from commit ef36bbbfbd)

Co-authored-by: Maria Alexandra <239999+axelavargas@users.noreply.github.com>
2021-09-17 13:59:10 -05:00
Grot (@grafanabot)
6f52226c66 Alerting: Metrics should have the label org instead of user (#39353) (#39365)
An user within Grafana has a completely different meaning. Multi-tenancy is done via Organizations as a top-level concept.

(cherry picked from commit 35e5bfce40)

Co-authored-by: gotjosh <josue@grafana.com>
2021-09-17 18:52:54 +02:00
Grot (@grafanabot)
ab5ec6e838 namespace should be AWS/Rekognition (#39094) (#39360)
(cherry picked from commit 7d873fa795)

Co-authored-by: Sumit Bopche <sumitbopche01@gmail.com>
2021-09-17 17:52:49 +02:00
Grot (@grafanabot)
71b0ae9094 BarChart: Fix field enumeration for bar value display and legend items (#39308) (#39357)
(cherry picked from commit 29e8728ef0)

Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
2021-09-17 17:23:38 +02:00
Grot (@grafanabot)
3b1abd4bd3 prometheus: monaco-query-field: fix metrics-list (#39347) (#39349)
(cherry picked from commit 73873f99cd)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-17 15:28:35 +02:00
Andres Martinez Gotor
13b8b7721b backport #39322 (#39344) 2021-09-17 15:22:48 +02:00
Grot (@grafanabot)
8a369feb63 Alerting: Support Unified Alerting with Grafana HA (#37920) (#39342)
* Alerting: Support Unified Alerting in Grafana's HA mode.

(cherry picked from commit 7db97097c9)

Co-authored-by: gotjosh <josue@grafana.com>
2021-09-17 13:23:51 +01:00
Grot (@grafanabot)
499b1f4ff2 influxdb: influxql: more robust resultformat-handling (#39330) (#39339)
(cherry picked from commit d116b2d71b)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-17 13:06:44 +02:00
Andres Martinez Gotor
8fcfc4d87e merge main (#39318)
Co-authored-by: Grot (@grafanabot) <43478413+grafanabot@users.noreply.github.com>
2021-09-17 11:23:50 +02:00
Grot (@grafanabot)
c05f195de5 prometheus: monaco: handle multiple query fields at the same time (#39286) (#39320)
(cherry picked from commit 8489575c84)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-17 10:24:18 +02:00
Grot (@grafanabot)
49bec6ce4f prometheus: query-editor: better duration-completions (#39284) (#39314)
(cherry picked from commit f8de33da8d)

Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2021-09-17 09:41:16 +02:00
Grot (@grafanabot)
d8b03490c3 "Release: Updated versions in package to 8.2.0-beta.1" (#39281) 2021-09-16 11:32:27 +02:00
431 changed files with 15063 additions and 2580 deletions

View File

@@ -156,6 +156,7 @@ steps:
from_secret: grafana_misc_stats_api_key
HOST: end-to-end-tests-server
PORT: 3001
failure: ignore
depends_on:
- end-to-end-tests-server
@@ -3491,6 +3492,6 @@ get:
---
kind: signature
hmac: 974d6cc07d690099a1e1ac4581c6ccafc6c6c2998289c09655c70932088dce40
hmac: 9211e316cd24660667ba57b860129d2f06b0a4a669aa4d5c1f13156667ae027f
...

View File

@@ -16,7 +16,7 @@ var config = {
"click element button[aria-label='Login button']",
"wait for element [aria-label='Skip change password button'] to be visible",
],
threshold: 2,
threshold: 3,
},
{
url: '${HOST}/?orgId=1',

View File

@@ -1,3 +1,104 @@
<!-- 8.2.0-beta1 START -->
# 8.2.0-beta1 (2021-09-16)
### Features and enhancements
- **AccessControl:** Introduce new permissions to restrict access for reloading provisioning configuration. [#38906](https://github.com/grafana/grafana/pull/38906), [@vtorosyan](https://github.com/vtorosyan)
- **Alerting:** Add UI to edit Cortex/Loki namespace, group names, and group evaluation interval. [#38543](https://github.com/grafana/grafana/pull/38543), [@domasx2](https://github.com/domasx2)
- **Alerting:** Add a Test button to test contact point. [#37475](https://github.com/grafana/grafana/pull/37475), [@domasx2](https://github.com/domasx2)
- **Alerting:** Allow creating/editing recording rules for Loki and Cortex. [#38064](https://github.com/grafana/grafana/pull/38064), [@domasx2](https://github.com/domasx2)
- **Alerting:** Sort notification channels by name to make them easier to locate. [#37426](https://github.com/grafana/grafana/pull/37426), [@jstangroome](https://github.com/jstangroome)
- **AzureMonitor:** Add data links to deep link to Azure Portal Azure Resource Graph. [#35591](https://github.com/grafana/grafana/pull/35591), [@shuotli](https://github.com/shuotli)
- **AzureMonitor:** Add support for annotations from Azure Monitor Metrics and Azure Resource Graph services. [#37633](https://github.com/grafana/grafana/pull/37633), [@joshhunt](https://github.com/joshhunt)
- **AzureMonitor:** Show error message when subscriptions request fails in ConfigEditor. [#37837](https://github.com/grafana/grafana/pull/37837), [@joshhunt](https://github.com/joshhunt)
- **Chore:** Update to Golang 1.16.7. [#38604](https://github.com/grafana/grafana/pull/38604), [@dsotirakis](https://github.com/dsotirakis)
- **CloudWatch Logs:** Add link to X-Ray data source for trace IDs in logs. [#39135](https://github.com/grafana/grafana/pull/39135), [@aocenas](https://github.com/aocenas)
- **CloudWatch Logs:** Disable query path using websockets (Live) feature. [#39231](https://github.com/grafana/grafana/pull/39231), [@aocenas](https://github.com/aocenas)
- **CloudWatch/Logs:** Don't group dataframes for non time series queries. [#37998](https://github.com/grafana/grafana/pull/37998), [@aocenas](https://github.com/aocenas)
- **Cloudwatch:** Migrate queries that use multiple stats to one query per stat. [#36925](https://github.com/grafana/grafana/pull/36925), [@sunker](https://github.com/sunker)
- **Dashboard:** Keep live timeseries moving left (v2). [#37769](https://github.com/grafana/grafana/pull/37769), [@ryantxu](https://github.com/ryantxu)
- **Datasources:** Introduce `response_limit` for datasource responses. [#38962](https://github.com/grafana/grafana/pull/38962), [@dsotirakis](https://github.com/dsotirakis)
- **Explore:** Add filter by trace or span ID to `trace to logs` feature. [#38943](https://github.com/grafana/grafana/pull/38943), [@connorlindsey](https://github.com/connorlindsey)
- **Explore:** Download traces as JSON in Explore Inspector. [#38614](https://github.com/grafana/grafana/pull/38614), [@connorlindsey](https://github.com/connorlindsey)
- **Explore:** Reuse Dashboard's QueryRows component. [#38942](https://github.com/grafana/grafana/pull/38942), [@Elfo404](https://github.com/Elfo404)
- **Explore:** Support custom display label for derived fields buttons for Loki datasource. [#37273](https://github.com/grafana/grafana/pull/37273), [@connorlindsey](https://github.com/connorlindsey)
- **Grafana UI:** Update monaco-related dependencies. [#39027](https://github.com/grafana/grafana/pull/39027), [@gabor](https://github.com/gabor)
- **Graphite:** Deprecate browser access mode. [#38783](https://github.com/grafana/grafana/pull/38783), [@ifrost](https://github.com/ifrost)
- **InfluxDB:** Improve handling of intervals in alerting. [#37588](https://github.com/grafana/grafana/pull/37588), [@gabor](https://github.com/gabor)
- **InfluxDB:** InfluxQL query editor: Handle unusual characters in tag values better. [#39170](https://github.com/grafana/grafana/pull/39170), [@gabor](https://github.com/gabor)
- **Jaeger:** Add ability to upload JSON file for trace data. [#37205](https://github.com/grafana/grafana/pull/37205), [@zoltanbedi](https://github.com/zoltanbedi)
- **LibraryElements:** Enable specifying UID for new and existing library elements. [#39019](https://github.com/grafana/grafana/pull/39019), [@hugohaggmark](https://github.com/hugohaggmark)
- **LibraryPanels:** Remove library panel icon from the panel header so you can no longer tell that a panel is a library panel from the dashboard view. [#38749](https://github.com/grafana/grafana/pull/38749), [@hugohaggmark](https://github.com/hugohaggmark)
- **Logs panel:** Scroll to the bottom on page refresh when sorting in ascending order. [#37634](https://github.com/grafana/grafana/pull/37634), [@ivanahuckova](https://github.com/ivanahuckova)
- **Loki:** Add fuzzy search to label browser. [#36864](https://github.com/grafana/grafana/pull/36864), [@connorlindsey](https://github.com/connorlindsey)
- **Navigation:** Implement active state for items in the Sidemenu. [#39030](https://github.com/grafana/grafana/pull/39030), [@ashharrison90](https://github.com/ashharrison90)
- **Packaging:** Add stricter systemd unit options. [#38109](https://github.com/grafana/grafana/pull/38109), [@erdnaxe](https://github.com/erdnaxe)
- **Packaging:** Update PID file location from `/var/run` to `/run`. [#35739](https://github.com/grafana/grafana/pull/35739), [@MichaIng](https://github.com/MichaIng)
- **Plugins:** Add Hide OAuth Forward config option. [#36306](https://github.com/grafana/grafana/pull/36306), [@wbrowne](https://github.com/wbrowne)
- **Postgres/MySQL/MSSQL:** Add setting to limit the maximum number of rows processed. [#38986](https://github.com/grafana/grafana/pull/38986), [@marefr](https://github.com/marefr)
- **Prometheus:** Add browser access mode deprecation warning. [#37578](https://github.com/grafana/grafana/pull/37578), [@ivanahuckova](https://github.com/ivanahuckova)
- **Prometheus:** Add interpolation for built-in-time variables to backend. [#39051](https://github.com/grafana/grafana/pull/39051), [@ivanahuckova](https://github.com/ivanahuckova)
- **Tempo:** Add ability to upload trace data in JSON format. [#37407](https://github.com/grafana/grafana/pull/37407), [@zoltanbedi](https://github.com/zoltanbedi)
- **TimeSeries/XYChart:** Allow grid lines visibility control in XYChart and TimeSeries panels. [#38502](https://github.com/grafana/grafana/pull/38502), [@dprokop](https://github.com/dprokop)
- **Transformations:** Convert field types to time string number or boolean. [#38517](https://github.com/grafana/grafana/pull/38517), [@nikki-kiga](https://github.com/nikki-kiga)
- **Value mappings:** Add regular-expression based value mapping. [#38931](https://github.com/grafana/grafana/pull/38931), [@mcdee](https://github.com/mcdee)
- **Zipkin:** Add ability to upload trace JSON. [#37483](https://github.com/grafana/grafana/pull/37483), [@zoltanbedi](https://github.com/zoltanbedi)
### Bug fixes
- **Admin:** Prevent user from deleting user's current/active organization. [#38056](https://github.com/grafana/grafana/pull/38056), [@idafurjes](https://github.com/idafurjes)
- **LibraryPanels:** Fix library panel getting saved in the dashboard's folder. [#38978](https://github.com/grafana/grafana/pull/38978), [@hugohaggmark](https://github.com/hugohaggmark)
- **OAuth:** Make generic teams URL and JMES path configurable. [#37233](https://github.com/grafana/grafana/pull/37233), [@djairhogeuens](https://github.com/djairhogeuens)
- **QueryEditor:** Fix broken copy-paste for mouse middle-click (#39117). [#39117](https://github.com/grafana/grafana/pull/39117), [@glintik](https://github.com/glintik)
- **Thresholds:** Fix undefined color in "Add threshold". [#39113](https://github.com/grafana/grafana/pull/39113), [@glintik](https://github.com/glintik)
- **Timeseries:** Add wide-to-long, and fix multi-frame output. [#38670](https://github.com/grafana/grafana/pull/38670), [@ryantxu](https://github.com/ryantxu)
- **TooltipPlugin:** Fix behavior of Shared Crosshair when Tooltip is set to All. [#37285](https://github.com/grafana/grafana/pull/37285), [@nikki-kiga](https://github.com/nikki-kiga)
### Breaking changes
The `monaco-editor` dependency in `grafana-ui` has been updated to a newer version (`0.27.0`), which is not completely backward compatible with the old version (`0.21.2`). The backward incompatible changes are fairly small, but they do exist, so if your code accesses the raw monaco-objects through the `grafana-ui` package, please check the [monaco-editor changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md) and apply any necessary changes. Issue [#39027](https://github.com/grafana/grafana/issues/39027)
The mandatory `css` prop in `grafana/ui` components has been removed.
Previous versions of `grafana/ui` components were typed incorrectly due to a dependency mismatch between emotion 10 and 11 causing a `css` prop to be added to components that extended react types.
Issue [#38078](https://github.com/grafana/grafana/issues/38078)
Panel queries and/or annotation queries that used more than one statistic will be converted into one query/annotation per statistic. In case an alerting rule was based on a query row that had more than one statistic, it would now be based only on the first statistic for that query row. New alerting rules will not be created for migrated queries. Please note that in most cases it would not make sense to have an alerting rule that is based on multiple statistics anyway. Issue [#36925](https://github.com/grafana/grafana/issues/36925)
### Deprecations
`getHighlighterExpressions` in datasource APIs ( used to highlight logs while editing queries) has been deprecated and will be removed in a future release.
# Deprecation notice
`ExploreQueryFieldProps` interface for query editors has been deprecated and will be removed in a future release. Use `QueryEditorProps` instead. Issue [#38942](https://github.com/grafana/grafana/issues/38942)
### Plugin development fixes & changes
- **Grafana UI:** Fix TS error property `css` is missing in type. [#38078](https://github.com/grafana/grafana/pull/38078), [@jackw](https://github.com/jackw)
<!-- 8.2.0-beta1 END -->
<!-- 8.1.4 START -->
# 8.1.4 (2021-09-16)
### Features and enhancements
- **Explore:** Ensure logs volume bar colors match legend colors. [#39072](https://github.com/grafana/grafana/pull/39072), [@ifrost](https://github.com/ifrost)
- **LDAP:** Search all DNs for users. [#38891](https://github.com/grafana/grafana/pull/38891), [@sakjur](https://github.com/sakjur)
### Bug fixes
- **Alerting:** Fix notification channel migration. [#38983](https://github.com/grafana/grafana/pull/38983), [@papagian](https://github.com/papagian)
- **Annotations:** Fix blank panels for queries with unknown data sources. [#39017](https://github.com/grafana/grafana/pull/39017), [@hugohaggmark](https://github.com/hugohaggmark)
- **BarChart:** Fix stale values and x axis labels. [#39188](https://github.com/grafana/grafana/pull/39188), [@leeoniya](https://github.com/leeoniya)
- **Graph:** Make old graph panel thresholds work even if ngalert is enabled. [#38918](https://github.com/grafana/grafana/pull/38918), [@domasx2](https://github.com/domasx2)
- **InfluxDB:** Fix regex to identify `/` as separator. [#39185](https://github.com/grafana/grafana/pull/39185), [@dsotirakis](https://github.com/dsotirakis)
- **LibraryPanels:** Fix update issues related to library panels in rows. [#38963](https://github.com/grafana/grafana/pull/38963), [@hugohaggmark](https://github.com/hugohaggmark)
- **Variables:** Fix variables not updating inside a Panel when the preceding Row uses "Repeat For". [#38935](https://github.com/grafana/grafana/pull/38935), [@axelavargas](https://github.com/axelavargas)
<!-- 8.1.4 END -->
<!-- 8.1.3 START -->
# 8.1.3 (2021-09-08)

View File

@@ -211,7 +211,7 @@ rudderstack_data_plane_url =
# Application Insights connection string. Specify an URL string to enable this feature.
application_insights_connection_string =
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
# Optional. Specifies an Application Insights endpoint URL where the endpoint string is wrapped in backticks ``.
application_insights_endpoint_url =
#################################### Security ############################
@@ -731,14 +731,65 @@ global_alert_rule = -1
#################################### Unified Alerting ####################
[unified_alerting]
# Enable the Unified Alerting sub-system and interface. When enabled we'll migrate all of your alert rules and notification channels to the new system. New alert rules will be created and your notification channels will be converted into an Alertmanager configuration. Previous data is preserved to enable backwards compatibility but new data is removed.
enabled = false
# Comma-separated list of organization IDs for which to disable unified alerting. Only supported if unified alerting is enabled.
disabled_orgs =
# Specify the frequency of polling for admin config changes.
admin_config_poll_interval_seconds = 60
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
admin_config_poll_interval = 60s
# Specify the frequency of polling for Alertmanager config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
alertmanager_config_poll_interval = 60s
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port.
ha_listen_address = "0.0.0.0:9094"
# Explicit address/hostname and port to advertise other Grafana instances. The port is used for both TCP and UDP.
ha_advertise_address = ""
# Comma-separated list of initial instances (in a format of host:port) that will form the HA cluster. Configuring this setting will enable High Availability mode for alerting.
ha_peers = ""
# Time to wait for an instance to send a notification via the Alertmanager. In HA, each Grafana instance will
# be assigned a position (e.g. 0, 1). We then multiply this position with the timeout to indicate how long should
# each instance wait before sending the notification to take into account replication lag.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_peer_timeout = 15s
# The interval between sending gossip messages. By lowering this value (more frequent) gossip messages are propagated
# across cluster more quickly at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_gossip_interval = 200ms
# The interval between gossip full state syncs. Setting this interval lower (more frequent) will increase convergence speeds
# across larger clusters at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
ha_push_pull_interval = 60s
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. This option has a legacy version in the `[alerting]` section that takes precedence.
max_attempts = 3
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
min_interval = 10s
#################################### Alerting ############################
[alerting]
# Disable alerting engine & UI features
# Disable legacy alerting engine & UI features
enabled = true
# Makes it possible to turn off alert rule execution but alerting UI is visible
# Makes it possible to turn off alert execution but alerting UI is visible
execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
@@ -914,7 +965,7 @@ app_tls_skip_verify_insecure = false
# Enter a comma-separated list of plugin identifiers to identify plugins to load even if they are unsigned. Plugins with modified signatures are never loaded.
allow_loading_unsigned_plugins =
# Enable or disable installing plugins directly from within Grafana.
plugin_admin_enabled = false
plugin_admin_enabled = true
plugin_admin_external_manage_enabled = false
plugin_catalog_url = https://grafana.com/grafana/plugins/

View File

@@ -708,14 +708,65 @@
#################################### Unified Alerting ####################
[unified_alerting]
#Enable the Unified Alerting sub-system and interface. When enabled we'll migrate all of your alert rules and notification channels to the new system. New alert rules will be created and your notification channels will be converted into an Alertmanager configuration. Previous data is preserved to enable backwards compatibility but new data is removed.```
;enabled = false
# Comma-separated list of organization IDs for which to disable unified alerting. Only supported if unified alerting is enabled.
;disabled_orgs =
# Specify the frequency of polling for admin config changes.
;admin_config_poll_interval_seconds = 60
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;admin_config_poll_interval = 60s
# Specify the frequency of polling for Alertmanager config changes.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;alertmanager_config_poll_interval = 60s
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port. The default value is `0.0.0.0:9094`.
;ha_listen_address = "0.0.0.0:9094"
# Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port. The default value is `0.0.0.0:9094`.
;ha_advertise_address = ""
# Comma-separated list of initial instances (in a format of host:port) that will form the HA cluster. Configuring this setting will enable High Availability mode for alerting.
;ha_peers = ""
# Time to wait for an instance to send a notification via the Alertmanager. In HA, each Grafana instance will
# be assigned a position (e.g. 0, 1). We then multiply this position with the timeout to indicate how long should
# each instance wait before sending the notification to take into account replication lag.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_peer_timeout = "15s"
# The interval between sending gossip messages. By lowering this value (more frequent) gossip messages are propagated
# across cluster more quickly at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_gossip_interval = "200ms"
# The interval between gossip full state syncs. Setting this interval lower (more frequent) will increase convergence speeds
# across larger clusters at the expense of increased bandwidth usage.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;ha_push_pull_interval = "60s"
# Enable or disable alerting rule execution. The alerting UI remains visible. This option has a legacy version in the `[alerting]` section that takes precedence.
;execute_alerts = true
# Alert evaluation timeout when fetching data from the datasource. This option has a legacy version in the `[alerting]` section that takes precedence.
# The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;evaluation_timeout = 30s
# Number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. This option has a legacy version in the `[alerting]` section that takes precedence.
;max_attempts = 3
# Minimum interval to enforce between rule evaluations. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has a legacy version in the `[alerting]` section that takes precedence.
# The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
;min_interval = 10s
#################################### Alerting ############################
[alerting]
# Disable alerting engine & UI features
# Disable legacy alerting engine & UI features
;enabled = true
# Makes it possible to turn off alert rule execution but alerting UI is visible
# Makes it possible to turn off alert execution but alerting UI is visible
;execute_alerts = true
# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state)
@@ -728,7 +779,6 @@
# This limit will protect the server from render overloading and make sure notifications are sent out quickly
;concurrent_render_limit = 5
# Default setting for alert calculation timeout. Default value is 30
;evaluation_timeout_seconds = 30

View File

@@ -76,6 +76,7 @@
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
@@ -83,7 +84,7 @@
},
"targets": [
{
"csvContent": "Name,Stat1,Stat2\nStockholm, 10, 15\nNew York, 19, 5\nLondon, 10, 1\nNegative, 15, -5\nLong value, 15,10",
"csvContent": "Time,Name,Stat1,Stat2\n2020-01-01T00:00:00Z,Stockholm, 10, 15\n2020-01-01T00:00:00Z,New York, 19, 5\n2020-01-01T00:00:00Z,London, 10, 1\n2020-01-01T00:00:00Z,Negative, 15, -5\n2020-01-01T00:00:00Z,Long value, 15,10",
"refId": "A",
"scenarioId": "csv_content"
}
@@ -147,6 +148,7 @@
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
@@ -216,6 +218,7 @@
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
@@ -285,6 +288,7 @@
},
"orientation": "auto",
"showValue": "always",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
@@ -353,6 +357,7 @@
},
"orientation": "auto",
"showValue": "auto",
"stacking": "none",
"text": {
"titleSize": 10,
"valueSize": 25
@@ -425,6 +430,7 @@
},
"orientation": "horizontal",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"
@@ -495,6 +501,7 @@
},
"orientation": "horizontal",
"showValue": "auto",
"stacking": "none",
"text": {},
"tooltip": {
"mode": "single"

View File

@@ -0,0 +1 @@
grafana/provisioning/dashboards/alerts/alert-*

View File

@@ -0,0 +1,66 @@
# Grafana Unified Alerting High Availability (HA) test setup
A set of docker compose services which together creates a Grafana HA test setup for unified alerting.
Included services
- Grafana
- Mysql - Grafana configuration database, exporter for metrics and session storage
- Prometheus - Monitoring of Grafana and used as data source
- Nginx - Reverse proxy for Grafana and Prometheus. Enables browsing Grafana/Prometheus UI using a hostname
## Prerequisites
### Build grafana docker container
Build a Grafana docker container from current branch and commit and tag it as grafana/grafana:dev.
```bash
$ cd <grafana repo>
$ make build-docker-full
```
### Virtual host names
#### Alternative 1 - Use dnsmasq
```bash
$ sudo apt-get install dnsmasq
$ echo 'address=/loc/127.0.0.1' | sudo tee /etc/dnsmasq.d/dnsmasq-loc.conf > /dev/null
$ sudo /etc/init.d/dnsmasq restart
$ ping whatever.loc
PING whatever.loc (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.076 ms
--- whatever.loc ping statistics ---
1 packet transmitted, 1 received, 0% packet loss, time 1998ms
```
#### Alternative 2 - Manually update /etc/hosts
Update your `/etc/hosts` to be able to access Grafana and/or Prometheus UI using a hostname.
```bash
$ cat /etc/hosts
127.0.0.1 grafana.loc
127.0.0.1 prometheus.loc
```
## Start services
```bash
$ docker-compose up -d
```
Browse
- http://grafana.loc/
- http://prometheus.loc/
## Test alerting
### Create contact points
TBD
### Create alerts
TBD
### Create silences
TBD

View File

@@ -0,0 +1,90 @@
version: "2.1"
services:
db:
image: mysql:5.6
platform: linux/x86_64
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: grafana
MYSQL_USER: grafana
MYSQL_PASSWORD: password
command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --innodb_monitor_enable=all, --max-connections=1001]
ports:
- 3306
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
timeout: 10s
retries: 10
mysqld-exporter:
image: prom/mysqld-exporter
environment:
- DATA_SOURCE_NAME=root:rootpass@(db:3306)/
ports:
- 9104
depends_on:
db:
condition: service_healthy
prometheus:
image: prom/prometheus:v2.4.2
volumes:
- ./prometheus/:/etc/prometheus/
environment:
- VIRTUAL_HOST=prometheus.loc
ports:
- 909
nginx-proxy:
image: jwilder/nginx-proxy
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
depends_on:
db:
condition: service_healthy
grafana1:
image: grafana/grafana:dev
volumes:
- ./grafana/provisioning/:/etc/grafana/provisioning/
environment:
- VIRTUAL_HOST=grafana.loc
- GF_FEATURE_TOGGLES_ENABLE=ngalert
- GF_UNIFIED_ALERTING_HA_PEERS=ha-test-unified-alerting_grafana2_1:9094,ha-test-unified-alerting_grafana1_1:9094
- GF_SERVER_ROOT_URL=http://grafana.loc
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana
- GF_DATABASE_PASSWORD=password
- GF_DATABASE_TYPE=mysql
- GF_DATABASE_HOST=db:3306
- GF_DATABASE_MAX_OPEN_CONN=300
- GF_SESSION_PROVIDER=mysql
- GF_SESSION_PROVIDER_CONFIG=grafana:password@tcp(db:3306)/grafana?allowNativePasswords=true
ports:
- 3010:3000
depends_on:
db:
condition: service_healthy
grafana2:
image: grafana/grafana:dev
volumes:
- ./grafana/provisioning/:/etc/grafana/provisioning/
environment:
- VIRTUAL_HOST=grafana.loc
- GF_FEATURE_TOGGLES_ENABLE=ngalert
- GF_UNIFIED_ALERTING_HA_PEERS=ha-test-unified-alerting_grafana2_1:9094,ha-test-unified-alerting_grafana1_1:9094
- GF_SERVER_ROOT_URL=http://grafana.loc
- GF_DATABASE_NAME=grafana
- GF_DATABASE_USER=grafana
- GF_DATABASE_PASSWORD=password
- GF_DATABASE_TYPE=mysql
- GF_DATABASE_HOST=db:3306
- GF_DATABASE_MAX_OPEN_CONN=300
- GF_SESSION_PROVIDER=mysql
- GF_SESSION_PROVIDER_CONFIG=grafana:password@tcp(db:3306)/grafana?allowNativePasswords=true
ports:
- 3020:3000
depends_on:
db:
condition: service_healthy

View File

@@ -0,0 +1,203 @@
local numAlerts = std.extVar('alerts');
local condition = std.extVar('condition');
local arr = std.range(1, numAlerts);
local alertDashboardTemplate = {
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": null,
"links": [],
"panels": [
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [
65
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "10s",
"handler": 1,
"for": "1m",
"name": "bulk alerting",
"noDataState": "no_data",
"notifications": [
{
"id": 2
}
]
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 0
},
"id": 2,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"$$hashKey": "object:117",
"expr": "go_goroutines",
"format": "time_series",
"intervalFactor": 1,
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 50
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
]
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "New dashboard",
"uid": null,
"version": 0
};
{
['alert-' + std.toString(x) + '.json']:
alertDashboardTemplate + {
panels: [
alertDashboardTemplate.panels[0] +
{
alert+: {
name: 'Alert rule ' + x,
conditions: [
alertDashboardTemplate.panels[0].alert.conditions[0] +
{
evaluator+: {
params: [condition]
}
},
],
},
},
],
uid: 'alert-' + x,
title: 'Alert ' + x
},
for x in arr
}

View File

@@ -0,0 +1,172 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"links": [],
"panels": [
{
"aliasColors": {
"Active alerts": "#bf1b00"
},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 12,
"w": 24,
"x": 0,
"y": 0
},
"id": 2,
"interval": "",
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": true
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [
{
"alias": "Active grafana instances",
"dashes": true,
"fill": 0
}
],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "sum(increase(grafana_alerting_notification_sent_total[1m])) by(job)",
"format": "time_series",
"instant": false,
"interval": "1m",
"intervalFactor": 1,
"legendFormat": "Notifications sent",
"refId": "A"
},
{
"expr": "min(grafana_alerting_active_alerts) without(instance)",
"format": "time_series",
"interval": "1m",
"intervalFactor": 1,
"legendFormat": "Active alerts",
"refId": "B"
},
{
"expr": "count(up{job=\"grafana\"})",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "Active grafana instances",
"refId": "C"
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Notifications sent vs active alerts",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": "0",
"show": true
},
{
"format": "short",
"label": null,
"logBase": 1,
"max": null,
"min": null,
"show": true
}
],
"yaxis": {
"align": false,
"alignLevel": 3
}
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-1h",
"to": "now"
},
"timepicker": {
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"timezone": "",
"title": "Overview",
"uid": "xHy7-hAik",
"version": 6
}

View File

@@ -0,0 +1,14 @@
apiVersion: 1
providers:
- name: 'Alerts'
folder: 'Alerts'
type: file
options:
path: /etc/grafana/provisioning/dashboards/alerts
- name: 'MySQL'
folder: 'MySQL'
type: file
options:
path: /etc/grafana/provisioning/dashboards/mysql

View File

@@ -0,0 +1,16 @@
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
jsonData:
timeInterval: 10s
queryTimeout: 30s
httpMethod: POST
- name: Loki
type: loki
access: proxy
url: http://loki:3100

View File

@@ -0,0 +1,47 @@
# my global config
global:
scrape_interval: 10s # By default, scrape targets every 15 seconds.
evaluation_interval: 10s # By default, scrape targets every 15 seconds.
# scrape_timeout is set to the global default (10s).
# Load and evaluate rules in this file every 'evaluation_interval' seconds.
#rule_files:
# - "alert.rules"
# - "first.rules"
# - "second.rules"
# alerting:
# alertmanagers:
# - scheme: http
# static_configs:
# - targets:
# - "127.0.0.1:9093"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'grafana'
dns_sd_configs:
- names:
- 'grafana'
type: 'A'
port: 3000
refresh_interval: 10s
- job_name: 'mysql'
dns_sd_configs:
- names:
- 'mysqld-exporter'
type: 'A'
port: 9104
refresh_interval: 10s
- job_name: 'loki'
dns_sd_configs:
- names:
- 'loki'
type: 'A'
port: 3100
refresh_interval: 10s

View File

@@ -16,6 +16,8 @@ To see all settings currently applied to the Grafana server, refer to [View serv
## Config file locations
The default settings for a Grafana instance are stored in the `$WORKING_DIR/conf/defaults.ini` file. _Do not_ change the location in this file.
_Do not_ change `defaults.ini`! Grafana defaults are stored in this file. Depending on your OS, make all configuration changes in either `custom.ini` or `grafana.ini`.
- Default configuration from `$WORKING_DIR/conf/defaults.ini`
@@ -1119,9 +1121,83 @@ Sets a global limit on number of alert rules that can be created. Default is -1
For more information about the Grafana 8 alerts, refer to [Unified Alerting]({{< relref "../alerting/unified-alerting/_index.md" >}}).
### admin_config_poll_interval_seconds
### enabled
Specify the frequency of polling for admin config changes. The default value is `60`.
Enable the Unified Alerting sub-system and interface. When enabled we'll migrate all of your alert rules and notification channels to the new system. New alert rules will be created and your notification channels will be converted into an Alertmanager configuration. Previous data is preserved to enable backwards compatibility but new data is removed. The default value is `false`.
Alerting Rules migrated from dashboards and panels will include a link back via the `annotations`.
### disabled_orgs
Comma-separated list of organization IDs for which to disable Grafana 8 Unified Alerting.
### admin_config_poll_interval
Specify the frequency of polling for admin config changes. The default value is `60s`.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### alertmanager_config_poll_interval
Specify the frequency of polling for Alertmanager config changes. The default value is `60s`.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### ha_listen_address
Listen address/hostname and port to receive unified alerting messages for other Grafana instances. The port is used for both TCP and UDP. It is assumed other Grafana instances are also running on the same port. The default value is `0.0.0.0:9094`.
### ha_advertise_address
Explicit address/hostname and port to advertise other Grafana instances. The port is used for both TCP and UDP.
### ha_peers
Comma-separated list of initial instances (in a format of host:port) that will form the HA cluster. Configuring this setting will enable High Availability mode for alerting.
### ha_peer_timeout
Time to wait for an instance to send a notification via the Alertmanager. In HA, each Grafana instance will
be assigned a position (e.g. 0, 1). We then multiply this position with the timeout to indicate how long should
each instance wait before sending the notification to take into account replication lag. The default value is `15s`.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### ha_gossip_interval
The interval between sending gossip messages. By lowering this value (more frequent) gossip messages are propagated
across cluster more quickly at the expense of increased bandwidth usage. The default value is `200ms`.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### ha_push_pull_interval
The interval between gossip full state syncs. Setting this interval lower (more frequent) will increase convergence speeds
across larger clusters at the expense of increased bandwidth usage. The default value is `60s`.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### execute_alerts
Enable or disable alerting rule execution. The default value is `true`. The alerting UI remains visible. This option has a [legacy version in the alerting section]({{< relref "#execute_alerts-1">}}) that takes precedence.
### evaluation_timeout
Sets the alert evaluation timeout when fetching data from the datasource. The default value is `30s`. This option has a [legacy version in the alerting section]({{< relref "#evaluation_timeout_seconds">}}) that takes precedence.
The timeout string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
### max_attempts
Sets a maximum number of times we'll attempt to evaluate an alert rule before giving up on that evaluation. The default value is `3`. This option has a [legacy version in the alerting section]({{< relref "#max_attempts-1">}}) that takes precedence.
### min_interval
Sets the minimum interval to enforce between rule evaluations. The default value is `10s` which equals the scheduler interval. Rules will be adjusted if they are less than this value or if they are not multiple of the scheduler interval (10s). Higher values can help with resource management as we'll schedule fewer evaluations over time. This option has [a legacy version in the alerting section]({{< relref "#min_interval_seconds">}}) that takes precedence.
The interval string is a possibly signed sequence of decimal numbers, followed by a unit suffix (ms, s, m, h, d), e.g. 30s or 1m.
> **Note.** This setting has precedence over each individual rule frequency. If a rule frequency is lower than this value, then this value is enforced.
<hr>
@@ -1131,7 +1207,7 @@ For more information about the Alerting feature in Grafana, refer to [Alerts ove
### enabled
Set to `false` to disable alerting engine and hide Alerting in the Grafana UI. Default is `true`.
Set to `false` to [enable Grafana 8 alerting]({{<relref "#unified_alerting">}}) and to disable legacy alerting engine. Default is `true`.
### execute_alerts
@@ -1677,7 +1753,7 @@ For more information about Grafana Enterprise, refer to [Grafana Enterprise]({{<
### enable
Keys of alpha features to enable, separated by space. Available alpha features are: `ngalert`
Keys of alpha features to enable, separated by space.
## [date_formats]

View File

@@ -154,7 +154,7 @@ Since not all datasources have the same configuration settings we only have the
| maxSeries | number | Influxdb | Max number of series/tables that Grafana processes |
| httpMethod | string | Prometheus | HTTP Method. 'GET', 'POST', defaults to POST |
| customQueryParameters | string | Prometheus | Query parameters to add, as a URL-encoded string. |
| manageAlerts | boolean | Prometheus and Loki | Manage alerts via Alerting UI |
| manageAlerts | boolean | Prometheus and Loki | Manage alerts via Alerting UI |
| esVersion | string | Elasticsearch | Elasticsearch version (E.g. `7.0.0`, `7.6.1`) |
| timeField | string | Elasticsearch | Which field that should be used as timestamp |
| interval | string | Elasticsearch | Index date time format. nil(No Pattern), 'Hourly', 'Daily', 'Weekly', 'Monthly' or 'Yearly' |

View File

@@ -7,9 +7,9 @@ weight = 110
Alerts allow you to know about problems in your systems moments after they occur. Robust and actionable alerts help you identify and resolve issues quickly, minimizing disruption to your services.
Grafana 8.0 has new and improved alerts. The new alerting system is an [opt-in]({{< relref "./unified-alerting/opt-in.md" >}}) feature that centralizes alerting information for Grafana managed alerts and alerts from Prometheus-compatible data sources in one UI and API.
Grafana 8.0 has new and improved alerts that centralizes alerting information for Grafana managed alerts as well as alerts from Prometheus-compatible data sources into one user interface and API.
> **Note:** Out of the box, Grafana still supports old [legacy dashboard alerts]({{< relref "./old-alerting/_index.md" >}}). We encourage you to create issues in the Grafana GitHub repository for bugs found while testing Grafana 8 alerts.
> **Note:** Grafana 8 alerts is an [opt-in]({{< relref "./unified-alerting/opt-in.md" >}}) feature. Out of the box, Grafana still supports old [legacy dashboard alerts]({{< relref "./old-alerting/_index.md" >}}). We encourage you to create issues in the Grafana GitHub repository for bugs found while testing Grafana 8 alerts.
Alerts have four main components:

View File

@@ -1,13 +1,13 @@
+++
title = "What's New with Grafana 8 Alerts"
title = "What's New with Grafana 8 alerts"
description = "What's New with Grafana 8 Alerts"
keywords = ["grafana", "alerting", "guide"]
weight = 112
+++
# What's New with Grafana 8 Alerts
# What's New with Grafana 8 alerts
The Alerts released with Grafana 8.0 are an opt-in feature that centralizes alerting information for Grafana managed alerts and alerts from Prometheus-compatible datasources in one UI and API. You are able to create and edit alerting rules for Grafana managed alerts, Cortex alerts, and Loki alerts as well as see alerting information from prometheus-compatible datasources in a single, searchable view.
The alerts released with Grafana 8.0 centralizes alerting information for Grafana managed alerts and alerts from Prometheus-compatible datasources in one UI and API. You can create and edit alerting rules for Grafana managed alerts, Cortex alerts, and Loki alerts as well as see alerting information from prometheus-compatible datasources in a single, searchable view.
## Multi-dimensional alerting

View File

@@ -6,9 +6,9 @@ weight = 113
# Overview of Grafana 8 alerts
Alerts allow you to know about problems in your systems moments after they occur. Robust and actionable alerts help you identify and resolve issues quickly, minimizing disruption to your services.
Grafana 8.0 has a new and improved alerting sub-system that centralizes alerting information for Grafana managed alerts and alerts from Prometheus-compatible data sources into one user interface and API.
> **Note:** Grafana 8 alerts (beta) is an [opt-in]({{< relref"./opt-in.md" >}}) feature. Out of the box, Grafana still supports old [legacy dashboard alerts]({{< relref "../old-alerting/_index.md" >}}). We encourage you to create issues in the Grafana GitHub repository for bugs found while testing this new feature.
> **Note:** Grafana 8 alerts is an [opt-in]({{< relref "../unified-alerting/opt-in.md" >}}) feature. Out of the box, Grafana still supports old [legacy dashboard alerts]({{< relref "./old-alerting/_index.md" >}}). We encourage you to create issues in the Grafana GitHub repository for bugs found while testing Grafana 8 alerts.
Grafana 8 alerts have four main components:
@@ -45,7 +45,7 @@ Alerting rules can only query backend data sources with alerting enabled:
## Metrics from the alerting engine
The alerting engine publishes some internal metrics about itself. You can read more about how Grafana publishes [internal metrics]({{< relref "../../administration/view-server/internal-metrics.md" >}}).
The alerting engine publishes some internal metrics about itself. You can read more about how Grafana publishes [internal metrics]({{< relref "../../administration/view-server/internal-metrics.md" >}}). See also, [View alert rules and their current state]({{< relref "alerting-rules/rule-list.md" >}}).
| Metric Name | Type | Description |
| ------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------- |
@@ -57,4 +57,6 @@ The alerting engine publishes some internal metrics about itself. You can read m
| `grafana_alerting_rule_evaluation_duration` | summary | The duration for a rule to execute |
| `grafana_alerting_rule_group_rules` | gauge | The number of rules |
- [View alert rules and their current state]({{< relref "alerting-rules/rule-list.md" >}})
## Limitation
Grafana 8 alerting system can retrieve rules from all available Prometheus, Loki, and Alertmanager data sources. It might not be able to fetch rules from all other supported data sources at this time.

View File

@@ -4,7 +4,7 @@ aliases = ["/docs/grafana/latest/alerting/rules/"]
weight = 130
+++
# Create and manage alerting Rules
# Create and manage alerting rules
One or more queries and/or expressions, a condition, the frequency of evaluation, and the (optional) duration that a condition must be met before creating an alert. Alerting rules are how you express the criteria for creating an alert. Queries and expressions select and can operate on the data you wish to alert on. A condition sets the threshold that an alert must meet or exceed to create an alert. The interval specifies how frequently the rule should be evaluated. The duration, when configured, sets a period that a condition must be met or exceeded before an alert is created. Alerting rules also can contain settings for what to do when your query does not return any data, or there is an error attempting to execute the query.

View File

@@ -4,33 +4,53 @@ description = "Enable Grafana 8 Alerts"
weight = 128
+++
# Enable Grafana 8 Alerts
# Opt-in to Grafana 8 alerts
Setting the `ngalert` feature toggle enables the new Grafana 8 alerting system.
This topic describes how to enable Grafana 8 alerts as well as the rules and restrictions that govern the migration of existing dashboard alerts to this new alerting system. You can also [disable Grafana 8 alerts]({{< relref "./opt-in.md#disable-grafana-8-alerts" >}}) if needed.
> **Note:** We recommend that you backup Grafana's database before enabling this feature. If you are using PostgreSQL as the backend data source, then the minimum required version is 9.5.
Before you begin, we recommend that you backup Grafana's database. If you are using PostgreSQL as the backend data source, then the minimum required version is 9.5.
At startup, when [the feature toggle is enabled]({{< relref "../../administration/configuration.md">}}#feature_toggles), the legacy Grafana dashboard alerting is disabled and existing dashboard alerts are migrated into a format that is compatible with the Grafana 8 alerting system. You can view these migrated rules, alongside any new alerts you create after the migration, from the Alerting page of your Grafana instance.
## Enable Grafana 8 alerts
> **Note - v8.2 or earlier:** Since the new system stores the notification log and silences on disk, we require the use of persistent disks for using Grafana 8 alerts. Otherwise, the silences and notification log will get lost on a restart, and you might get unwanted or duplicate notifications.
To enable Grafana 8 alerts:
> **Note - v8.3+**: We have removed the need of persistent disk. The notification log and silences are now stored in the database. If you used the file-based approach, we'll read those files and eventually (every 15 minutes) persist them to the database.
1. Go to your custom configuration file located in $WORKING_DIR/conf/custom.ini.
1. In the [unified alerts]({{< relref "../../administration/configuration.md#unified_alerting" >}}) section, set the `enabled` property to `true`.
1. Next, in the [alerting]({{< relref "../../administration/configuration.md#alerting" >}}) section of the configuration file, update the configuration for the legacy dashboard alerts by setting the `enabled` property to `false`.
1. Restart Grafana for the configuration changes to take effect.
Read and write access to dashboard alerts in Grafana versions 7 and earlier were governed by the dashboard and folder permissions under which the alerts were stored. In Grafana 8, alerts are stored in folders and inherit the permissions of those folders. During the migration, dashboard alert permissions are matched to the new rules permissions as follows:
> **Note:** Before Grafana v8.2, to enable or disable Grafana 8 alerts, users configured the `ngalert` feature toggle. This toggle option is no longer available.
Moreover, before v8.2, notification logs and silences were stored on a disk. If you did not use persistent disks, any configured silences and logs would get lost on a restart, resulting in unwanted or duplicate notifications.
As of Grafana 8.2, we no longer require the use of a persistent disk. Instead, the notification logs and silences are stored regularly (every 15 minutes), and a clean shutdown to the database. If you used the file-based approach, Grafana will read the existing file and persisting it eventually.
## Migrating legacy alerts to Grafana 8 alerting system
When Grafana 8 alerting is enabled, existing legacy dashboard alerts migrate in a format compatible with the Grafana 8 alerting system. In the Alerting page of your Grafana instance, you can view the migrated alerts alongside new alerts.
Read and write access to legacy dashboard alerts was governed by the dashboard and folder permissions storing them. In Grafana 8, alerts inherit the permissions of the folders they are stored in. During migration, legacy dashboard alert permissions are matched to the new rules permissions as follows:
- If alert's dashboard has permissions, it will create a folder named like `Migrated {"dashboardUid": "UID", "panelId": 1, "alertId": 1}` to match permissions of the dashboard (including the inherited permissions from the folder).
- If there are no dashboard permissions and the dashboard is under a folder, then the rule is linked to this folder and inherits its permissions.
- If there are no dashboard permissions and the dashboard is under the General folder, then the rule is linked to the `General Alerting` folder and the rule inherits the default permissions.
- If there are no dashboard permissions and the dashboard is under the General folder, then the rule is linked to the `General Alerting` folder, and the rule inherits the default permissions.
During beta, Grafana 8 alerting system can retrieve rules from all available Prometheus, Loki, and Alertmanager data sources. It might not be able to fetch rules from all other supported data sources at this time.
Notification channels are migrated to an Alertmanager configuration with the appropriate routes and receivers. Default notification channels are added as contact points to the default route. Notification channels not associated with any Dashboard alert go to the `autogen-unlinked-channel-recv` route.
Also notification channels are migrated to an Alertmanager configuration with the appropriate routes and receivers. Default notification channels are added as contact points to the default route. Notification channels not associated with any Dashboard alert go to the `autogen-unlinked-channel-recv` route.
Since `Hipchat` and `Sensu` notification channels are no longer supported, legacy alerts associated with these channels are not automatically migrated to Grafana 8 alerting. Assign the legacy alerts to a supported notification channel so that you continue to receive notifications for those alerts.
Silences (expiring after one year) are created for all paused dashboard alerts.
Since `Hipchat` and `Sensu` are discontinued, they are not migrated to the new alerting. If you have dashboard alerts associated with those types of channels and you want to migrate to the new alerting, make sure you assign another supported notification channel, so that you continue to receive notifications for those alerts.
Finally, silences (expiring after one year) are created for all paused dashboard alerts.
### Limitation
## Disabling Grafana 8 Alerting after migration
Grafana 8 alerting system can retrieve rules from all available Prometheus, Loki, and Alertmanager data sources. It might not be able to fetch rules from all other supported data sources at this time.
To disable Grafana 8 Alerting, remove or disable the `ngalert` feature toggle. Dashboard alerts will be re-enabled and any alerts created during or after the migration are deleted.
## Disable Grafana 8 alerts
> **Note:** Any alerting rules created in the Grafana 8 Alerting system will be lost when migrating back to dashboard alerts
To disable Grafana 8 alerts and enable legacy dashboard alerts:
1. Go to your custom configuration file located in $WORKING_DIR/conf/custom.ini.
1. In the [unified alerts]({{< relref "../../administration/configuration.md#unified_alerting" >}}) section, set the `enabled` property to `false`.
1. Next, in the [alerting]({{< relref "../../administration/configuration.md#alerting" >}}) section of the configuration file, update the configuration for the legacy dashboard alerts by setting the `enabled` property to `true`.
1. Restart Grafana for the configuration changes to take effect.
> **Note:** If you choose to migrate from Grafana 8 alerts to legacy dashboard alerts, you will lose any new alerts that you created in the Grafana 8 alerting system.

View File

@@ -109,10 +109,12 @@ allowed_groups =
```
You can also use these environment variables to configure **client_id** and **client_secret**:
```
GF_AUTH_AZUREAD_CLIENT_ID
GF_AUTH_AZUREAD_CLIENT_SECRET
```
**Note:** Ensure that the [root_url]({{< relref "../administration/configuration/#root-url" >}}) in Grafana is set in your Azure Application Reply URLs (**App** -> **Settings** -> **Reply URLs**)
### Configure allowed groups

View File

@@ -31,8 +31,8 @@ The reference information that follows complements conceptual information about
## Default built-in role assignments
| Built-in role | Associated role | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Built-in role | Associated role | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Grafana Admin | `fixed:permissions:admin:edit`<br>`fixed:permissions:admin:read`<br>`fixed:provisioning:admin`<br>`fixed:reporting:admin:edit`<br>`fixed:reporting:admin:read`<br>`fixed:users:admin:edit`<br>`fixed:users:admin:read`<br>`fixed:users:org:edit`<br>`fixed:users:org:read`<br>`fixed:ldap:admin:edit`<br>`fixed:ldap:admin:read`<br>`fixed:server:admin:read`<br>`fixed:settings:admin:read`<br>`fixed:settings:admin:edit` | Allow access to the same resources and permissions the [Grafana server administrator]({{< relref "../../permissions/_index.md#grafana-server-admin-role" >}}) has by default. |
| Admin | `fixed:users:org:edit`<br>`fixed:users:org:read`<br>`fixed:reporting:admin:edit`<br>`fixed:reporting:admin:read` | Allow access to the same resources and permissions that the [Grafana organization administrator]({{< relref "../../permissions/organization_roles.md" >}}) has by default. |
| Admin | `fixed:users:org:edit`<br>`fixed:users:org:read`<br>`fixed:reporting:admin:edit`<br>`fixed:reporting:admin:read` | Allow access to the same resources and permissions that the [Grafana organization administrator]({{< relref "../../permissions/organization_roles.md" >}}) has by default. |
| Editor | `fixed:datasource:editor:read` |

View File

@@ -401,6 +401,12 @@ The full Redis URL of your Redis server. Example: `redis://localhost:6739/0`.
The default is `"redis://localhost:6379"`.
### cluster
A comma-separated list of Redis cluster members in `host:port` format. For example, `localhost:7000, localhost: 7001, localhost:7002`.
> **Note:** If you have specify `cluster`, the value for `url` is ignored.
### prefix
A string that prefixes all Redis keys. This value must be set if using a shared database in Redis. If `prefix` is empty, then one will not be used.

View File

@@ -67,7 +67,6 @@ You can use the unit dropdown to also specify custom units, custom prefix or suf
To select a custom unit enter the unit and select the last `Custom: xxx` option in the dropdown.
- If y u want a space -> If you want a space
- `suffix:<suffix>` for custom unit that should go after value.
- `time:<format>` For custom date time formats type for example `time:YYYY-MM-DD`. See [formats](https://momentjs.com/docs/#/displaying/) for the format syntax and options.
- `si:<base scale><unit characters>` for custom SI units. For example: `si: mF`. This one is a bit more advanced as you can specify both a unit and the

View File

@@ -8,6 +8,8 @@ weight = 10000
Here you can find detailed release notes that list everything that is included in every release as well as notices
about deprecations, breaking changes as well as changes that relate to plugin development.
- [Release notes for 8.2.0-beta1]({{< relref "release-notes-8-2-0-beta1" >}})
- [Release notes for 8.1.4]({{< relref "release-notes-8-1-4" >}})
- [Release notes for 8.1.3]({{< relref "release-notes-8-1-3" >}})
- [Release notes for 8.1.2]({{< relref "release-notes-8-1-2" >}})
- [Release notes for 8.1.1]({{< relref "release-notes-8-1-1" >}})

View File

@@ -0,0 +1,89 @@
+++
title = "Release notes for Grafana 8.2.0-beta1"
[_build]
list = false
+++
<!-- Auto generated by update changelog github action -->
# Release notes for Grafana 8.2.0-beta1
### Features and enhancements
- **AccessControl:** Introduce new permissions to restrict access for reloading provisioning configuration. [#38906](https://github.com/grafana/grafana/pull/38906), [@vtorosyan](https://github.com/vtorosyan)
- **Alerting:** Add UI to edit Cortex/Loki namespace, group names, and group evaluation interval. [#38543](https://github.com/grafana/grafana/pull/38543), [@domasx2](https://github.com/domasx2)
- **Alerting:** Add a Test button to test contact point. [#37475](https://github.com/grafana/grafana/pull/37475), [@domasx2](https://github.com/domasx2)
- **Alerting:** Allow creating/editing recording rules for Loki and Cortex. [#38064](https://github.com/grafana/grafana/pull/38064), [@domasx2](https://github.com/domasx2)
- **Alerting:** Sort notification channels by name to make them easier to locate. [#37426](https://github.com/grafana/grafana/pull/37426), [@jstangroome](https://github.com/jstangroome)
- **AzureMonitor:** Add data links to deep link to Azure Portal Azure Resource Graph. [#35591](https://github.com/grafana/grafana/pull/35591), [@shuotli](https://github.com/shuotli)
- **AzureMonitor:** Add support for annotations from Azure Monitor Metrics and Azure Resource Graph services. [#37633](https://github.com/grafana/grafana/pull/37633), [@joshhunt](https://github.com/joshhunt)
- **AzureMonitor:** Show error message when subscriptions request fails in ConfigEditor. [#37837](https://github.com/grafana/grafana/pull/37837), [@joshhunt](https://github.com/joshhunt)
- **Chore:** Update to Golang 1.16.7. [#38604](https://github.com/grafana/grafana/pull/38604), [@dsotirakis](https://github.com/dsotirakis)
- **CloudWatch Logs:** Add link to X-Ray data source for trace IDs in logs. [#39135](https://github.com/grafana/grafana/pull/39135), [@aocenas](https://github.com/aocenas)
- **CloudWatch Logs:** Disable query path using websockets (Live) feature. [#39231](https://github.com/grafana/grafana/pull/39231), [@aocenas](https://github.com/aocenas)
- **CloudWatch/Logs:** Don't group dataframes for non time series queries. [#37998](https://github.com/grafana/grafana/pull/37998), [@aocenas](https://github.com/aocenas)
- **Cloudwatch:** Migrate queries that use multiple stats to one query per stat. [#36925](https://github.com/grafana/grafana/pull/36925), [@sunker](https://github.com/sunker)
- **Dashboard:** Keep live timeseries moving left (v2). [#37769](https://github.com/grafana/grafana/pull/37769), [@ryantxu](https://github.com/ryantxu)
- **Datasources:** Introduce `response_limit` for datasource responses. [#38962](https://github.com/grafana/grafana/pull/38962), [@dsotirakis](https://github.com/dsotirakis)
- **Explore:** Add filter by trace or span ID to `trace to logs` feature. [#38943](https://github.com/grafana/grafana/pull/38943), [@connorlindsey](https://github.com/connorlindsey)
- **Explore:** Download traces as JSON in Explore Inspector. [#38614](https://github.com/grafana/grafana/pull/38614), [@connorlindsey](https://github.com/connorlindsey)
- **Explore:** Reuse Dashboard's QueryRows component. [#38942](https://github.com/grafana/grafana/pull/38942), [@Elfo404](https://github.com/Elfo404)
- **Explore:** Support custom display label for derived fields buttons for Loki datasource. [#37273](https://github.com/grafana/grafana/pull/37273), [@connorlindsey](https://github.com/connorlindsey)
- **Grafana UI:** Update monaco-related dependencies. [#39027](https://github.com/grafana/grafana/pull/39027), [@gabor](https://github.com/gabor)
- **Graphite:** Deprecate browser access mode. [#38783](https://github.com/grafana/grafana/pull/38783), [@ifrost](https://github.com/ifrost)
- **InfluxDB:** Improve handling of intervals in alerting. [#37588](https://github.com/grafana/grafana/pull/37588), [@gabor](https://github.com/gabor)
- **InfluxDB:** InfluxQL query editor: Handle unusual characters in tag values better. [#39170](https://github.com/grafana/grafana/pull/39170), [@gabor](https://github.com/gabor)
- **Jaeger:** Add ability to upload JSON file for trace data. [#37205](https://github.com/grafana/grafana/pull/37205), [@zoltanbedi](https://github.com/zoltanbedi)
- **LibraryElements:** Enable specifying UID for new and existing library elements. [#39019](https://github.com/grafana/grafana/pull/39019), [@hugohaggmark](https://github.com/hugohaggmark)
- **LibraryPanels:** Remove library panel icon from the panel header so you can no longer tell that a panel is a library panel from the dashboard view. [#38749](https://github.com/grafana/grafana/pull/38749), [@hugohaggmark](https://github.com/hugohaggmark)
- **Logs panel:** Scroll to the bottom on page refresh when sorting in ascending order. [#37634](https://github.com/grafana/grafana/pull/37634), [@ivanahuckova](https://github.com/ivanahuckova)
- **Loki:** Add fuzzy search to label browser. [#36864](https://github.com/grafana/grafana/pull/36864), [@connorlindsey](https://github.com/connorlindsey)
- **Navigation:** Implement active state for items in the Sidemenu. [#39030](https://github.com/grafana/grafana/pull/39030), [@ashharrison90](https://github.com/ashharrison90)
- **Packaging:** Add stricter systemd unit options. [#38109](https://github.com/grafana/grafana/pull/38109), [@erdnaxe](https://github.com/erdnaxe)
- **Packaging:** Update PID file location from `/var/run` to `/run`. [#35739](https://github.com/grafana/grafana/pull/35739), [@MichaIng](https://github.com/MichaIng)
- **Plugins:** Add Hide OAuth Forward config option. [#36306](https://github.com/grafana/grafana/pull/36306), [@wbrowne](https://github.com/wbrowne)
- **Postgres/MySQL/MSSQL:** Add setting to limit the maximum number of rows processed. [#38986](https://github.com/grafana/grafana/pull/38986), [@marefr](https://github.com/marefr)
- **Prometheus:** Add browser access mode deprecation warning. [#37578](https://github.com/grafana/grafana/pull/37578), [@ivanahuckova](https://github.com/ivanahuckova)
- **Prometheus:** Add interpolation for built-in-time variables to backend. [#39051](https://github.com/grafana/grafana/pull/39051), [@ivanahuckova](https://github.com/ivanahuckova)
- **Tempo:** Add ability to upload trace data in JSON format. [#37407](https://github.com/grafana/grafana/pull/37407), [@zoltanbedi](https://github.com/zoltanbedi)
- **TimeSeries/XYChart:** Allow grid lines visibility control in XYChart and TimeSeries panels. [#38502](https://github.com/grafana/grafana/pull/38502), [@dprokop](https://github.com/dprokop)
- **Transformations:** Convert field types to time string number or boolean. [#38517](https://github.com/grafana/grafana/pull/38517), [@nikki-kiga](https://github.com/nikki-kiga)
- **Value mappings:** Add regular-expression based value mapping. [#38931](https://github.com/grafana/grafana/pull/38931), [@mcdee](https://github.com/mcdee)
- **Zipkin:** Add ability to upload trace JSON. [#37483](https://github.com/grafana/grafana/pull/37483), [@zoltanbedi](https://github.com/zoltanbedi)
### Bug fixes
- **Admin:** Prevent user from deleting user's current/active organization. [#38056](https://github.com/grafana/grafana/pull/38056), [@idafurjes](https://github.com/idafurjes)
- **LibraryPanels:** Fix library panel getting saved in the dashboard's folder. [#38978](https://github.com/grafana/grafana/pull/38978), [@hugohaggmark](https://github.com/hugohaggmark)
- **OAuth:** Make generic teams URL and JMES path configurable. [#37233](https://github.com/grafana/grafana/pull/37233), [@djairhogeuens](https://github.com/djairhogeuens)
- **QueryEditor:** Fix broken copy-paste for mouse middle-click (#39117). [#39117](https://github.com/grafana/grafana/pull/39117), [@glintik](https://github.com/glintik)
- **Thresholds:** Fix undefined color in "Add threshold". [#39113](https://github.com/grafana/grafana/pull/39113), [@glintik](https://github.com/glintik)
- **Timeseries:** Add wide-to-long, and fix multi-frame output. [#38670](https://github.com/grafana/grafana/pull/38670), [@ryantxu](https://github.com/ryantxu)
- **TooltipPlugin:** Fix behavior of Shared Crosshair when Tooltip is set to All. [#37285](https://github.com/grafana/grafana/pull/37285), [@nikki-kiga](https://github.com/nikki-kiga)
### Breaking changes
The `monaco-editor` dependency in `grafana-ui` has been updated to a newer version (`0.27.0`), which is not completely backward compatible with the old version (`0.21.2`). The backward incompatible changes are fairly small, but they do exist, so if your code accesses the raw monaco-objects through the `grafana-ui` package, please check the [monaco-editor changelog](https://github.com/microsoft/monaco-editor/blob/main/CHANGELOG.md) and apply any necessary changes. Issue [#39027](https://github.com/grafana/grafana/issues/39027)
The mandatory `css` prop in `grafana/ui` components has been removed.
Previous versions of `grafana/ui` components were typed incorrectly due to a dependency mismatch between emotion 10 and 11 causing a `css` prop to be added to components that extended react types.
Issue [#38078](https://github.com/grafana/grafana/issues/38078)
Panel queries and/or annotation queries that used more than one statistic will be converted into one query/annotation per statistic. In case an alerting rule was based on a query row that had more than one statistic, it would now be based only on the first statistic for that query row. New alerting rules will not be created for migrated queries. Please note that in most cases it would not make sense to have an alerting rule that is based on multiple statistics anyway. Issue [#36925](https://github.com/grafana/grafana/issues/36925)
### Deprecations
`getHighlighterExpressions` in datasource APIs ( used to highlight logs while editing queries) has been deprecated and will be removed in a future release.
# Deprecation notice
`ExploreQueryFieldProps` interface for query editors has been deprecated and will be removed in a future release. Use `QueryEditorProps` instead. Issue [#38942](https://github.com/grafana/grafana/issues/38942)
### Plugin development fixes & changes
- **Grafana UI:** Fix TS error property `css` is missing in type. [#38078](https://github.com/grafana/grafana/pull/38078), [@jackw](https://github.com/jackw)
### Grafana 8 alerts fixes
- **Organisation level isolation:** The fix for organization level isolation introduced a [new migration flow](https://github.com/grafana/grafana/pull/37414) that deletes all Grafana 8 alerting data and migrates the dashboard alerts to the new system again so that an Alertmanager configuration is created properly for each organization. It removes any manually created (or modified) Grafana 8 alerts or Alertmanager configuration after upgrading.

View File

@@ -0,0 +1,210 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 321,
"links": [],
"liveNow": false,
"panels": [
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 6,
"options": {
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"showThresholdLabels": false,
"showThresholdMarkers": true,
"text": {}
},
"pluginVersion": "8.3.0-pre",
"title": "Gauge Example",
"type": "gauge"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "thresholds"
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 8
},
"id": 4,
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"text": {},
"textMode": "auto"
},
"pluginVersion": "8.3.0-pre",
"title": "Stat",
"type": "stat"
},
{
"datasource": null,
"fieldConfig": {
"defaults": {
"color": {
"mode": "palette-classic"
},
"custom": {
"axisLabel": "",
"axisPlacement": "auto",
"barAlignment": 0,
"drawStyle": "line",
"fillOpacity": 0,
"gradientMode": "none",
"hideFrom": {
"legend": false,
"tooltip": false,
"viz": false
},
"lineInterpolation": "linear",
"lineWidth": 1,
"pointSize": 5,
"scaleDistribution": {
"type": "linear"
},
"showPoints": "auto",
"spanNulls": false,
"stacking": {
"group": "A",
"mode": "none"
},
"thresholdsStyle": {
"mode": "off"
}
},
"mappings": [],
"thresholds": {
"mode": "absolute",
"steps": [
{
"color": "green",
"value": null
},
{
"color": "red",
"value": 80
}
]
}
},
"overrides": []
},
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 16
},
"id": 2,
"options": {
"legend": {
"calcs": [],
"displayMode": "list",
"placement": "bottom"
},
"tooltip": {
"mode": "single"
}
},
"title": "Time series example",
"type": "timeseries"
}
],
"refresh": false,
"schemaVersion": 31,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "2021-09-01T04:00:00.000Z",
"to": "2021-09-15T04:00:00.000Z"
},
"timepicker": {},
"timezone": "",
"title": "E2E Test - Import Dashboard",
"uid": "kquZN5H7k",
"version": 4
}

View File

@@ -12,7 +12,7 @@ const addDataSource = () => {
e2e.components.DataSourcePicker.container()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').click({ force: true });
e2e.components.DataSourcePicker.input().should('be.visible').click({ force: true });
});
e2e().contains('gdev-tempo').scrollIntoView().should('be.visible').click();
@@ -53,7 +53,7 @@ describe('Exemplars', () => {
e2e.components.DataSourcePicker.container()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').click();
e2e.components.DataSourcePicker.input().should('be.visible').click();
});
e2e().contains(dataSourceName).scrollIntoView().should('be.visible').click();
e2e.components.TimePicker.openButton().click();

View File

@@ -1,122 +1,12 @@
import { e2e } from '@grafana/e2e';
e2e.scenario({
describeName: 'Import Dashboard Test',
itName: 'Ensure you can import a dashboard',
describeName: 'Import Dashboards Test',
itName: 'Ensure you can import a number of json test dashboards from a specific test directory',
addScenarioDataSource: false,
addScenarioDashBoard: false,
skipScenario: false,
scenario: () => {
e2e.flows.importDashboard(TEST_DASHBOARD);
e2e.flows.importDashboards('/dashboards', 1000);
},
});
const TEST_DASHBOARD = {
annotations: {
list: [
{
builtIn: 1,
datasource: '-- Grafana --',
enable: true,
hide: true,
iconColor: 'rgba(0, 211, 255, 1)',
name: 'Annotations & Alerts',
type: 'dashboard',
},
],
},
editable: true,
gnetId: null,
graphTooltip: 0,
id: 74,
links: [],
panels: [
{
datasource: null,
fieldConfig: {
defaults: {
color: {
mode: 'palette-classic',
},
custom: {
axisLabel: '',
axisPlacement: 'auto',
barAlignment: 0,
drawStyle: 'line',
fillOpacity: 0,
gradientMode: 'none',
hideFrom: {
legend: false,
tooltip: false,
viz: false,
},
lineInterpolation: 'linear',
lineWidth: 1,
pointSize: 5,
scaleDistribution: {
type: 'linear',
},
showPoints: 'auto',
spanNulls: false,
stacking: {
group: 'A',
mode: 'none',
},
thresholdsStyle: {
mode: 'off',
},
},
mappings: [],
thresholds: {
mode: 'absolute',
steps: [
{
color: 'green',
value: null,
},
{
color: 'red',
value: 80,
},
],
},
},
overrides: [],
},
gridPos: {
h: 9,
w: 12,
x: 0,
y: 0,
},
id: 2,
options: {
legend: {
calcs: [],
displayMode: 'list',
placement: 'bottom',
},
tooltip: {
mode: 'single',
},
},
title: 'Panel Title',
type: 'timeseries',
},
],
schemaVersion: 30,
style: 'dark',
tags: [],
templating: {
list: [],
},
time: {
from: '2021-06-30T04:00:00.000Z',
to: '2021-07-02T03:59:59.000Z',
},
timepicker: {},
timezone: '',
title: 'An imported dashboard for e2e tests',
uid: '6V0Nzyz7k',
version: 1,
};

View File

@@ -28,6 +28,7 @@ e2e.scenario({
e2e.components.QueryTab.content().should('be.visible');
e2e.components.TransformTab.content().should('not.exist');
e2e.components.AlertTab.content().should('not.exist');
e2e.components.PanelAlertTabContent.content().should('not.exist');
// Bottom pane tabs
// Can change to Transform tab
@@ -38,6 +39,7 @@ e2e.scenario({
e2e.components.Transforms.card('Merge').scrollIntoView().should('be.visible');
e2e.components.QueryTab.content().should('not.exist');
e2e.components.AlertTab.content().should('not.exist');
e2e.components.PanelAlertTabContent.content().should('not.exist');
// Can change to Alerts tab (graph panel is the default vis so the alerts tab should be rendered)
e2e.components.Tab.title('Alert').should('be.visible').click();
@@ -47,6 +49,7 @@ e2e.scenario({
e2e.components.AlertTab.content().should('be.visible');
e2e.components.QueryTab.content().should('not.exist');
e2e.components.TransformTab.content().should('not.exist');
e2e.components.PanelAlertTabContent.content().should('not.exist');
e2e.components.Tab.title('Query').should('be.visible').click();
});

View File

@@ -11,7 +11,7 @@ e2e.scenario({
e2e.components.DataSourcePicker.container()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').click();
e2e.components.DataSourcePicker.input().should('be.visible').click();
});
cy.contains('gdev-prometheus').scrollIntoView().should('be.visible').click();

View File

@@ -50,8 +50,11 @@ e2e.scenario({
e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('p2').should('be.visible').click();
e2e.components.PageToolbar.container().click();
e2e.components.DashboardLinks.dropDown().should('be.visible').click().wait('@tagsTemplatingSearch');
e2e.components.DashboardLinks.dropDown()
.scrollIntoView()
.should('be.visible')
.click()
.wait('@tagsTemplatingSearch');
// verify all links, should have p2 value
verifyLinks('p2');

View File

@@ -14,7 +14,7 @@ describe('Trace view', () => {
e2e.components.DataSourcePicker.container()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').click();
e2e.components.DataSourcePicker.input().should('be.visible').click();
});
e2e().contains('gdev-jaeger').scrollIntoView().should('be.visible').click();

View File

@@ -85,7 +85,7 @@ describe('Variables - Add variable', () => {
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').type('gdev-testdata').type('{enter}');
e2e.components.DataSourcePicker.input().should('be.visible').type('gdev-testdata').type('{enter}');
});
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput()
@@ -139,7 +139,7 @@ describe('Variables - Add variable', () => {
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsDataSourceSelect()
.should('be.visible')
.within(() => {
e2e.components.Select.input().should('be.visible').type('gdev-testdata').type('{enter}');
e2e.components.DataSourcePicker.input().should('be.visible').type('gdev-testdata').type('{enter}');
});
e2e.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsQueryInput()

View File

@@ -3,5 +3,6 @@
"types": ["cypress"]
},
"extends": "../../tsconfig.json",
"include": ["**/*.ts", "../../packages/grafana-e2e/cypress/support/index.d.ts"]
"include": ["**/*.ts", "../../packages/grafana-e2e/cypress/support/index.d.ts"],
"resolveJsonModule": true
}

View File

@@ -2,16 +2,15 @@ package grafana
import (
"embed"
"io/fs"
)
// CoreSchema embeds all core CUE files, which live in packages/grafana-schema/src
//
//go:embed cue.mod cue packages/grafana-schema/src/schema/*.cue packages/grafana-schema/src/scuemata/*/*.cue
//go:embed cue.mod cue packages/grafana-schema/src/schema/*.cue packages/grafana-schema/src/scuemata/*/*.cue packages/grafana-schema/src/scuemata/*/*/*.cue
var CoreSchema embed.FS
// PluginSchema embeds all expected plugin CUE files and plugin metadata from
// within the public/app/plugins subdirectory.
//
//go:embed public/app/plugins/*/*/*.cue public/app/plugins/*/*/plugin.json
var base embed.FS
// PluginSchema embeds all CUE files within the public/ subdirectory.
var PluginSchema, _ = fs.Sub(base, "public/app/plugins")
var PluginSchema embed.FS

5
go.mod
View File

@@ -35,6 +35,7 @@ require (
github.com/go-kit/kit v0.11.0
github.com/go-macaron/binding v0.0.0-20190806013118-0b4f37bab25b
github.com/go-openapi/strfmt v0.20.1
github.com/go-redis/redis/v8 v8.11.3
github.com/go-sourcemap/sourcemap v2.1.3+incompatible
github.com/go-sql-driver/mysql v1.6.0
github.com/go-stack/stack v1.8.0
@@ -49,7 +50,7 @@ require (
github.com/gorilla/websocket v1.4.2
github.com/gosimple/slug v1.9.0
github.com/grafana/grafana-aws-sdk v0.7.0
github.com/grafana/grafana-plugin-sdk-go v0.113.0
github.com/grafana/grafana-plugin-sdk-go v0.114.0
github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/hashicorp/go-hclog v0.16.1
@@ -112,7 +113,6 @@ require (
gopkg.in/ldap.v3 v3.1.0
gopkg.in/macaron.v1 v1.4.0
gopkg.in/mail.v2 v2.3.1
gopkg.in/redis.v5 v5.2.9
gopkg.in/square/go-jose.v2 v2.5.1
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
@@ -141,6 +141,7 @@ require (
github.com/cockroachdb/apd/v2 v2.0.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
github.com/deepmap/oapi-codegen v1.3.13 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect

23
go.sum
View File

@@ -461,6 +461,7 @@ github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/
github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/go-sip13 v0.0.0-20190329191031-25c5027a8c7b/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -759,9 +760,12 @@ github.com/go-openapi/validate v0.20.2 h1:AhqDegYV3J3iQkMPJSXkvzymHKMTw0BST3RK3h
github.com/go-openapi/validate v0.20.2/go.mod h1:e7OJoKNgd0twXZwIn0A43tHbvIcr/rZIVCbJBpTUoY0=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-redis/redis/v8 v8.0.0-beta.10.0.20200905143926-df7fe4e2ce72/go.mod h1:CJP1ZIHwhosNYwIdaHPZK9vHsM3+roNBaZ7U9Of1DXc=
github.com/go-redis/redis/v8 v8.2.3/go.mod h1:ysgGY09J/QeDYbu3HikWEIPCwaeOkuNoTgKayTEaEOw=
github.com/go-redis/redis/v8 v8.11.3 h1:GCjoYp8c+yQTJfc0n69iwSiHjvuAdruxl7elnZCxgt8=
github.com/go-redis/redis/v8 v8.11.3/go.mod h1:xNJ9xDG09FsIPwh3bWdk+0oDWHbtF9rPN0F/oD9XeKc=
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 h1:JVrqSeQfdhYRFk24TvhTZWU0q8lfCojxZQFi3Ou7+uY=
github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
@@ -773,6 +777,7 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y=
@@ -1020,8 +1025,8 @@ github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036/go.mod h1:xbL0r
github.com/grafana/grafana-aws-sdk v0.7.0 h1:D+Lhxi3P/7vpyDHUK/fdX9bL2mRz8hLG04ucNf1E02o=
github.com/grafana/grafana-aws-sdk v0.7.0/go.mod h1:+pPo5U+pX0zWimR7YBc7ASeSQfbRkcTyQYqMiAj7G5U=
github.com/grafana/grafana-plugin-sdk-go v0.79.0/go.mod h1:NvxLzGkVhnoBKwzkst6CFfpMFKwAdIUZ1q8ssuLeF60=
github.com/grafana/grafana-plugin-sdk-go v0.113.0 h1:X46np4UNgM0YLhxC0oLa2q7WOHdU5T/oppZ+XlYusMk=
github.com/grafana/grafana-plugin-sdk-go v0.113.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/grafana-plugin-sdk-go v0.114.0 h1:9I55IXw7mOT71tZ/pdqCaWGz8vxfz31CXjaDtBV9ZBo=
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103 h1:qCmofFVwQR9QnsinstVqI1NPLMVl33jNCnOCXEAVn6E=
github.com/grafana/loki v1.6.2-0.20210520072447-15d417efe103/go.mod h1:GHIsn+EohCChsdu5YouNZewqLeV9L2FNw4DEJU3P9qE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
@@ -1567,8 +1572,9 @@ github.com/newrelic/newrelic-telemetry-sdk-go v0.2.0/go.mod h1:G9MqE/cHGv3Hx3qpY
github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsqio/go-nsq v1.0.7/go.mod h1:XP5zaUs3pqf+Q71EqUJs3HYfBIqfK6G83WQMdNN+Ito=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
@@ -1594,8 +1600,9 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -1604,8 +1611,9 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/openconfig/gnmi v0.0.0-20180912164834-33a1865c3029/go.mod h1:t+O9It+LKzfOAhKTT5O0ehDix+MTqbtT0T9t+7zzOvc=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@@ -2356,6 +2364,7 @@ golang.org/x/net v0.0.0-20210324051636-2c4c8ecb7826/go.mod h1:RBQZq4jEuRlivfhVLd
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -2500,6 +2509,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -2652,6 +2662,7 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201119054027-25dc3e1ccc3c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201226215659-b1c90890d22a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -2898,8 +2909,6 @@ gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/olivere/elastic.v5 v5.0.70/go.mod h1:FylZT6jQWtfHsicejzOm3jIMVPOAksa80i3o+6qtQRk=
gopkg.in/redis.v5 v5.2.9 h1:MNZYOLPomQzZMfpN3ZtD1uyJ2IDonTTlxYiV/pEApiw=
gopkg.in/redis.v5 v5.2.9/go.mod h1:6gtv0/+A4iM08kdRfocWYB3bLX2tebpNtfKlFT6H4mY=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=

View File

@@ -1,6 +1,8 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"packages": ["packages/*"],
"version": "8.2.0-pre"
"packages": [
"packages/*"
],
"version": "8.2.0-beta.2"
}

View File

@@ -3,7 +3,7 @@
"license": "AGPL-3.0-only",
"private": true,
"name": "grafana",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"repository": "github:grafana/grafana",
"scripts": {
"api-tests": "jest --notify --watch --config=devenv/e2e-api-tests/jest.js",
@@ -290,7 +290,7 @@
"ol": "6.7.0",
"papaparse": "5.3.0",
"pluralize": "^8.0.0",
"prismjs": "1.24.0",
"prismjs": "1.25.0",
"prop-types": "15.7.2",
"rc-cascader": "1.5.0",
"re-resizable": "^6.2.0",
@@ -329,7 +329,6 @@
"whatwg-fetch": "3.1.0"
},
"resolutions": {
"caniuse-db": "1.0.30000772",
"underscore": "1.12.1"
},
"workspaces": {

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/data",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana Data Library",
"keywords": [
"typescript"
@@ -23,7 +23,7 @@
},
"dependencies": {
"@braintree/sanitize-url": "5.0.2",
"@grafana/schema": "8.2.0-pre",
"@grafana/schema": "8.2.0-beta.2",
"@types/d3-interpolate": "^1.3.1",
"date-fns": "2.21.3",
"eventemitter3": "4.0.7",

View File

@@ -135,4 +135,71 @@ describe('DateMath', () => {
expect(date!.valueOf()).toEqual(dateTime([2014, 1, 3]).valueOf());
});
});
describe('Round to fiscal start/end', () => {
it('Should round to start of fiscal year when datetime is the same year as the start of the fiscal year', () => {
let date = dateMath.roundToFiscal(1, dateTime([2021, 3, 5]), 'y', false);
let expected = dateTime([2021, 1, 1]);
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to start of fiscal year when datetime is the next year from the start of the fiscal year', () => {
let date = dateMath.roundToFiscal(1, dateTime([2022, 0, 2]), 'y', false);
let expected = dateTime([2021, 1, 1]);
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to start of fiscal year when datetime is on a leap day', () => {
let date = dateMath.roundToFiscal(1, dateTime([2020, 1, 29]), 'y', false);
let expected = dateTime([2020, 1, 1]);
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to end of fiscal year when datetime is the same year as the start of the fiscal year', () => {
let date = dateMath.roundToFiscal(1, dateTime([2021, 5, 2]), 'y', true);
let expected = dateTime([2022, 0, 1]).endOf('M');
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to end of fiscal year when datetime is the next year from the start of the fiscal year', () => {
let date = dateMath.roundToFiscal(1, dateTime([2022, 0, 1]), 'y', true);
let expected = dateTime([2022, 0, 1]).endOf('M');
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to end of fiscal year when datetime is on a leap day', () => {
let date = dateMath.roundToFiscal(1, dateTime([2020, 1, 29]), 'y', true);
let expected = dateTime([2021, 0, 1]).endOf('M');
expect(date!.valueOf()).toEqual(expected.valueOf());
});
//fq1 = 2021-02-01 - 2021-04-30
//fq2 = 2021-05-01 - 2021-07-31
//fq4 = 2021-08-01 - 2021-10-31
//fq5 = 2021-11-01 - 2022-01-31
it('Should round to start of q2 when one month into q2', () => {
let date = dateMath.roundToFiscal(1, dateTime([2021, 6, 1]), 'Q', false);
let expected = dateTime([2021, 4, 1]);
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to start of q4 when datetime is in next year from fiscal year start', () => {
let date = dateMath.roundToFiscal(1, dateTime([2022, 0, 1]), 'Q', false);
let expected = dateTime([2021, 10, 1]);
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to end of q2 when one month into q2', () => {
let date = dateMath.roundToFiscal(1, dateTime([2021, 6, 1]), 'Q', true);
let expected = dateTime([2021, 6, 1]).endOf('M');
expect(date!.valueOf()).toEqual(expected.valueOf());
});
it('Should round to end of q4 when datetime is in next year from fiscal year start', () => {
let date = dateMath.roundToFiscal(1, dateTime([2022, 0, 1]), 'Q', true);
let expected = dateTime([2022, 0, 31]).endOf('M');
expect(date!.valueOf()).toEqual(expected.valueOf());
});
});
});

View File

@@ -2,7 +2,7 @@ import { includes, isDate } from 'lodash';
import { DateTime, dateTime, dateTimeForTimeZone, ISO_8601, isDateTime, DurationUnit } from './moment_wrapper';
import { TimeZone } from '../types/index';
const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's', 'Q'];
export function isMathString(text: string | DateTime | Date): boolean {
if (!text) {
@@ -26,7 +26,8 @@ export function isMathString(text: string | DateTime | Date): boolean {
export function parse(
text?: string | DateTime | Date | null,
roundUp?: boolean,
timezone?: TimeZone
timezone?: TimeZone,
fiscalYearStartMonth?: number
): DateTime | undefined {
if (!text) {
return undefined;
@@ -67,7 +68,7 @@ export function parse(
return time;
}
return parseDateMath(mathString, time, roundUp);
return parseDateMath(mathString, time, roundUp, fiscalYearStartMonth);
}
}
@@ -96,7 +97,12 @@ export function isValid(text: string | DateTime): boolean {
* @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit.
*/
// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any`
export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined {
export function parseDateMath(
mathString: string,
time: any,
roundUp?: boolean,
fiscalYearStartMonth = 0
): DateTime | undefined {
const strippedMathString = mathString.replace(/\s/g, '');
const dateTime = time;
let i = 0;
@@ -107,6 +113,7 @@ export function parseDateMath(mathString: string, time: any, roundUp?: boolean):
let type;
let num;
let unit;
let isFiscal = false;
if (c === '/') {
type = 0;
@@ -121,7 +128,7 @@ export function parseDateMath(mathString: string, time: any, roundUp?: boolean):
if (isNaN(parseInt(strippedMathString.charAt(i), 10))) {
num = 1;
} else if (strippedMathString.length === 2) {
num = strippedMathString.charAt(i);
num = parseInt(strippedMathString.charAt(i), 10);
} else {
const numFrom = i;
while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) {
@@ -141,14 +148,27 @@ export function parseDateMath(mathString: string, time: any, roundUp?: boolean):
}
unit = strippedMathString.charAt(i++);
if (unit === 'f') {
unit = strippedMathString.charAt(i++);
isFiscal = true;
}
if (!includes(units, unit)) {
return undefined;
} else {
if (type === 0) {
if (roundUp) {
dateTime.endOf(unit);
if (isFiscal) {
roundToFiscal(fiscalYearStartMonth, dateTime, unit, roundUp);
} else {
dateTime.endOf(unit);
}
} else {
dateTime.startOf(unit);
if (isFiscal) {
roundToFiscal(fiscalYearStartMonth, dateTime, unit, roundUp);
} else {
dateTime.startOf(unit);
}
}
} else if (type === 1) {
dateTime.add(num, unit);
@@ -159,3 +179,24 @@ export function parseDateMath(mathString: string, time: any, roundUp?: boolean):
}
return dateTime;
}
export function roundToFiscal(fyStartMonth: number, dateTime: any, unit: string, roundUp: boolean | undefined) {
switch (unit) {
case 'y':
if (roundUp) {
roundToFiscal(fyStartMonth, dateTime, unit, false).add(11, 'M').endOf('M');
} else {
dateTime.subtract((dateTime.month() - fyStartMonth + 12) % 12, 'M').startOf('M');
}
return dateTime;
case 'Q':
if (roundUp) {
roundToFiscal(fyStartMonth, dateTime, unit, false).add(2, 'M').endOf('M');
} else {
dateTime.subtract((dateTime.month() - fyStartMonth + 3) % 3, 'M').startOf('M');
}
return dateTime;
default:
return undefined;
}
}

View File

@@ -1,4 +1,10 @@
import { intervalToAbbreviatedDurationString, addDurationToDate, parseDuration } from './durationutil';
import {
intervalToAbbreviatedDurationString,
addDurationToDate,
parseDuration,
isValidDuration,
isValidGoDuration,
} from './durationutil';
describe('Duration util', () => {
describe('intervalToAbbreviatedDurationString', () => {
@@ -20,4 +26,28 @@ describe('Duration util', () => {
expect(parseDuration(durationString)).toEqual({ months: '3', minutes: '4' });
});
});
describe('isValidDuration', () => {
it('valid duration string returns true', () => {
const durationString = '3M 5d 20m';
expect(isValidDuration(durationString)).toEqual(true);
});
it('invalid duration string returns false', () => {
const durationString = '3M 6v 5b 4m';
expect(isValidDuration(durationString)).toEqual(false);
});
});
describe('isValidGoDuration', () => {
it('valid duration string returns true', () => {
const durationString = '3h 4m 1s 2ms 3us 5ns';
expect(isValidGoDuration(durationString)).toEqual(true);
});
it('invalid duration string returns false', () => {
const durationString = '3M 6v 5b 4m';
expect(isValidGoDuration(durationString)).toEqual(false);
});
});
});

View File

@@ -13,7 +13,7 @@ const durationMap: { [key in Required<keyof Duration>]: string[] } = {
};
/**
* intervalToAbbreviatedDurationString convers interval to readable duration string
* intervalToAbbreviatedDurationString converts interval to readable duration string
*
* @param interval - interval to convert
* @param includeSeconds - optional, default true. If false, will not include seconds unless interval is less than 1 minute
@@ -85,3 +85,55 @@ export function durationToMilliseconds(duration: Duration): number {
export function isValidDate(dateString: string): boolean {
return !isNaN(Date.parse(dateString));
}
/**
* isValidDuration returns true if the given string can be parsed into a valid Duration object, false otherwise
*
* @param durationString - string representation of a duration
*
* @public
*/
export function isValidDuration(durationString: string): boolean {
for (const value of durationString.trim().split(' ')) {
const match = value.match(/(\d+)(.+)/);
if (match === null || match.length !== 3) {
return false;
}
const key = Object.entries(durationMap).find(([_, abbreviations]) => abbreviations?.includes(match[2]))?.[0];
if (!key) {
return false;
}
}
return true;
}
/**
* isValidGoDuration returns true if the given string can be parsed into a valid Duration object based on
* Go's time.parseDuration, false otherwise.
*
* Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
*
* Go docs: https://pkg.go.dev/time#ParseDuration
*
* @param durationString - string representation of a duration
*
* @internal
*/
export function isValidGoDuration(durationString: string): boolean {
const timeUnits = ['h', 'm', 's', 'ms', 'us', 'µs', 'ns'];
for (const value of durationString.trim().split(' ')) {
const match = value.match(/(\d+)(.+)/);
if (match === null || match.length !== 3) {
return false;
}
const isValidUnit = timeUnits.includes(match[2]);
if (!isValidUnit) {
return false;
}
}
return true;
}

View File

@@ -19,6 +19,7 @@ export interface DateTimeOptionsWhenParsing extends DateTimeOptions {
* the returned DateTime value will be 06:00:00.
*/
roundUp?: boolean;
fiscalYearStartMonth?: number;
}
type DateTimeParser<T extends DateTimeOptions = DateTimeOptions> = (value: DateTimeInput, options?: T) => DateTime;
@@ -56,7 +57,7 @@ const parseString = (value: string, options?: DateTimeOptionsWhenParsing): DateT
return moment() as DateTime;
}
const parsed = parse(value, options?.roundUp, options?.timeZone);
const parsed = parse(value, options?.roundUp, options?.timeZone, options?.fiscalYearStartMonth);
return parsed || (moment() as DateTime);
}

View File

@@ -40,7 +40,9 @@ const rangeOptions: TimeOption[] = [
},
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week' },
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month' },
{ from: 'now-1Q/fQ', to: 'now-1Q/fQ', display: 'Previous fiscal quarter' },
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year' },
{ from: 'now-1y/fy', to: 'now-1y/fy', display: 'Previous fiscal year' },
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes' },
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes' },
@@ -58,6 +60,10 @@ const rangeOptions: TimeOption[] = [
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
{ from: 'now-2y', to: 'now', display: 'Last 2 years' },
{ from: 'now-5y', to: 'now', display: 'Last 5 years' },
{ from: 'now/fQ', to: 'now', display: 'This fiscal quarter so far' },
{ from: 'now/fQ', to: 'now/fQ', display: 'This fiscal quarter' },
{ from: 'now/fy', to: 'now', display: 'This fiscal year so far' },
{ from: 'now/fy', to: 'now/fy', display: 'This fiscal year' },
];
const hiddenRangeOptions: TimeOption[] = [
@@ -192,9 +198,9 @@ export const describeTimeRangeAbbreviation = (range: TimeRange, timeZone?: TimeZ
return parsed ? timeZoneAbbrevation(parsed, { timeZone }) : '';
};
export const convertRawToRange = (raw: RawTimeRange, timeZone?: TimeZone): TimeRange => {
const from = dateTimeParse(raw.from, { roundUp: false, timeZone });
const to = dateTimeParse(raw.to, { roundUp: true, timeZone });
export const convertRawToRange = (raw: RawTimeRange, timeZone?: TimeZone, fiscalYearStartMonth?: number): TimeRange => {
const from = dateTimeParse(raw.from, { roundUp: false, timeZone, fiscalYearStartMonth });
const to = dateTimeParse(raw.to, { roundUp: true, timeZone, fiscalYearStartMonth });
if (dateMath.isMathString(raw.from) || dateMath.isMathString(raw.to)) {
return { from, to, raw };
@@ -210,6 +216,15 @@ function isRelativeTime(v: DateTime | string) {
return false;
}
export function isFiscal(timeRange: TimeRange) {
if (typeof timeRange.raw.from === 'string' && timeRange.raw.from.indexOf('f') > 0) {
return true;
} else if (typeof timeRange.raw.to === 'string' && timeRange.raw.to.indexOf('f') > 0) {
return true;
}
return false;
}
export function isRelativeTimeRange(raw: RawTimeRange): boolean {
return isRelativeTime(raw.from) || isRelativeTime(raw.to);
}

View File

@@ -157,6 +157,18 @@ describe('Format value', () => {
expect(result.text).toEqual('elva');
});
it('should return mapped color but use value format if no value mapping text specified', () => {
const valueMappings: ValueMapping[] = [
{ type: MappingType.RangeToText, options: { from: 1, to: 9, result: { color: '#FFF' } } },
];
const instance = getDisplayProcessorFromConfig({ decimals: 2, mappings: valueMappings });
const result = instance(5);
expect(result.color).toEqual('#FFF');
expect(result.text).toEqual('5.00');
});
it('should replace a matching regex', () => {
const valueMappings: ValueMapping[] = [
{ type: MappingType.RegexToText, options: { pattern: '([^.]*).example.com', result: { text: '$1' } } },

View File

@@ -79,14 +79,12 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP
value = dateTime(value).valueOf();
}
let text = toString(value);
let numeric = isStringUnit ? NaN : anyToNumber(value);
let prefix: string | undefined = undefined;
let suffix: string | undefined = undefined;
let color: string | undefined = undefined;
let percent: number | undefined = undefined;
let shouldFormat = true;
let text: string | undefined;
let prefix: string | undefined;
let suffix: string | undefined;
let color: string | undefined;
let percent: number | undefined;
if (mappings && mappings.length > 0) {
const mappingResult = getValueMappingResult(mappings, value);
@@ -99,13 +97,11 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP
if (mappingResult.color != null) {
color = options.theme.visualization.getColorByName(mappingResult.color);
}
shouldFormat = false;
}
}
if (!isNaN(numeric)) {
if (shouldFormat && !isBoolean(value)) {
if (text == null && !isBoolean(value)) {
const v = formatFunc(numeric, config.decimals, null, options.timeZone, showMs);
text = v.text;
suffix = v.suffix;
@@ -113,18 +109,21 @@ export function getDisplayProcessor(options?: DisplayProcessorOptions): DisplayP
}
// Return the value along with scale info
if (color === undefined) {
if (color == null) {
const scaleResult = scaleFunc(numeric);
color = scaleResult.color;
percent = scaleResult.percent;
}
}
if (!text) {
if (config.noValue) {
text = config.noValue;
} else {
text = ''; // No data?
if (text == null) {
text = toString(value);
if (!text) {
if (config.noValue) {
text = config.noValue;
} else {
text = ''; // No data?
}
}
}

View File

@@ -182,6 +182,27 @@ describe('PanelPlugin', () => {
expect(panel.fieldConfigDefaults.defaults.custom).toEqual(expectedDefaults);
});
test('throw error with array fieldConfigs', () => {
const panel = new PanelPlugin(() => {
return <div>Panel</div>;
});
panel.useFieldConfig({
useCustomConfig: (builder) => {
builder.addCustomEditor({
id: 'somethingUnique',
path: 'numericOption[0]',
name: 'Option editor',
description: 'Option editor description',
defaultValue: 10,
} as any);
},
});
expect(() => panel.fieldConfigRegistry).toThrowErrorMatchingInlineSnapshot(
`"[undefined] Field config paths do not support arrays: custom.somethingUnique"`
);
});
test('default values for nested paths', () => {
const panel = new PanelPlugin(() => {
return <div>Panel</div>;

View File

@@ -75,6 +75,13 @@ export function createFieldConfigRegistry<TFieldConfigOptions>(
}
}
// assert that field configs do not use array path syntax
for (const item of registry.list()) {
if (item.path.indexOf('[') > 0) {
throw new Error(`[${pluginName}] Field config paths do not support arrays: ${item.id}`);
}
}
return registry;
}

View File

@@ -96,7 +96,7 @@ class DarkColors implements ThemeColorsBase<Partial<ThemeRichColor>> {
text = {
primary: `rgb(${this.whiteBase})`,
secondary: `rgba(${this.whiteBase}, 0.65)`,
disabled: `rgba(${this.whiteBase}, 0.40)`,
disabled: `rgba(${this.whiteBase}, 0.57)`,
link: palette.blueDarkText,
maxContrast: palette.white,
};

View File

@@ -45,7 +45,6 @@ export enum GrafanaEdition {
export interface FeatureToggles {
[name: string]: boolean;
ngalert: boolean;
trimDefaults: boolean;
accesscontrol: boolean;
tempoServiceGraph: boolean;
@@ -132,4 +131,5 @@ export interface GrafanaConfig {
customTheme?: any;
geomapDefaultBaseLayer?: MapLayerOptions;
geomapDisableCustomBaseLayer?: boolean;
unifiedAlertingEnabled: boolean;
}

View File

@@ -0,0 +1,2 @@
export const GAUGE_DEFAULT_MINIMUM = 0;
export const GAUGE_DEFAULT_MAXIMUM = 100;

View File

@@ -1,3 +1,4 @@
export * from './constants';
export * from './data';
export * from './dataFrame';
export * from './dataFrameTypes';

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/e2e-selectors",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana End-to-End Test Selectors Library",
"keywords": [
"cli",

View File

@@ -202,6 +202,7 @@ export const Components = {
},
DataSourcePicker: {
container: 'Data source picker select container',
input: () => 'input[id="data-source-picker"]',
},
TimeZonePicker: {
container: 'Time zone picker select container',
@@ -243,4 +244,7 @@ export const Components = {
name: 'data-testid-import-dashboard-title',
submit: 'data-testid-import-dashboard-submit',
},
PanelAlertTabContent: {
content: 'Unified alert editor tab content',
},
};

View File

@@ -159,6 +159,7 @@ export const Pages = {
PluginPage: {
page: 'Plugin page',
signatureInfo: 'Plugin signature info',
disabledInfo: 'Plugin disabled info',
},
PlaylistForm: {
name: 'Playlist name',

View File

@@ -1,3 +1,6 @@
const fs = require('fs');
const path = require('path');
const compareScreenshots = require('./compareScreenshots');
const extendConfig = require('./extendConfig');
const readProvisions = require('./readProvisions');
@@ -12,6 +15,18 @@ module.exports = (on, config) => {
return null;
},
});
on('task', {
getJSONFilesFromDir: async ({ projectPath, relativePath }) => {
const directoryPath = path.join(projectPath, relativePath);
const jsonFiles = fs.readdirSync(directoryPath);
return jsonFiles
.filter((fileName) => /.json$/i.test(fileName))
.map((fileName) => {
const fileBuffer = fs.readFileSync(path.join(directoryPath, fileName));
return JSON.parse(fileBuffer);
});
},
});
// Always extend with this library's config and return for diffing
// @todo remove this when possible: https://github.com/cypress-io/cypress/issues/5674

View File

@@ -23,3 +23,10 @@ Cypress.Commands.add('readProvisions', (filePaths: string[]) => {
filePaths,
});
});
Cypress.Commands.add('getJSONFilesFromDir', (dirPath: string) => {
return cy.task('getJSONFilesFromDir', {
projectPath: Cypress.config().parentTestsFolder,
relativePath: dirPath,
});
});

View File

@@ -5,5 +5,6 @@ declare namespace Cypress {
compareScreenshots(config: CompareScreenshotsConfig | string): Chainable;
logToConsole(message: string, optional?: any): void;
readProvisions(filePaths: string[]): Chainable;
getJSONFilesFromDir(dirPath: string): Chainable;
}
}

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/e2e",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana End-to-End Test Library",
"keywords": [
"cli",
@@ -45,7 +45,7 @@
"types": "src/index.ts",
"dependencies": {
"@cypress/webpack-preprocessor": "5.9.0",
"@grafana/e2e-selectors": "8.2.0-pre",
"@grafana/e2e-selectors": "8.2.0-beta.2",
"@grafana/tsconfig": "^1.0.0-rc1",
"@mochajs/json-file-reporter": "^1.2.0",
"blink-diff": "1.0.13",

View File

@@ -7,13 +7,14 @@ type Panel = {
[key: string]: unknown;
};
type Dashboard = { title: string; panels: Panel[]; uid: string; [key: string]: unknown };
export type Dashboard = { title: string; panels: Panel[]; uid: string; [key: string]: unknown };
/**
* Smoke test a datasource by quickly importing a test dashboard for it
* Smoke test a particular dashboard by quickly importing a json file and validate that all the panels finish loading
* @param dashboardToImport a sample dashboard
* @param queryTimeout a number of ms to wait for the imported dashboard to finish loading
*/
export const importDashboard = (dashboardToImport: Dashboard) => {
export const importDashboard = (dashboardToImport: Dashboard, queryTimeout?: number) => {
e2e().visit(fromBaseUrl('/dashboard/import'));
// Note: normally we'd use 'click' and then 'type' here, but the json object is so big that using 'val' is much faster
@@ -24,7 +25,9 @@ export const importDashboard = (dashboardToImport: Dashboard) => {
e2e.components.DashboardImportPage.submit().should('be.visible').click();
e2e.components.ImportDashboardForm.name().should('be.visible').click().clear().type(dashboardToImport.title);
e2e.components.ImportDashboardForm.submit().should('be.visible').click();
e2e().wait(3000);
// wait for dashboard to load
e2e().wait(queryTimeout || 6000);
// save the newly imported dashboard to context so it'll get properly deleted later
e2e()
@@ -42,19 +45,21 @@ export const importDashboard = (dashboardToImport: Dashboard) => {
expect(dashboardToImport.uid).to.equal(uid);
});
// inspect first panel and verify data has been processed for it
e2e.components.Panels.Panel.title(dashboardToImport.panels[0].title).should('be.visible').click();
e2e.components.Panels.Panel.headerItems('Inspect').should('be.visible').click();
e2e.components.Tab.title('JSON').should('be.visible').click();
e2e().wait(3000);
e2e.components.PanelInspector.Json.content().should('be.visible').contains('Panel JSON').click();
e2e().wait(3000);
e2e.components.Select.option().should('be.visible').contains('Data').click();
e2e().wait(3000);
dashboardToImport.panels.forEach((panel) => {
// Look at the json data
e2e.components.Panels.Panel.title(panel.title).should('be.visible').click();
e2e.components.Panels.Panel.headerItems('Inspect').should('be.visible').click();
e2e.components.Tab.title('JSON').should('be.visible').click();
e2e.components.PanelInspector.Json.content().should('be.visible').contains('Panel JSON').click();
e2e.components.Select.option().should('be.visible').contains('Data').click();
// ensures that panel has loaded without knowingly hitting an error
// note: this does not prove that data came back as we expected it,
// it could get `state: Done` for no data for example
// but it ensures we didn't hit a 401 or 500 or something like that
e2e.components.CodeEditor.container().should('be.visible').contains('"state": "Done"');
// ensures that panel has loaded without knowingly hitting an error
// note: this does not prove that data came back as we expected it,
// it could get `state: Done` for no data for example
// but it ensures we didn't hit a 401 or 500 or something like that
e2e.components.CodeEditor.container().should('be.visible').contains('"state": "Done"');
// need to close panel
e2e.components.Drawer.General.close().click();
});
};

View File

@@ -0,0 +1,19 @@
import { importDashboard, Dashboard } from './importDashboard';
import { e2e } from '../index';
/**
* Smoke test several dashboard json files from a test directory
* and validate that all the panels in each import finish loading their queries
* @param dirPath the relative path to a directory which contains json files representing dashboards,
* for example if your dashboards live in `cypress/testDashboards` you can pass `/testDashboards`
* @param queryTimeout a number of ms to wait for the imported dashboard to finish loading
*/
export const importDashboards = async (dirPath: string, queryTimeout?: number) => {
e2e()
.getJSONFilesFromDir(dirPath)
.then((jsonFiles: Dashboard[]) => {
jsonFiles.forEach((file) => {
importDashboard(file, queryTimeout || 6000);
});
});
};

View File

@@ -13,6 +13,7 @@ export * from './revertAllChanges';
export * from './saveDashboard';
export * from './selectOption';
export * from './importDashboard';
export * from './importDashboards';
export {
VISUALIZATION_ALERT_LIST,

View File

@@ -11,10 +11,10 @@ export const setTimeRange = ({ from, to, zone }: TimeRangeConfig) => {
e2e.components.TimePicker.openButton().click();
if (zone) {
e2e().contains('button', 'Change time zone').click();
e2e().contains('button', 'Change time settings').click();
selectOption({
clickToOpen: false,
clickToOpen: true,
container: e2e.components.TimeZonePicker.container(),
optionText: zone,
});

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/runtime",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana Runtime Library",
"keywords": [
"grafana",
@@ -22,9 +22,9 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@grafana/data": "8.2.0-pre",
"@grafana/e2e-selectors": "8.2.0-pre",
"@grafana/ui": "8.2.0-pre",
"@grafana/data": "8.2.0-beta.2",
"@grafana/e2e-selectors": "8.2.0-beta.2",
"@grafana/ui": "8.2.0-beta.2",
"history": "4.10.1",
"systemjs": "0.20.19",
"systemjs-plugin-css": "0.1.37"

View File

@@ -145,6 +145,7 @@ export class DataSourcePicker extends PureComponent<DataSourcePickerProps, DataS
return (
<div aria-label={selectors.components.DataSourcePicker.container}>
<Select
inputId="data-source-picker"
menuShouldPortal
className={styles.select}
isMulti={false}

View File

@@ -60,7 +60,6 @@ export class GrafanaBootConfig implements GrafanaConfig {
theme2: GrafanaTheme2;
pluginsToPreload: string[] = [];
featureToggles: FeatureToggles = {
ngalert: false,
accesscontrol: false,
trimDefaults: false,
tempoServiceGraph: false,
@@ -80,7 +79,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
sampleRate: 1,
};
pluginCatalogURL = 'https://grafana.com/grafana/plugins/';
pluginAdminEnabled = false;
pluginAdminEnabled = true;
pluginAdminExternalManageEnabled = false;
expressionsEnabled = false;
customTheme?: any;
@@ -94,6 +93,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
};
geomapDefaultBaseLayerConfig?: MapLayerOptions;
geomapDisableCustomBaseLayer?: boolean;
unifiedAlertingEnabled = false;
applicationInsightsConnectionString?: string;
applicationInsightsEndpointUrl?: string;

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/schema",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana Schema Library",
"keywords": [
"typescript"

View File

@@ -1,13 +1,12 @@
package schema
AxisPlacement: "auto" | "top" | "right" | "bottom" | "left" | "hidden" @cuetsy(kind="enum")
PointVisibility: "auto" | "never" | "always" @cuetsy(kind="enum")
VisibilityMode: "auto" | "never" | "always" @cuetsy(kind="enum")
DrawStyle: "line" | "bars" | "points" @cuetsy(kind="enum")
LineInterpolation: "linear" | "smooth" | "stepBefore" | "stepAfter" @cuetsy(kind="enum")
ScaleDistribution: "linear" | "log" @cuetsy(kind="enum")
GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(kind="enum")
StackingMode: "none" | "normal" | "percent" @cuetsy(kind="enum")
BarValueVisibility: "auto" | "never" | "always" @cuetsy(kind="enum")
BarAlignment: -1 | 0 | 1 @cuetsy(kind="enum",memberNames="Before|Center|After")
ScaleOrientation: 0 | 1 @cuetsy(kind="enum",memberNames="Horizontal|Vertical")
ScaleDirection: 1 | 1 | -1 | -1 @cuetsy(kind="enum",memberNames="Up|Right|Down|Left")
@@ -33,7 +32,7 @@ FillConfig: {
fillBelowTo?: string
} @cuetsy(kind="interface")
PointsConfig: {
showPoints?: PointVisibility
showPoints?: VisibilityMode
pointSize?: number
pointColor?: string
pointSymbol?: string

View File

@@ -11,9 +11,9 @@ export enum AxisPlacement {
Right = 'right',
Top = 'top',
}
export enum PointVisibility {
Always = 'always',
export enum VisibilityMode {
Auto = 'auto',
Always = 'always',
Never = 'never',
}
export enum GraphDrawStyle {
@@ -45,12 +45,11 @@ export interface LineStyle {
dash?: number[];
fill?: 'solid' | 'dash' | 'dot' | 'square';
}
export interface PointsConfig {
pointColor?: string;
pointSize?: number;
pointSymbol?: string;
showPoints?: PointVisibility;
showPoints?: VisibilityMode;
}
export interface ScaleDistributionConfig {
log?: number;
@@ -71,15 +70,6 @@ export enum BarAlignment {
After = 1,
}
/**
* @alpha
*/
export enum BarValueVisibility {
Auto = 'auto',
Never = 'never',
Always = 'always',
}
/**
* @alpha
*/

View File

@@ -0,0 +1,42 @@
package dist
import (
"github.com/grafana/grafana/packages/grafana-schema/src/scuemata/dashboard"
pbarchart "github.com/grafana/grafana/public/app/plugins/panel/barchart:grafanaschema"
pbargauge "github.com/grafana/grafana/public/app/plugins/panel/bargauge:grafanaschema"
pcanvas "github.com/grafana/grafana/public/app/plugins/panel/canvas:grafanaschema"
pdashlist "github.com/grafana/grafana/public/app/plugins/panel/dashlist:grafanaschema"
pgauge "github.com/grafana/grafana/public/app/plugins/panel/gauge:grafanaschema"
phistogram "github.com/grafana/grafana/public/app/plugins/panel/histogram:grafanaschema"
pnews "github.com/grafana/grafana/public/app/plugins/panel/news:grafanaschema"
pstat "github.com/grafana/grafana/public/app/plugins/panel/stat:grafanaschema"
st "github.com/grafana/grafana/public/app/plugins/panel/state-timeline:grafanaschema"
sh "github.com/grafana/grafana/public/app/plugins/panel/status-history:grafanaschema"
ptable "github.com/grafana/grafana/public/app/plugins/panel/table:grafanaschema"
ptext "github.com/grafana/grafana/public/app/plugins/panel/text:grafanaschema"
ptimeseries "github.com/grafana/grafana/public/app/plugins/panel/timeseries:grafanaschema"
)
// Family composes the base dashboard scuemata family with all Grafana core plugins -
// the plugins that are dist[ributed] with Grafana. The resulting composed scuemata is
// exactly equivalent to what's produced by the DistDashboardFamily() Go function.
//
// CUE programs should default to importing this dist variant over the base variant.
Family: dashboard.Family & {
compose: Panel: {
// TODO do this with a loop once we include the panel type/plugin id in the model
barchart: pbarchart.Panel
bargauge: pbargauge.Panel
canvas: pcanvas.Panel
dashlist: pdashlist.Panel
gauge: pgauge.Panel
histogram: phistogram.Panel
news: pnews.Panel
stat: pstat.Panel
"state-timeline": st.Panel
"status-history": sh.Panel
text: ptext.Panel
table: ptable.Panel
timeseries: ptimeseries.Panel
}
}

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/toolkit",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana Toolkit",
"keywords": [
"grafana",
@@ -28,10 +28,10 @@
"dependencies": {
"@babel/core": "7.13.14",
"@babel/preset-env": "7.13.12",
"@grafana/data": "8.2.0-pre",
"@grafana/data": "8.2.0-beta.2",
"@grafana/eslint-config": "2.5.0",
"@grafana/tsconfig": "^1.0.0-rc1",
"@grafana/ui": "8.2.0-pre",
"@grafana/ui": "8.2.0-beta.2",
"@types/command-exists": "^1.2.0",
"@types/expect-puppeteer": "3.3.1",
"@types/fs-extra": "^8.1.0",

View File

@@ -2,7 +2,7 @@
"author": "Grafana Labs",
"license": "Apache-2.0",
"name": "@grafana/ui",
"version": "8.2.0-pre",
"version": "8.2.0-beta.2",
"description": "Grafana Components Library",
"keywords": [
"grafana",
@@ -33,9 +33,9 @@
"@emotion/css": "11.1.3",
"@emotion/react": "11.1.5",
"@grafana/aws-sdk": "0.0.3",
"@grafana/data": "8.2.0-pre",
"@grafana/e2e-selectors": "8.2.0-pre",
"@grafana/schema": "8.2.0-pre",
"@grafana/data": "8.2.0-beta.2",
"@grafana/e2e-selectors": "8.2.0-beta.2",
"@grafana/schema": "8.2.0-beta.2",
"@grafana/slate-react": "0.22.10-grafana",
"@grafana/tsconfig": "^1.0.0-rc1",
"@monaco-editor/react": "4.2.2",
@@ -73,7 +73,7 @@
"react-transition-group": "4.4.1",
"slate": "0.47.8",
"tinycolor2": "1.4.1",
"uplot": "1.6.15"
"uplot": "1.6.16"
},
"devDependencies": {
"@rollup/plugin-commonjs": "16.0.0",
@@ -83,10 +83,10 @@
"@storybook/addon-essentials": "6.3.7",
"@storybook/addon-knobs": "6.3.0",
"@storybook/addon-storysource": "6.3.7",
"@storybook/react": "6.3.7",
"@storybook/theming": "6.3.7",
"@storybook/builder-webpack5": "6.3.7",
"@storybook/manager-webpack5": "6.3.7",
"@storybook/react": "6.3.7",
"@storybook/theming": "6.3.7",
"@testing-library/jest-dom": "5.11.9",
"@types/classnames": "2.2.7",
"@types/common-tags": "^1.8.0",

View File

@@ -4,6 +4,7 @@ import {
DisplayValue,
VizOrientation,
ThresholdsMode,
FALLBACK_COLOR,
Field,
FieldType,
getDisplayProcessor,
@@ -12,6 +13,7 @@ import {
import {
BarGauge,
Props,
getCellColor,
getValueColor,
getBasicAndGradientStyles,
getBarGradient,
@@ -74,6 +76,69 @@ function getValue(value: number, title?: string): DisplayValue {
}
describe('BarGauge', () => {
describe('getCellColor', () => {
it('returns a fallback if the positionValue is null', () => {
const props = getProps();
expect(getCellColor(null, props.value, props.display)).toEqual({
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
});
});
it('does not show as lit if the value is null (somehow)', () => {
const props = getProps();
expect(getCellColor(1, (null as unknown) as DisplayValue, props.display)).toEqual(
expect.objectContaining({
isLit: false,
})
);
});
it('does not show as lit if the numeric value is NaN', () => {
const props = getProps();
expect(
getCellColor(
1,
{
numeric: NaN,
text: '0',
},
props.display
)
).toEqual(
expect.objectContaining({
isLit: false,
})
);
});
it('does not show as lit if the positionValue is greater than the numeric value', () => {
const props = getProps();
expect(getCellColor(75, props.value, props.display)).toEqual(
expect.objectContaining({
isLit: false,
})
);
});
it('shows as lit otherwise', () => {
const props = getProps();
expect(getCellColor(1, props.value, props.display)).toEqual(
expect.objectContaining({
isLit: true,
})
);
});
it('returns a fallback if there is no display processor', () => {
const props = getProps();
expect(getCellColor(null, props.value, undefined)).toEqual({
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
});
});
});
describe('Get value color', () => {
it('should get the threshold color if value is same as a threshold', () => {
const props = getProps();

View File

@@ -6,6 +6,8 @@ import {
DisplayValue,
formattedValueToString,
FormattedValue,
GAUGE_DEFAULT_MAXIMUM,
GAUGE_DEFAULT_MINIMUM,
DisplayValueAlignmentFactors,
ThresholdsMode,
DisplayProcessor,
@@ -122,43 +124,8 @@ export class BarGauge extends PureComponent<Props> {
);
}
getCellColor(positionValue: TimeSeriesValue): CellColors {
const { value, display } = this.props;
if (positionValue === null) {
return {
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
};
}
const color = display ? display(positionValue).color : null;
if (color) {
// if we are past real value the cell is not "on"
if (value === null || (positionValue !== null && positionValue > value.numeric)) {
return {
background: tinycolor(color).setAlpha(0.18).toRgbString(),
border: 'transparent',
isLit: false,
};
} else {
return {
background: tinycolor(color).setAlpha(0.95).toRgbString(),
backgroundShade: tinycolor(color).setAlpha(0.55).toRgbString(),
border: tinycolor(color).setAlpha(0.9).toRgbString(),
isLit: true,
};
}
}
return {
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
};
}
renderRetroBars(): ReactNode {
const { field, value, itemSpacing, alignmentFactors, orientation, lcdCellWidth, text } = this.props;
const { display, field, value, itemSpacing, alignmentFactors, orientation, lcdCellWidth, text } = this.props;
const {
valueHeight,
valueWidth,
@@ -167,8 +134,8 @@ export class BarGauge extends PureComponent<Props> {
wrapperWidth,
wrapperHeight,
} = calculateBarAndValueDimensions(this.props);
const minValue = field.min!;
const maxValue = field.max!;
const minValue = field.min ?? GAUGE_DEFAULT_MINIMUM;
const maxValue = field.max ?? GAUGE_DEFAULT_MAXIMUM;
const isVert = isVertical(orientation);
const valueRange = maxValue - minValue;
@@ -200,7 +167,7 @@ export class BarGauge extends PureComponent<Props> {
for (let i = 0; i < cellCount; i++) {
const currentValue = minValue + (valueRange / cellCount) * i;
const cellColor = this.getCellColor(currentValue);
const cellColor = getCellColor(currentValue, value, display);
const cellStyles: CSSProperties = {
borderRadius: '2px',
};
@@ -425,6 +392,44 @@ export function calculateBarAndValueDimensions(props: Props): BarAndValueDimensi
};
}
export function getCellColor(
positionValue: TimeSeriesValue,
value: Props['value'],
display: Props['display']
): CellColors {
if (positionValue === null) {
return {
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
};
}
const color = display ? display(positionValue).color : null;
if (color) {
// if we are past real value the cell is not "on"
if (value === null || isNaN(value.numeric) || (positionValue !== null && positionValue > value.numeric)) {
return {
background: tinycolor(color).setAlpha(0.18).toRgbString(),
border: 'transparent',
isLit: false,
};
} else {
return {
background: tinycolor(color).setAlpha(0.95).toRgbString(),
backgroundShade: tinycolor(color).setAlpha(0.55).toRgbString(),
border: tinycolor(color).setAlpha(0.9).toRgbString(),
isLit: true,
};
}
}
return {
background: FALLBACK_COLOR,
border: FALLBACK_COLOR,
};
}
export function getValuePercent(value: number, minValue: number, maxValue: number): number {
return Math.min((value - minValue) / (maxValue - minValue), 1);
}
@@ -436,7 +441,9 @@ export function getBasicAndGradientStyles(props: Props): BasicAndGradientStyles
const { displayMode, field, value, alignmentFactors, orientation, theme, text } = props;
const { valueWidth, valueHeight, maxBarHeight, maxBarWidth } = calculateBarAndValueDimensions(props);
const valuePercent = getValuePercent(value.numeric, field.min!, field.max!);
const minValue = field.min ?? GAUGE_DEFAULT_MINIMUM;
const maxValue = field.max ?? GAUGE_DEFAULT_MAXIMUM;
const valuePercent = getValuePercent(value.numeric, minValue, maxValue);
const valueColor = getValueColor(props);
const valueToBaseSizeOn = alignmentFactors ? alignmentFactors : value;

View File

@@ -69,9 +69,7 @@ export const Card: CardInterface = ({ heading, description, disabled, href, onCl
<div className={styles.inner}>
<div className={styles.info}>
<div>
<div className={styles.heading} role="heading">
{heading}
</div>
<h2 className={styles.heading}>{heading}</h2>
{meta}
{description && <p className={styles.description}>{description}</p>}
</div>
@@ -115,6 +113,7 @@ export const getCardStyles = stylesFactory((theme: GrafanaTheme2) => {
width: 100%;
margin-bottom: 0;
font-size: ${theme.typography.size.md};
letter-spacing: inherit;
line-height: ${theme.typography.body.lineHeight};
color: ${theme.colors.text.primary};
font-weight: ${theme.typography.fontWeightMedium};

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { css } from '@emotion/css';
import { Modal } from '../Modal/Modal';
import { IconName } from '../../types/icon';
@@ -51,10 +51,16 @@ export const ConfirmModal = ({
}: ConfirmModalProps): JSX.Element => {
const [disabled, setDisabled] = useState(Boolean(confirmationText));
const styles = useStyles2(getStyles);
const buttonRef = useRef<HTMLButtonElement>(null);
const onConfirmationTextChange = (event: React.FormEvent<HTMLInputElement>) => {
setDisabled(confirmationText?.localeCompare(event.currentTarget.value) !== 0);
};
useEffect(() => {
// for some reason autoFocus property did no work on this button, but this does
buttonRef.current?.focus();
}, []);
return (
<Modal className={styles.modal} title={title} icon={icon} isOpen={isOpen} onDismiss={onDismiss}>
<div className={styles.modalText}>
@@ -76,7 +82,7 @@ export const ConfirmModal = ({
variant="destructive"
onClick={onConfirm}
disabled={disabled}
autoFocus
ref={buttonRef}
aria-label={selectors.pages.ConfirmModal.delete}
>
{confirmText}

View File

@@ -24,15 +24,18 @@ const menuItems = [
items: [
{ label: 'First', ariaLabel: 'First' },
{ label: 'Second', ariaLabel: 'Second' },
{ label: 'Third', ariaLabel: 'Third' },
{ label: 'Fourth', ariaLabel: 'Fourth' },
{ label: 'Fifth', ariaLabel: 'Fifth' },
],
},
];
const renderMenuItems = () => {
return menuItems?.map((group, index) => (
<MenuGroup key={`${group.label}${index}`} label={group.label} ariaLabel={group.label}>
{(group.items || []).map((item) => (
<MenuItem key={item.label} label={item.label} ariaLabel={item.label} />
return menuItems.map((group, index) => (
<MenuGroup key={`${group.label}${index}`} label={group.label}>
{group.items.map((item) => (
<MenuItem key={item.label} label={item.label} />
))}
</MenuGroup>
));

View File

@@ -41,12 +41,20 @@ export const ContextMenu: React.FC<ContextMenuProps> = React.memo(
}, [x, y]);
useClickAway(menuRef, () => {
if (onClose) {
onClose();
}
onClose?.();
});
const header = renderHeader && renderHeader();
const menuItems = renderMenuItems && renderMenuItems();
const header = renderHeader?.();
const menuItems = renderMenuItems?.();
const onOpen = (setFocusedItem: (a: number) => void) => {
setFocusedItem(0);
};
const onKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
e.preventDefault();
e.stopPropagation();
onClose?.();
}
};
return (
<Portal>
@@ -55,7 +63,9 @@ export const ContextMenu: React.FC<ContextMenuProps> = React.memo(
ref={menuRef}
style={positionStyles}
ariaLabel={selectors.components.Menu.MenuComponent('Context')}
onOpen={onOpen}
onClick={onClose}
onKeyDown={onKeyDown}
>
{menuItems}
</Menu>

View File

@@ -23,13 +23,12 @@ export const DataLinksContextMenu: React.FC<DataLinksContextMenuProps> = ({ chil
const itemsGroup: MenuItemsGroup[] = [{ items: linkModelToContextMenuItems(links), label: 'Data links' }];
const renderMenuGroupItems = () => {
return itemsGroup.map((group, index) => (
<MenuGroup key={`${group.label}${index}`} label={group.label} ariaLabel={group.label}>
<MenuGroup key={`${group.label}${index}`} label={group.label}>
{(group.items || []).map((item) => (
<MenuItem
key={item.label}
url={item.url}
label={item.label}
ariaLabel={item.label}
target={item.target}
icon={item.icon}
active={item.active}

View File

@@ -5,7 +5,7 @@ import { useStyles2 } from '../../../themes';
import { Button } from '../../Button';
import { ClickOutsideWrapper } from '../../ClickOutsideWrapper/ClickOutsideWrapper';
import { TimeRangeList } from '../TimeRangePicker/TimeRangeList';
import { quickOptions } from '../rangeOptions';
import { quickOptions } from '../options';
import CustomScrollbar from '../../CustomScrollbar/CustomScrollbar';
import { TimePickerTitle } from '../TimeRangePicker/TimePickerTitle';
import {

View File

@@ -7,7 +7,7 @@ import { Icon } from '../Icon/Icon';
import { getInputStyles } from '../Input/Input';
import { TimePickerButtonLabel } from './TimeRangePicker';
import { TimePickerContent } from './TimeRangePicker/TimePickerContent';
import { otherOptions, quickOptions } from './rangeOptions';
import { quickOptions } from './options';
import { selectors } from '@grafana/e2e-selectors';
import { stylesFactory } from '../../themes';
@@ -100,7 +100,6 @@ export const TimeRangeInput: FC<TimeRangeInputProps> = ({
timeZone={timeZone}
value={isValidTimeRange(value) ? (value as TimeRange) : getDefaultTimeRange()}
onChange={onRangeChange}
otherOptions={otherOptions}
quickOptions={quickOptions}
onChangeTimeZone={onChangeTimeZone}
className={styles.content}

View File

@@ -23,7 +23,7 @@ import {
dateMath,
} from '@grafana/data';
import { Themeable } from '../../types';
import { otherOptions, quickOptions } from './rangeOptions';
import { quickOptions } from './options';
import { ButtonGroup, ToolbarButton } from '../Button';
import { selectors } from '@grafana/e2e-selectors';
@@ -32,10 +32,12 @@ export interface TimeRangePickerProps extends Themeable {
hideText?: boolean;
value: TimeRange;
timeZone?: TimeZone;
fiscalYearStartMonth?: number;
timeSyncButton?: JSX.Element;
isSynced?: boolean;
onChange: (timeRange: TimeRange) => void;
onChangeTimeZone: (timeZone: TimeZone) => void;
onChangeFiscalYearStartMonth?: (month: number) => void;
onMoveBackward: () => void;
onMoveForward: () => void;
onZoom: () => void;
@@ -75,11 +77,13 @@ export class UnthemedTimeRangePicker extends PureComponent<TimeRangePickerProps,
onMoveForward,
onZoom,
timeZone,
fiscalYearStartMonth,
timeSyncButton,
isSynced,
theme,
history,
onChangeTimeZone,
onChangeFiscalYearStartMonth,
hideQuickRanges,
} = this.props;
@@ -117,13 +121,14 @@ export class UnthemedTimeRangePicker extends PureComponent<TimeRangePickerProps,
<ClickOutsideWrapper includeButtonPress={false} onClick={this.onClose}>
<TimePickerContent
timeZone={timeZone}
fiscalYearStartMonth={fiscalYearStartMonth}
value={value}
onChange={this.onChange}
otherOptions={otherOptions}
quickOptions={quickOptions}
history={history}
showHistory
onChangeTimeZone={onChangeTimeZone}
onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth}
hideQuickRanges={hideQuickRanges}
/>
</ClickOutsideWrapper>

View File

@@ -38,14 +38,12 @@ describe('TimePickerContent', () => {
it('renders with relative picker', () => {
renderComponent({ value: absoluteValue });
expect(screen.queryByText(/relative time ranges/i)).toBeInTheDocument();
expect(screen.queryByText(/other quick ranges/i)).toBeInTheDocument();
expect(screen.queryByText(/Last 5 minutes/i)).toBeInTheDocument();
});
it('renders without relative picker', () => {
renderComponent({ value: absoluteValue, hideQuickRanges: true });
expect(screen.queryByText(/relative time ranges/i)).not.toBeInTheDocument();
expect(screen.queryByText(/other quick ranges/i)).not.toBeInTheDocument();
expect(screen.queryByText(/Last 5 minutes/i)).not.toBeInTheDocument();
});
it('renders with timezone picker', () => {
@@ -86,14 +84,12 @@ describe('TimePickerContent', () => {
it('renders with relative picker', () => {
renderComponent({ value: absoluteValue, isFullscreen: false });
expect(screen.queryByText(/relative time ranges/i)).toBeInTheDocument();
expect(screen.queryByText(/other quick ranges/i)).toBeInTheDocument();
expect(screen.queryByText(/Last 5 minutes/i)).toBeInTheDocument();
});
it('renders without relative picker', () => {
renderComponent({ value: absoluteValue, isFullscreen: false, hideQuickRanges: true });
expect(screen.queryByText(/relative time ranges/i)).not.toBeInTheDocument();
expect(screen.queryByText(/other quick ranges/i)).not.toBeInTheDocument();
expect(screen.queryByText(/Last 5 minutes/i)).not.toBeInTheDocument();
});
it('renders with absolute picker when absolute value and quick ranges are visible', () => {
@@ -139,6 +135,10 @@ function renderComponent({
<TimePickerContentWithScreenSize
onChangeTimeZone={noop}
onChange={noop}
quickOptions={[
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes' },
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes' },
]}
timeZone="utc"
value={value}
isFullscreen={isFullscreen}

View File

@@ -12,6 +12,7 @@ import { TimeRangeList } from './TimeRangeList';
import { TimePickerFooter } from './TimePickerFooter';
import { getFocusStyles } from '../../../themes/mixins';
import { selectors } from '@grafana/e2e-selectors';
import { FilterInput } from '../..';
const getStyles = stylesFactory((theme: GrafanaTheme2, isReversed, hideQuickRanges, isContainerTall) => {
return {
@@ -46,11 +47,15 @@ const getStyles = stylesFactory((theme: GrafanaTheme2, isReversed, hideQuickRang
rightSide: css`
width: 40% !important;
border-right: ${isReversed ? `1px solid ${theme.colors.border.weak}` : 'none'};
display: flex;
flex-direction: column;
@media only screen and (max-width: ${theme.breakpoints.values.lg}px) {
width: 100% !important;
}
`,
timeRangeFilter: css`
padding: ${theme.spacing(1)};
`,
spacing: css`
margin-top: 16px;
`,
@@ -127,9 +132,10 @@ interface Props {
value: TimeRange;
onChange: (timeRange: TimeRange) => void;
onChangeTimeZone: (timeZone: TimeZone) => void;
onChangeFiscalYearStartMonth?: (month: number) => void;
timeZone?: TimeZone;
fiscalYearStartMonth?: number;
quickOptions?: TimeOption[];
otherOptions?: TimeOption[];
history?: TimeRange[];
showHistory?: boolean;
className?: string;
@@ -150,11 +156,11 @@ interface FormProps extends Omit<Props, 'history'> {
export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (props) => {
const {
quickOptions = [],
otherOptions = [],
isReversed,
isFullscreen,
hideQuickRanges,
timeZone,
fiscalYearStartMonth,
value,
onChange,
history,
@@ -162,6 +168,7 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
className,
hideTimeZone,
onChangeTimeZone,
onChangeFiscalYearStartMonth,
} = props;
const isHistoryEmpty = !history?.length;
const isContainerTall =
@@ -169,7 +176,10 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
const theme = useTheme2();
const styles = getStyles(theme, isReversed, hideQuickRanges, isContainerTall);
const historyOptions = mapToHistoryOptions(history, timeZone);
const timeOption = useTimeOption(value.raw, otherOptions, quickOptions);
const timeOption = useTimeOption(value.raw, quickOptions);
const [searchTerm, setSearchQuery] = useState('');
const filteredQuickOptions = quickOptions.filter((o) => o.display.toLowerCase().includes(searchTerm.toLowerCase()));
const onChangeTimeOption = (timeOption: TimeOption) => {
return onChange(mapOptionToTimeRange(timeOption));
@@ -179,26 +189,23 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
<div id="TimePickerContent" className={cx(styles.container, className)}>
<div className={styles.body}>
{(!isFullscreen || !hideQuickRanges) && (
<CustomScrollbar className={styles.rightSide}>
{!isFullscreen && <NarrowScreenForm {...props} historyOptions={historyOptions} />}
{!hideQuickRanges && (
<>
<TimeRangeList
title="Relative time ranges"
options={quickOptions}
onChange={onChangeTimeOption}
value={timeOption}
/>
<div className={styles.spacing} />
<TimeRangeList
title="Other quick ranges"
options={otherOptions}
onChange={onChangeTimeOption}
value={timeOption}
/>
</>
)}
</CustomScrollbar>
<div className={styles.rightSide}>
<div className={styles.timeRangeFilter}>
<FilterInput
width={0}
autoFocus={true}
value={searchTerm}
onChange={setSearchQuery}
placeholder={'Search quick ranges'}
/>
</div>
<CustomScrollbar>
{!isFullscreen && <NarrowScreenForm {...props} historyOptions={historyOptions} />}
{!hideQuickRanges && (
<TimeRangeList options={filteredQuickOptions} onChange={onChangeTimeOption} value={timeOption} />
)}
</CustomScrollbar>
</div>
)}
{isFullscreen && (
<div className={styles.leftSide}>
@@ -206,7 +213,14 @@ export const TimePickerContentWithScreenSize: React.FC<PropsWithScreenSize> = (p
</div>
)}
</div>
{!hideTimeZone && isFullscreen && <TimePickerFooter timeZone={timeZone} onChangeTimeZone={onChangeTimeZone} />}
{!hideTimeZone && isFullscreen && (
<TimePickerFooter
timeZone={timeZone}
fiscalYearStartMonth={fiscalYearStartMonth}
onChangeTimeZone={onChangeTimeZone}
onChangeFiscalYearStartMonth={onChangeFiscalYearStartMonth}
/>
)}
</div>
);
};
@@ -268,7 +282,7 @@ const NarrowScreenForm: React.FC<FormProps> = (props) => {
};
const FullScreenForm: React.FC<FormProps> = (props) => {
const { onChange } = props;
const { onChange, value, timeZone, fiscalYearStartMonth, isReversed, historyOptions } = props;
const theme = useTheme2();
const styles = getFullScreenStyles(theme, props.hideQuickRanges);
const onChangeTimeOption = (timeOption: TimeOption) => {
@@ -282,18 +296,19 @@ const FullScreenForm: React.FC<FormProps> = (props) => {
<TimePickerTitle>Absolute time range</TimePickerTitle>
</div>
<TimeRangeForm
value={props.value}
timeZone={props.timeZone}
onApply={props.onChange}
value={value}
timeZone={timeZone}
fiscalYearStartMonth={fiscalYearStartMonth}
onApply={onChange}
isFullscreen={true}
isReversed={props.isReversed}
isReversed={isReversed}
/>
</div>
{props.showHistory && (
<div className={styles.recent}>
<TimeRangeList
title="Recently used absolute ranges"
options={props.historyOptions || []}
options={historyOptions || []}
onChange={onChangeTimeOption}
placeholderEmpty={<EmptyRecentList />}
/>
@@ -338,23 +353,13 @@ function mapToHistoryOptions(ranges?: TimeRange[], timeZone?: TimeZone): TimeOpt
EmptyRecentList.displayName = 'EmptyRecentList';
const useTimeOption = (
raw: RawTimeRange,
quickOptions: TimeOption[],
otherOptions: TimeOption[]
): TimeOption | undefined => {
const useTimeOption = (raw: RawTimeRange, quickOptions: TimeOption[]): TimeOption | undefined => {
return useMemo(() => {
if (!rangeUtil.isRelativeTimeRange(raw)) {
return;
}
const quickOption = quickOptions.find((option) => {
return quickOptions.find((option) => {
return option.from === raw.from && option.to === raw.to;
});
if (quickOption) {
return quickOption;
}
return otherOptions.find((option) => {
return option.from === raw.from && option.to === raw.to;
});
}, [raw, otherOptions, quickOptions]);
}, [raw, quickOptions]);
};

View File

@@ -9,18 +9,29 @@ import { Button } from '../../Button';
import { TimeZonePicker } from '../TimeZonePicker';
import { isString } from 'lodash';
import { selectors } from '@grafana/e2e-selectors';
import { Field, RadioButtonGroup, Select } from '../..';
import { monthOptions } from '../options';
interface Props {
timeZone?: TimeZone;
fiscalYearStartMonth?: number;
timestamp?: number;
onChangeTimeZone: (timeZone: TimeZone) => void;
onChangeFiscalYearStartMonth?: (month: number) => void;
}
export const TimePickerFooter: FC<Props> = (props) => {
const { timeZone, timestamp = Date.now(), onChangeTimeZone } = props;
const {
timeZone,
fiscalYearStartMonth,
timestamp = Date.now(),
onChangeTimeZone,
onChangeFiscalYearStartMonth,
} = props;
const [isEditing, setEditing] = useState(false);
const [editMode, setEditMode] = useState('tz');
const onToggleChangeTz = useCallback(
const onToggleChangeTimeSettings = useCallback(
(event?: React.MouseEvent) => {
if (event) {
event.stopPropagation();
@@ -43,42 +54,72 @@ export const TimePickerFooter: FC<Props> = (props) => {
return null;
}
if (isEditing) {
return (
<div className={cx(style.container, style.editContainer)}>
<section aria-label={selectors.components.TimeZonePicker.container} className={style.timeZoneContainer}>
<TimeZonePicker
includeInternal={true}
onChange={(timeZone) => {
onToggleChangeTz();
if (isString(timeZone)) {
onChangeTimeZone(timeZone);
}
}}
autoFocus={true}
onBlur={onToggleChangeTz}
/>
</section>
</div>
);
}
return (
<section aria-label="Time zone selection" className={style.container}>
<div className={style.timeZoneContainer}>
<div className={style.timeZone}>
<TimeZoneTitle title={info.name} />
<div className={style.spacer} />
<TimeZoneDescription info={info} />
<div>
<section aria-label="Time zone selection" className={style.container}>
<div className={style.timeZoneContainer}>
<div className={style.timeZone}>
<TimeZoneTitle title={info.name} />
<div className={style.spacer} />
<TimeZoneDescription info={info} />
</div>
<TimeZoneOffset timeZone={timeZone} timestamp={timestamp} />
</div>
<TimeZoneOffset timeZone={timeZone} timestamp={timestamp} />
</div>
<div className={style.spacer} />
<Button variant="secondary" onClick={onToggleChangeTz} size="sm">
Change time zone
</Button>
</section>
<div className={style.spacer} />
<Button variant="secondary" onClick={onToggleChangeTimeSettings} size="sm">
Change time settings
</Button>
</section>
{isEditing ? (
<div className={style.editContainer}>
<div>
<RadioButtonGroup
value={editMode}
options={[
{ label: 'Time Zone', value: 'tz' },
{ label: 'Fiscal year', value: 'fy' },
]}
onChange={setEditMode}
></RadioButtonGroup>
</div>
{editMode === 'tz' ? (
<section
aria-label={selectors.components.TimeZonePicker.container}
className={cx(style.timeZoneContainer, style.timeSettingContainer)}
>
<TimeZonePicker
includeInternal={true}
onChange={(timeZone) => {
onToggleChangeTimeSettings();
if (isString(timeZone)) {
onChangeTimeZone(timeZone);
}
}}
onBlur={onToggleChangeTimeSettings}
/>
</section>
) : (
<section
aria-label={selectors.components.TimeZonePicker.container}
className={cx(style.timeZoneContainer, style.timeSettingContainer)}
>
<Field className={style.fiscalYearField} label={'Fiscal year start month'}>
<Select
value={fiscalYearStartMonth}
options={monthOptions}
onChange={(value) => {
if (onChangeFiscalYearStartMonth) {
onChangeFiscalYearStartMonth(value.value ?? 0);
}
}}
/>
</Field>
</section>
)}
</div>
) : null}
</div>
);
};
@@ -93,11 +134,21 @@ const getStyle = stylesFactory((theme: GrafanaTheme2) => {
align-items: center;
`,
editContainer: css`
border-top: 1px solid ${theme.colors.border.weak};
padding: 11px;
justify-content: space-between;
align-items: center;
padding: 7px;
`,
spacer: css`
margin-left: 7px;
`,
timeSettingContainer: css`
padding-top: ${theme.spacing(1)};
`,
fiscalYearField: css`
margin-bottom: 0px;
`,
timeZoneContainer: css`
display: flex;
flex-direction: row;

View File

@@ -1,8 +1,10 @@
import { css } from '@emotion/css';
import {
dateMath,
DateTime,
dateTimeFormat,
dateTimeParse,
GrafanaTheme2,
isDateTime,
rangeUtil,
RawTimeRange,
@@ -11,6 +13,8 @@ import {
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import React, { FormEvent, useCallback, useEffect, useState } from 'react';
import { Icon, Tooltip } from '../..';
import { useStyles2 } from '../../..';
import { Button } from '../../Button';
import { Field } from '../../Forms/Field';
import { Input } from '../../Input/Input';
@@ -21,6 +25,7 @@ interface Props {
value: TimeRange;
onApply: (range: TimeRange) => void;
timeZone?: TimeZone;
fiscalYearStartMonth?: number;
roundup?: boolean;
isReversed?: boolean;
}
@@ -37,8 +42,9 @@ const ERROR_MESSAGES = {
};
export const TimeRangeForm: React.FC<Props> = (props) => {
const { value, isFullscreen = false, timeZone, onApply: onApplyFromProps, isReversed } = props;
const { value, isFullscreen = false, timeZone, onApply: onApplyFromProps, isReversed, fiscalYearStartMonth } = props;
const [fromValue, toValue] = valueToState(value.raw.from, value.raw.to, timeZone);
const style = useStyles2(getStyles);
const [from, setFrom] = useState<InputState>(fromValue);
const [to, setTo] = useState<InputState>(toValue);
@@ -77,11 +83,11 @@ export const TimeRangeForm: React.FC<Props> = (props) => {
}
const raw: RawTimeRange = { from: from.value, to: to.value };
const timeRange = rangeUtil.convertRawToRange(raw, timeZone);
const timeRange = rangeUtil.convertRawToRange(raw, timeZone, fiscalYearStartMonth);
onApplyFromProps(timeRange);
},
[from.invalid, from.value, onApplyFromProps, timeZone, to.invalid, to.value]
[from.invalid, from.value, onApplyFromProps, timeZone, to.invalid, to.value, fiscalYearStartMonth]
);
const onChange = useCallback(
@@ -93,29 +99,47 @@ export const TimeRangeForm: React.FC<Props> = (props) => {
[timeZone]
);
const fiscalYear = rangeUtil.convertRawToRange({ from: 'now/fy', to: 'now/fy' }, timeZone, fiscalYearStartMonth);
const fyTooltip = (
<div className={style.tooltip}>
{rangeUtil.isFiscal(value) ? (
<Tooltip content={`Fiscal year: ${fiscalYear.from.format('MMM-DD')} - ${fiscalYear.to.format('MMM-DD')}`}>
<Icon name="info-circle" />
</Tooltip>
) : null}
</div>
);
const icon = isFullscreen ? null : <Button icon="calendar-alt" variant="secondary" onClick={onOpen} />;
return (
<div aria-label="Absolute time ranges">
<Field label="From" invalid={from.invalid} error={from.errorMessage}>
<Input
onClick={(event) => event.stopPropagation()}
onFocus={onFocus}
onChange={(event) => onChange(event.currentTarget.value, to.value)}
addonAfter={icon}
aria-label={selectors.components.TimePicker.fromField}
value={from.value}
/>
<div className={style.fieldContainer}>
<Input
onClick={(event) => event.stopPropagation()}
onFocus={onFocus}
onChange={(event) => onChange(event.currentTarget.value, to.value)}
addonAfter={icon}
aria-label={selectors.components.TimePicker.fromField}
value={from.value}
/>
{fyTooltip}
</div>
</Field>
<Field label="To" invalid={to.invalid} error={to.errorMessage}>
<Input
onClick={(event) => event.stopPropagation()}
onFocus={onFocus}
onChange={(event) => onChange(from.value, event.currentTarget.value)}
addonAfter={icon}
aria-label={selectors.components.TimePicker.toField}
value={to.value}
/>
<div className={style.fieldContainer}>
<Input
onClick={(event) => event.stopPropagation()}
onFocus={onFocus}
onChange={(event) => onChange(from.value, event.currentTarget.value)}
addonAfter={icon}
aria-label={selectors.components.TimePicker.toField}
value={to.value}
/>
{fyTooltip}
</div>
</Field>
<Button data-testid={selectors.components.TimePicker.applyTimeRange} onClick={onApply}>
Apply time range
@@ -185,3 +209,15 @@ function isValid(value: string, roundUp?: boolean, timeZone?: TimeZone): boolean
const parsed = dateTimeParse(value, { roundUp, timeZone });
return parsed.isValid();
}
function getStyles(theme: GrafanaTheme2) {
return {
fieldContainer: css`
display: flex;
`,
tooltip: css`
padding-left: ${theme.spacing(1)};
padding-top: ${theme.spacing(0.5)};
`,
};
}

View File

@@ -26,7 +26,7 @@ const getOptionsStyles = stylesFactory(() => {
});
interface Props {
title: string;
title?: string;
options: TimeOption[];
value?: TimeOption;
onChange: (option: TimeOption) => void;
@@ -69,7 +69,7 @@ const Options: React.FC<Props> = ({ options, value, onChange, title }) => {
value={option}
selected={isEqual(option, value)}
onSelect={onChange}
name={title}
name={title ?? 'Time ranges'}
/>
))}
</ul>

View File

@@ -43,7 +43,6 @@ export const TimeZonePicker: React.FC<Props> = (props) => {
return (
<Select
menuShouldPortal
value={selected}
placeholder="Type to search (country, city, abbreviation)"
autoFocus={autoFocus}

View File

@@ -1,4 +1,4 @@
import { TimeOption } from '@grafana/data';
import { SelectableValue, TimeOption } from '@grafana/data';
export const quickOptions: TimeOption[] = [
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes' },
@@ -17,15 +17,14 @@ export const quickOptions: TimeOption[] = [
{ from: 'now-1y', to: 'now', display: 'Last 1 year' },
{ from: 'now-2y', to: 'now', display: 'Last 2 years' },
{ from: 'now-5y', to: 'now', display: 'Last 5 years' },
];
export const otherOptions: TimeOption[] = [
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday' },
{ from: 'now-2d/d', to: 'now-2d/d', display: 'Day before yesterday' },
{ from: 'now-7d/d', to: 'now-7d/d', display: 'This day last week' },
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week' },
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month' },
{ from: 'now-1Q/fQ', to: 'now-1Q/fQ', display: 'Previous fiscal quarter' },
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year' },
{ from: 'now-1y/fy', to: 'now-1y/fy', display: 'Previous fiscal year' },
{ from: 'now/d', to: 'now/d', display: 'Today' },
{ from: 'now/d', to: 'now', display: 'Today so far' },
{ from: 'now/w', to: 'now/w', display: 'This week' },
@@ -34,4 +33,23 @@ export const otherOptions: TimeOption[] = [
{ from: 'now/M', to: 'now', display: 'This month so far' },
{ from: 'now/y', to: 'now/y', display: 'This year' },
{ from: 'now/y', to: 'now', display: 'This year so far' },
{ from: 'now/fQ', to: 'now', display: 'This fiscal quarter so far' },
{ from: 'now/fQ', to: 'now/fQ', display: 'This fiscal quarter' },
{ from: 'now/fy', to: 'now', display: 'This fiscal year so far' },
{ from: 'now/fy', to: 'now/fy', display: 'This fiscal year' },
];
export const monthOptions: Array<SelectableValue<number>> = [
{ label: 'January', value: 0 },
{ label: 'February', value: 1 },
{ label: 'March', value: 2 },
{ label: 'April', value: 3 },
{ label: 'May', value: 4 },
{ label: 'June', value: 5 },
{ label: 'July', value: 6 },
{ label: 'August', value: 7 },
{ label: 'September', value: 8 },
{ label: 'October', value: 9 },
{ label: 'November', value: 10 },
{ label: 'December', value: 11 },
];

View File

@@ -62,7 +62,6 @@ const ButtonSelectComponent = <T,>(props: Props<T>) => {
<MenuItem
key={`${item.value}`}
label={(item.label || item.value) as string}
ariaLabel={(item.label || item.value) as string}
onClick={() => onChangeInternal(item)}
active={item.value === value?.value}
/>

View File

@@ -1,6 +1,7 @@
import React, { FC } from 'react';
import { escapeStringForRegex, unEscapeStringFromRegex } from '@grafana/data';
import { Input, Icon, Button } from '@grafana/ui';
import { Button, Icon, Input } from '..';
import { useFocus } from '../Input/utils';
export interface Props {
value: string | undefined;
@@ -12,9 +13,19 @@ export interface Props {
}
export const FilterInput: FC<Props> = ({ value, placeholder, width, onChange, onKeyDown, autoFocus }) => {
const [inputRef, setInputFocus] = useFocus();
const suffix =
value !== '' ? (
<Button icon="times" fill="text" size="sm" onClick={() => onChange('')}>
<Button
icon="times"
fill="text"
size="sm"
onClick={(e) => {
setInputFocus();
onChange('');
e.stopPropagation();
}}
>
Clear
</Button>
) : null;
@@ -23,6 +34,7 @@ export const FilterInput: FC<Props> = ({ value, placeholder, width, onChange, on
<Input
autoFocus={autoFocus ?? false}
prefix={<Icon name="search" />}
ref={inputRef}
suffix={suffix}
width={width}
type="text"

View File

@@ -16,6 +16,7 @@ export interface Props extends Omit<FieldProps, 'css' | 'horizontal' | 'descript
grow?: boolean;
/** Make field's background transparent */
transparent?: boolean;
htmlFor?: string;
}
export const InlineField: FC<Props> = ({
@@ -27,13 +28,14 @@ export const InlineField: FC<Props> = ({
loading,
disabled,
className,
htmlFor,
grow,
transparent,
...htmlProps
}) => {
const theme = useTheme();
const styles = getStyles(theme, grow);
const inputId = getChildId(children);
const inputId = htmlFor ?? getChildId(children);
const labelElement =
typeof label === 'string' ? (

View File

@@ -5,6 +5,8 @@ import {
formattedValueToString,
FieldConfig,
ThresholdsMode,
GAUGE_DEFAULT_MAXIMUM,
GAUGE_DEFAULT_MINIMUM,
getActiveThreshold,
Threshold,
getColorForTheme,
@@ -58,15 +60,15 @@ export class Gauge extends PureComponent<Props> {
const { field, theme, value } = this.props;
if (field.color?.mode !== FieldColorModeId.Thresholds) {
return [{ value: field.min ?? 0, color: value.color ?? FALLBACK_COLOR }];
return [{ value: field.min ?? GAUGE_DEFAULT_MINIMUM, color: value.color ?? FALLBACK_COLOR }];
}
const thresholds = field.thresholds ?? Gauge.defaultProps.field?.thresholds!;
const isPercent = thresholds.mode === ThresholdsMode.Percentage;
const steps = thresholds.steps;
let min = field.min ?? 0;
let max = field.max ?? 100;
let min = field.min ?? GAUGE_DEFAULT_MINIMUM;
let max = field.max ?? GAUGE_DEFAULT_MAXIMUM;
if (isPercent) {
min = 0;
@@ -116,8 +118,8 @@ export class Gauge extends PureComponent<Props> {
const fontSize = this.props.text?.valueSize ?? calculateFontSize(text, valueWidth, dimension, 1, gaugeWidth * 1.7);
const thresholdLabelFontSize = Math.max(fontSize / 2.5, 12);
let min = field.min ?? 0;
let max = field.max ?? 100;
let min = field.min ?? GAUGE_DEFAULT_MINIMUM;
let max = field.max ?? GAUGE_DEFAULT_MAXIMUM;
let numeric = value.numeric;
if (field.thresholds?.mode === ThresholdsMode.Percentage) {

View File

@@ -79,13 +79,12 @@ export const GraphContextMenu: React.FC<GraphContextMenuProps> = ({
};
const renderMenuGroupItems = () => {
return itemsToRender?.map((group, index) => (
<MenuGroup key={`${group.label}${index}`} label={group.label} ariaLabel={group.label}>
<MenuGroup key={`${group.label}${index}`} label={group.label}>
{(group.items || []).map((item) => (
<MenuItem
key={`${item.label}`}
url={item.url}
label={item.label}
ariaLabel={item.label}
target={item.target}
icon={item.icon}
active={item.active}

View File

@@ -72,7 +72,7 @@ export interface GraphNGState {
}
/**
* "Time as X" core component, expectes ascending x
* "Time as X" core component, expects ascending x
*/
export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
static contextType = PanelContextRoot;
@@ -115,7 +115,7 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
state = {
alignedFrame,
alignedData: config!.prepData!(alignedFrame),
alignedData: config!.prepData!([alignedFrame]) as AlignedData,
config,
};
@@ -138,7 +138,7 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
const u = this.plotInstance.current;
if (u) {
// Try finding left position on time axis
const left = u.valToPos(evt.payload.point.time, 'time');
const left = u.valToPos(evt.payload.point.time, 'x');
let top;
if (left) {
// find midpoint between points at current idx
@@ -195,7 +195,7 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
if (shouldReconfig) {
newState.config = this.props.prepConfig(newState.alignedFrame, this.props.frames, this.getTimeRange);
newState.alignedData = newState.config.prepData!(newState.alignedFrame);
newState.alignedData = newState.config.prepData!([newState.alignedFrame]) as AlignedData;
pluginLog('GraphNG', false, 'config recreated', newState.config);
}
}

Some files were not shown because too many files have changed in this diff Show More