Merge pull request #180 from flant/chore_remove_dist

Remove dist folder
This commit is contained in:
Ivan Mikheykin
2021-02-17 12:51:21 +03:00
committed by GitHub
22 changed files with 2 additions and 907 deletions
+1
View File
@@ -1,3 +1,4 @@
dist
node_modules
.jshintrc
.idea
-81
View File
@@ -1,81 +0,0 @@
# Changelog
## v0.4.0
- Fix to work with Grafana 7.4.x
- Migrate to grafana-toolkit and yarn to build and sign.
- Cleanup dist directory, reduce compiled plugin size.
- Code cleanup: fix linter errors and warnings
- Add Github Actions configuration to automate release process.
- Add unobtrusive branding.
## v0.3.4
- Fix to work in Grafana 7.2.0,7.2.1
- Fix 'name' in tooltip for opacity and gradient modes
- Fix color scale for opacity and gradient modes
## v0.3.3
- Fix fallback to string events for older versions of Grafana
## v0.3.2
- Fix plugin metadata for Grafana repository
## v0.3.1
- Fix to work in Grafana 7.1.0
## v0.3.0
- Tooltip freeze on click
- Show URLs in tooltip
- Pagination controls
- Fix tooltip and null buckets
- Fix display for 6.7+, 7.0+
## v0.2.0
- Migrate code base to typescript
- Fixes to work in 6.3.0+ grafana
## v0.1.1
- Fix for annotations in grafana 5.x before 5.4
## v0.1.0
- Tested with Grafana 6.0.0
- Tested with InfluxDB and Mysql datasources
- Add initial support for display annotations
- Add example for k8s statuses (thanks, @vrutkovs)
- Fix hanging on big values
- Fix horizontal spacing = 0
- Fix for "Object doesn't support property or method 'remove'"
- Fix card width for targets with different datapoints count
## v0.0.4
- Fix display of multivalues buckets as an empty cell
## v0.0.3
- Add solarized preset
- Reorganize statuses editor for discrete mode
- Separate options for vertical and horizontal spacing for cards
- Add simple sort options for Y axis
- Fix display null values as zero
## v0.0.2
- Install with GF_INSTALL_PLUGINS
- Fix legend overlap
- Fix colors for dark theme
- Fix panel rendering timeout error
## v0.0.1
- First public release
-22
View File
@@ -1,22 +0,0 @@
MIT License
Copyright (c) 2018 Flant
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-209
View File
@@ -1,209 +0,0 @@
# Statusmap panel for Grafana
[![Download from GitHub](https://img.shields.io/github/tag-date/flant/grafana-statusmap.svg?logo=github&label=latest)](https://github.com/flant/grafana-statusmap/releases/latest)
[![GH Discussions](https://img.shields.io/badge/GitHub-discussions-brightgreen)](https://github.com/flant/grafana-statusmap/discussions)
[![Telegram chat RU](https://img.shields.io/badge/@statusmap_ru-RU-informational.svg?logo=telegram)](https://t.me/statusmap_ru)
[![Follow Flant on Twitter](https://img.shields.io/twitter/follow/flant_com?label=Follow%20Flant&style=social)](https://twitter.com/flant_com)
Panel to show discrete statuses of multiple targets over time.
![Statusmap sample panel](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/flant-statusmap-panel.png)
![Statusmap sample panel with dark theme](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/flant-statusmap-panel-dark.png)
## Features
* Grouping values into rows and buckets using legend from query
* User defined color mapping
* Multiple values in bucket are displayed via tooltip
* Increasing rows/buckets' interval for better visual representation
* Representing null values as empty bucket or zero value
### Supported environment
* Tested with datasources:
- Prometheus
- InfluxDB
- Mysql
* Supported Grafana versions:
- 6.7+ are the most priority (6.7, 7.0-7.4)
- also works in 5.4.3 and 6.0+
## Motivation
We had a desperate need to visualize a set of timeseries statuses over time period, so we can
see a history of changes for objects' status. Since we maintain a lot of Kubernetes clusters
(and related infrastructure), our main cases for that are visualization of servers & Kubernetes
pods health states as well as HTTP services health checks. We've tried a variety of Grafana
plugins available (they are listed in *Acknowledgements* below) but none of them could provide
the features and visualization really close to what we've been looking for.
_NB: You can find more details about our journey of creating the plugin in
[this post](https://medium.com/flant-com/statusmap-grafana-plugin-to-visualize-status-over-time-fe6ced391853)._
_Objects_ being visualized with this plugin may be different: not only IT components (e.g. server
hosts and Kubernetes pods) but just anything you can imagine like coffee makers on the picture
above. These objects should have _discrete statuses_ which are sets of predefined values, e.g.
`ok` = 0, `off` = 1, `fail` = 2, etc.
## Configuration
### Datasource notes
To create neat graphs your datasource should return good data. Plugin adjust `$__interval` variable depending on
bucket width in panel options. Your queries should aggregate statuses over `$__interval`.
To make multiple values mode works as expected you should define multiple queries: one query for each possible status.
Plugin doesn't aggregate data in time for now, it only renders input data as buckets. Because of this
data should contain points for each timestamp in time range and equal timestamps for every possible
target (y-axis label). This limitation is addressed by [issue #53](https://github.com/flant/grafana-statusmap/issues/53).
#### Prometheus
To work with data from Prometheus you will need to setup discrete statuses for your objects.
Requirements to store these statuses in metrics are as follows:
* metrics should have two values: `0` and `1`;
* there should be a label with status' value.
When it's done, you can collect all the data via query, e.g.:
```
(max_over_time(coffee_maker_status{status="<STATUS_VALUE>"}[$__interval]) == 1) * <STATUS_VALUE>
```
If there was no such status (`<STATUS_VALUE>`) during query's interval, Prometheus would
return nothing. Otherwise, status' value will be returned.
For example, if you have 5 types of statuses and a metric (`coffee_maker_status`) with 5
allowed values (`0`, `1`, `2`, `3`, `4`), you should transform this metric using following rule:
```
- record: coffee_maker_status:discrete
expr: |
count_values("status", coffee_maker_status)
```
That's how `coffee_maker_status` metric with value `3` will be transformed into new metric:
```
coffee_maker_status:discrete{status="3"} 1
```
Now, when Prometheus has `0` and `1` values for each status, all these metrics can be
aggregated, so you will get all available statuses of your objects over time.
#### InfluxDB
Choose 'Time series' for 'Format as' and use `GROUP BY ($__interval)` in query. `$tag_<tag name>` can be used in 'Alias by' to define y-axis labels.
#### Mysql
Example query with aggregation over `$__interval` is like this (you need one query for each possible status value):
```
SELECT
$__timeGroupAlias(date_insert,$__interval),
name AS metric,
min(statusi) AS "statusi"
FROM coffee_makers
WHERE
$__timeFilter(date_insert) AND statusi=1
GROUP BY 1,2
ORDER BY $__timeGroup(date_insert,$__interval)
```
`metric` column is used as y-axis label.
### Panel
First of all, an individual query for each possible status' value should be created.
Each query should also have similar legend for grouping:
![Query setup](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/queries-example.png)
Then, color mapping for status' values should be defined in __Discrete__ color mode:
![Color mapping](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/color-mapping.png)
Use can use presets to define a trafic light colors or 8 colors from [solarized](https://ethanschoonover.com/solarized/) palette:
![Color mapping empty](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/color-preset-01.png)
![Color mapping trafic lights](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/color-preset-02.png)
_Note: __Spectrum__ and __Opacity__ color modes function the same way they do in [Heatmap](https://grafana.com/plugins/heatmap) plugin._
### More options
#### Bucket
![Bucket options](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/options-bucket.png)
__Multiple values__ checkbox specifies how they should be displayed:
* If it's off, multiple values for one bucket are treated as error;
* If it's on, color for such bucket would be determined by the value having least index in color mapping.
![Color mapping](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/multiple-values-error.png)
__Display nulls__ can be treated as empty buckets or displayed with the color of `0` value.
![Color mapping](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/null-as-empty.png)
__Min width__ and __spacing__ are used to specify minimal bucket width and spacing between buckets.
__Rounding__ may be used to round edges.
![Min width, spacing, rounding 1](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/min-width-spacing-rounding-01.png)
![Min width, spacing, rounding 2](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/min-width-spacing-rounding-02.png)
__Values index__ set to positive number to display only values from specified timeseries.
#### Display
![Display options](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/options-display.png)
__Show legend__ checkbox toggles legend at the bottom of the panel.
__Rows sort__ can be used to sort labels on Y axis. Metrics — sort y labels as they are defined on Metrics tab. a→z and z→a sort labels descending or ascending in a [natural](https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare) order.
#### Pagination
![Pagination controls](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/pagination-graph.png)
__Enable pagination__ toggles pagination controls on graph.
__Rows per page__ a number of rows to display on graph.
#### Tooltip
![Tooltip in frozen state](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/tooltip-frozen.png)
__Show tooltip__ toggles tooltip display on mouse over buckets.
__Freeze on click__ toggles tooltip "freezing" on click. Frozen tooltip can be used to compare data with floating tooltip or to follow URLs.
__Show items__ toggles display of additional items in tooltip.
__Items__ is a list of definitions to display URLs in tooltip.
Each URL has a template, icon, label and formating options: lowercase and date format for variables.
![Tooltip items editor](https://raw.githubusercontent.com/flant/grafana-statusmap/master/docs/img/tooltip-editor.png)
## Learn more
* [Changelog](https://github.com/flant/grafana-statusmap/blob/master/CHANGELOG.md)
* Use [GitHub Discussions](https://github.com/flant/grafana-statusmap/discussions) to ask for help.
* [Installation](https://grafana.com/grafana/plugins/flant-statusmap-panel/installation)
* Setup [development](https://github.com/flant/grafana-statusmap/blob/master/DEVELOPMENT.md) environment to help us improve the plugin.
## Acknowledgements
The first public release of this plugin has been fully made by [Flant](https://flant.com/) engineers. The whole idea has come from Dmitry Stolyarov ([@distol](https://github.com/distol)), initial version has been written by Sergey Gnuskov ([@gsmetal](https://github.com/gsmetal)) and final changes has been made by Ivan Mikheykin ([@diafour](https://github.com/diafour)).
This plugin is based on "Heatmap" panel by Grafana and partly inspired by ideas from Carpet plot, Discrete panel, Status Panel, Status Dot, Status By Group.
-2
View File
@@ -1,2 +0,0 @@
define((function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=12)}({12:function(e,t,n){}})}));
//# sourceMappingURL=dark.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack:///webpack/bootstrap"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s"],"mappings":"sCACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,IAIjBlC,EAAoBA,EAAoBmC,EAAI,I","file":"dark.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 12);\n"],"sourceRoot":""}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

-46
View File
@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1"
id="Layer_1" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px"
viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="49.9995" y1="0" x2="49.9995" y2="100.0005">
<stop offset="0" style="stop-color:#4748FF"/>
<stop offset="1" style="stop-color:#4F1A98"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M0,8.504C0,3.827,3.827,0,8.504,0h82.992C96.173,0,100,3.827,100,8.504v82.992
c0,4.677-3.827,8.504-8.504,8.504H8.504C3.827,100,0,96.173,0,91.496V8.504z"/>
</g>
<g>
<rect x="37.675" y="7.334" fill="#00A94C" width="9.139" height="19.773"/>
<rect x="37.675" y="29.216" fill="#00A94C" width="9.139" height="19.773"/>
<rect x="37.675" y="72.98" fill="#00A94C" width="9.139" height="19.686"/>
<rect x="37.675" y="51.099" fill="#00A94C" width="9.139" height="19.598"/>
<rect x="48.66" y="7.334" fill="#00A94C" width="9.139" height="19.773"/>
<rect x="48.66" y="72.894" fill="#00A94C" width="9.139" height="19.772"/>
</g>
<rect x="48.66" y="51.099" fill="#FFFF00" width="9.139" height="19.598"/>
<rect x="59.557" y="7.334" fill="#FF6A13" width="9.14" height="19.773"/>
<g>
<rect x="59.557" y="29.216" fill="#00A94C" width="9.14" height="19.773"/>
<rect x="48.572" y="29.216" fill="#00A94C" width="9.14" height="19.773"/>
<rect x="59.557" y="72.894" fill="#00A94C" width="9.14" height="19.772"/>
<rect x="59.557" y="51.099" fill="#00A94C" width="9.14" height="19.598"/>
</g>
<rect x="70.454" y="7.334" fill="#FF6A13" width="9.14" height="19.773"/>
<g>
<rect x="70.454" y="29.216" fill="#00A94C" width="9.14" height="19.773"/>
<rect x="70.454" y="72.894" fill="#00A94C" width="9.14" height="19.772"/>
<rect x="70.454" y="51.099" fill="#00A94C" width="9.14" height="19.685"/>
<rect x="81.439" y="29.216" fill="#00A94C" width="9.14" height="19.773"/>
<rect x="81.439" y="72.894" fill="#00A94C" width="9.14" height="19.772"/>
<rect x="81.439" y="51.099" fill="#00A94C" width="9.14" height="19.598"/>
<rect x="81.439" y="7.334" fill="#00A94C" width="9.14" height="19.773"/>
</g>
<rect x="9.421" y="15.335" fill="#FFFFFF" width="23.069" height="3.771"/>
<rect x="15.133" y="37.217" fill="#FFFFFF" width="17.356" height="3.771"/>
<rect x="20.956" y="57.956" fill="#FFFFFF" width="11.534" height="3.772"/>
<rect x="9.421" y="79.839" fill="#FFFFFF" width="23.069" height="3.771"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

-2
View File
@@ -1,2 +0,0 @@
define((function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=11)}({11:function(e,t,n){}})}));
//# sourceMappingURL=light.js.map
-1
View File
@@ -1 +0,0 @@
{"version":3,"sources":["webpack:///webpack/bootstrap"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s"],"mappings":"sCACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,IAIjBlC,EAAoBA,EAAoBmC,EAAI,I","file":"light.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 11);\n"],"sourceRoot":""}
-37
View File
@@ -1,37 +0,0 @@
<div class="status-heatmap-wrapper">
<div class="status-heatmap-canvas-wrapper">
<div class="datapoints-warning" ng-if="ctrl.multipleValues || ctrl.noColorDefined || ctrl.noDatapoints">
<span class="small" ng-if="ctrl.multipleValues" bs-tooltip="'{{ctrl.dataWarnings.multipleValues.tip}}'">{{ctrl.dataWarnings.multipleValues.title}}</span>
<span class="small" ng-if="ctrl.noColorDefined" bs-tooltip="'{{ctrl.dataWarnings.noColorDefined.tip}}'">{{ctrl.dataWarnings.noColorDefined.title}}</span>
<span class="small" ng-if="ctrl.noDatapoints" bs-tooltip="'{{ctrl.dataWarnings.noDatapoints.tip}}'">{{ctrl.dataWarnings.noDatapoints.title}}</span>
</div>
<div class="statusmap-panel" ng-dblclick="ctrl.zoomOut()"></div>
</div>
<div class="status-heatmap-legend-wrapper" ng-if="ctrl.panel.legend.show">
<status-heatmap-legend></status-heatmap-legend>
</div>
<div class="clearfix"></div>
<div class="statusmap-pagination gf-form" ng-if="ctrl.panel.usingPagination">
<div class="gf-form">
<button class="btn btn-inverse" ng-disabled="!pager.hasPrev()" ng-click="ctrl.onPrevPage()">
<i class="fa fa-arrow-left"></i>&nbsp;Previous
</button>
<label class="gf-form-label">{{pager.currentPage+1}}/{{pager.pages()}}</label>
<button class="btn btn-inverse last-in-group" ng-disabled="!pager.hasNext()" ng-click="ctrl.onNextPage()">
Next&nbsp;<i class="fa fa-arrow-right"></i>
</button>
</div>
<div class="gf-form">
<label class="gf-form-label">Rows per page</label>
<input type="number" class="gf-form-input width-3 last-in-group" placeholder="12" data-placement="top"
bs-tooltip="'Number of rows to show per page.'" ng-model="ctrl.pageSizeViewer" ng-change="ctrl.onChangePageSize()"
ng-model-onblur>
</div>
<label class="gf-form-label">Show {{pager.pageStartRow()}} to {{pager.pageEndRow()}} of {{pager.totalRows()}} rows</label>
</div>
</div>
<div class="clearfix"></div>
-3
View File
File diff suppressed because one or more lines are too long
-14
View File
@@ -1,14 +0,0 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
-1
View File
File diff suppressed because one or more lines are too long
-285
View File
@@ -1,285 +0,0 @@
<div ng-show="ctrl.multipleValues">
<strong>Error</strong>: data has multiple values for one target. Please change target or check "use max value".
</div>
<div ng-show="ctrl.noColorDefined">
<strong>Error</strong>: data value with undefined color. Check metric values, color values or define new color.
</div>
<div class="editor-row">
<div class="section gf-form-group">
<h5 class="section-heading">Colors</h5>
<div class="gf-form">
<label class="gf-form-label width-9">Mode</label>
<div class="gf-form-select-wrapper width-8">
<select class="input-small gf-form-input" ng-model="ctrl.panel.color.mode" ng-options="s for s in ctrl.colorModes" ng-change="ctrl.render()"></select>
</div>
</div>
<div ng-show="ctrl.panel.color.mode === 'opacity'">
<div class="gf-form" ng-show="ctrl.panel.useMax">
<strong>Note:</strong> Bucket color determined by maximum value in bucket<br/>
</div>
<div class="gf-form">
<label class="gf-form-label width-9">Color</label>
<span class="gf-form-label">
<color-picker color="ctrl.panel.color.cardColor" onChange="ctrl.onCardColorChange"></color-picker>
</span>
</div>
<div class="gf-form">
<label class="gf-form-label width-9">Scale</label>
<div class="gf-form-select-wrapper width-8">
<select class="input-small gf-form-input" ng-model="ctrl.panel.color.colorScale" ng-options="s for s in ctrl.opacityScales" ng-change="ctrl.render()"></select>
</div>
</div>
<div class="gf-form" ng-if="ctrl.panel.color.colorScale === 'sqrt'">
<label class="gf-form-label width-9">Exponent</label>
<input type="number" class="gf-form-input width-8" placeholder="auto" data-placement="right" bs-tooltip="''" ng-model="ctrl.panel.color.exponent" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
</div>
<div ng-show="ctrl.panel.color.mode === 'spectrum'">
<div class="gf-form" ng-show="ctrl.panel.useMax">
<strong>Note:</strong> Bucket color determined by maximum value in bucket<br/>
</div>
<div class="gf-form">
<label class="gf-form-label width-9">Scheme</label>
<div class="gf-form-select-wrapper width-8">
<select class="input-small gf-form-input" ng-model="ctrl.panel.color.colorScheme" ng-options="s.value as s.name for s in ctrl.colorSchemes" ng-change="ctrl.render()"></select>
</div>
</div>
</div>
<div ng-show="ctrl.panel.color.mode === 'discrete'">
<div class="gf-form" ng-show="ctrl.panel.useMax">
<strong>Note:</strong> Multiple values displayed using color with least index<br/>
</div>
<div class="gf-form" ng-show="ctrl.panel.color.thresholds.length == 0">
<label class="gf-form-label width-2">0</label>
<label class="gf-form-input width-30">No statuses defined. Add new status or use presets below.</label>
</div>
<div class="gf-form-inline" ng-repeat="threshold in ctrl.panel.color.thresholds">
<div class="gf-form">
<label class="gf-form-label width-2">{{ $index }}</label>
</div>
<div class="gf-form">
<label class="gf-form-label width-9 query-keyword" ng-if="ctrl.panel.useMax">If bucket has value</label>
<label class="gf-form-label width-9 query-keyword" ng-if="!ctrl.panel.useMax">If bucket value ==</label>
<input type="text" class="input-small gf-form-input width-4" ng-model="threshold.value" ng-change="ctrl.render()"/>
<label class="gf-form-label query-keyword">
fill
</label>
<label class="gf-form-label">
<spectrum-picker ng-model="threshold.color" ng-change="ctrl.render()"/>
</label>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword">set tooltip</label>
<input type="text" class="input-small gf-form-input width-9" ng-model="threshold.tooltip" ng-change="ctrl.render()"/>
</div>
<div class="gf-form">
<label class="gf-form-label">
<i class="fa fa-trash pointer" ng-click="editor.onRemoveThreshold($index)"></i>
</label>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form"></div>
<div class="gf-form">
<button class="btn btn-inverse" ng-click="editor.onAddThreshold()">
<i class="fa fa-plus"></i> Add new status
</button>
</div>
<div class="gf-form">
<button class="btn btn-inverse" ng-click="editor.onRemoveThresholds()">
<i class="fa fa-minus"></i> Remove all
</button>
</div>
</div>
<div class="gf-form-inline" ng-show="ctrl.panel.color.thresholds.length == 0">
<div class="gf-form"></div>
<div class="gf-form">
<label class="gf-form-label">Presets</label>
</div>
<div class="gf-form">
<button class="btn" ng-click="editor.onAddThreeLights()">
Red-Yellow-Green
</button>
</div>
<div class="gf-form">
<button class="btn" ng-click="editor.onAddSolarized()">
Solarized
</button>
</div>
</div>
</div>
<div class="gf-form" ng-show="ctrl.panel.color.mode !== 'discrete'">
<options-color-legend></options-color-legend>
</div>
</div>
<div class="section gf-form-group" ng-show="ctrl.panel.color.mode !== 'discrete'">
<h5 class="section-heading">Color scale</h5>
<div class="gf-form">
<label class="gf-form-label width-8">Min value</label>
<input type="number" ng-model="ctrl.panel.color.min" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Max value</label>
<input type="number" ng-model="ctrl.panel.color.max" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
</div>
<div class="section gf-form-group">
<h5 class="section-heading">Display</h5>
<gf-form-switch class="gf-form" label-class="width-8"
label="Show legend"
checked="ctrl.panel.legend.show" on-change="ctrl.render()">
</gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-8"
label="Show X axis"
checked="ctrl.panel.xAxis.show" on-change="ctrl.render()">
</gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-8"
label="Show Y axis"
checked="ctrl.panel.yAxis.show" on-change="ctrl.render()">
</gf-form-switch>
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
<label class="gf-form-label width-8">Min width</label>
<input type="number" ng-model="ctrl.panel.yAxis.minWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
</div>
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
<label class="gf-form-label width-8">Max width</label>
<input type="number" ng-model="ctrl.panel.yAxis.maxWidth" class="gf-form-input width-5" placeholder="auto" data-placement="right" bs-tooltip="''" ng-change="ctrl.render()" ng-model-onblur>
</div>
<div class="gf-form" ng-show="ctrl.panel.yAxis.show">
<label class="gf-form-label width-8">Rows sort</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input max-width-8"
ng-model="ctrl.panel.yAxisSort"
ng-options="f for f in ['metrics', 'a → z', 'z → a']"
ng-change="ctrl.render()"></select>
</div>
</div>
</div>
<div class="section gf-form-group">
<h5 class="section-heading">Buckets</h5>
<gf-form-switch class="gf-form" label-class="width-8"
label="Multiple values"
checked="ctrl.panel.useMax" on-change="ctrl.render()">
</gf-form-switch>
<div class="gf-form" ng-show="ctrl.panel.useMax">
Color for bucket with multiple values is determined by color mode<br/>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Values index</label>
<input type="number" class="gf-form-input width-5" placeholder="-1" data-placement="right"
bs-tooltip="'Display only values with this index in a bucket. Use -1 to display all values'"
ng-model="ctrl.panel.seriesFilterIndex" ng-change="ctrl.refresh()"
ng-model-onblur>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Display nulls</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input max-width-9" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['as empty', 'as zero']" ng-change="ctrl.render()"></select>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Min width</label>
<input type="number" class="gf-form-input width-5" placeholder="5" data-placement="right" bs-tooltip="'Minimal card width for 1/1 resolution in pixels'" ng-model="ctrl.panel.cards.cardMinWidth" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">V spacing</label>
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards vertical spacing in pixels'" ng-model="ctrl.panel.cards.cardVSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">H spacing</label>
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="right" bs-tooltip="'Cards horizontal spacing in pixels'" ng-model="ctrl.panel.cards.cardHSpacing" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Rounding</label>
<input type="number" class="gf-form-input width-5" placeholder="0" data-placement="right" bs-tooltip="'Cards rounding radius in pixels'" ng-model="ctrl.panel.cards.cardRound" ng-change="ctrl.refresh()" ng-model-onblur>
</div>
</div>
<div class="section gf-form-group">
<h5 class="section-heading">Y-axis label</h5>
<div class="gf-form">
<gf-form-switch class="gf-form" label="Split query alias" label-class="width-12"
checked="ctrl.panel.yLabel.usingSplitLabel" on-change="ctrl.refresh()"></gf-form-switch>
</div>
<div class="gf-form" ng-if="ctrl.panel.yLabel.usingSplitLabel">
<label class="gf-form-label width-10">Delimiter
<info-popover mode="left-normal">
<p>Label splitter</p>
<span>
Set the string to split the original alias to generate partials to be used on the link and custom y-label
<span>
</info-popover>
</label>
<input type="text" class="gf-form-input width-10" placeholder="." data-placement="top"
ng-model="ctrl.panel.yLabel.delimiter" ng-change="ctrl.refresh()"
ng-model-onblur>
</div>
<div class="gf-form" ng-if="ctrl.panel.yLabel.usingSplitLabel">
<label class="gf-form-label width-10">Label template
<info-popover mode="left-normal">
<p>
<span>Override the series label</span>
<br>
<span> If blank, it will be used ${__y_label}</span>
</p>
<span>
Use special variables:
<br>
<em>${__y_label}</em> original name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_trim}</em> trimmed name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_N}</em> partial name of the time series (alias or legend in the query editor), only valid when custom y-label is enabled.
</span>
<span>
<hr>
<span>Examples</span>
<br>
<span>Series original:<em>"linux01.status.ok"</em></span>
<br>
<span>Separator: <em>"."</em></span>
<br>
<span>Label override:</span><em>${__y_label_1}-${__y_label_3} | ${__y_label_0}</em>
<br>
<span>Result: <em>status-ok | linux01</em></span>
</span>
</info-popover>
</label>
<input type="text" class="gf-form-input width-10" placeholder="${__y_label}" data-placement="top"
bs-tooltip="'Leave blank to use original ${__y_label}'" ng-model="ctrl.panel.yLabel.labelTemplate" ng-change="ctrl.refresh()"
ng-model-onblur>
</div>
<br>
<h5 class="section-heading">Pagination</h5>
<div class="gf-form">
<gf-form-switch class="gf-form" label="Enable pagination" label-class="width-12"
checked="ctrl.panel.usingPagination" on-change="ctrl.render()"></gf-form-switch>
</div>
<div class="gf-form" ng-if="ctrl.panel.usingPagination">
<label class="gf-form-label width-10">Rows per page</label>
<input type="number" class="gf-form-input width-5" placeholder="2" data-placement="top"
bs-tooltip="'Number of rows to show by default'" ng-model="ctrl.panel.pageSize" ng-change="ctrl.changeDefaultPaginationSize(ctrl.panel.pageSize)"
ng-model-onblur>
</div>
</div>
</div>
-163
View File
@@ -1,163 +0,0 @@
<div class="editor-row">
<div class="section gf-form-group">
<gf-form-switch class="gf-form" label-class="width-10"
label="Show tooltip"
tooltip="Show tooltip when mouse is over the card"
checked="ctrl.panel.tooltip.show" on-change="ctrl.render()">
</gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-10"
label="Freeze on click"
tooltip="Freeze tooltip copy when card is clicked"
checked="ctrl.panel.tooltip.freezeOnClick" on-change="ctrl.render()">
</gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-10"
label="Show items"
tooltip="Show items (urls) in tooltip"
checked="ctrl.panel.tooltip.showItems" on-change="ctrl.render()">
</gf-form-switch>
</div>
<div class="section gf-form-group">
<h5 class="section-heading">Custom content</h5>
<gf-form-switch class="gf-form" label-class="width-14"
label="Show custom content"
tooltip="'Show custom content on tooltip'"
checked="ctrl.panel.tooltip.showCustomContent" on-change="ctrl.render()">
</gf-form-switch>
<div class="gf-form" ng-if="ctrl.panel.tooltip.showCustomContent">
<label class="gf-form-label width-10">
Template
<info-popover mode="left-normal">
<p>Set custom content that will appear on the tooltip</p>
<span>
Use special variables:
<br>
<em>${__y_label}</em> name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_trim}</em> trimmed name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_N}</em> partial name of the time series (alias or legend in the query editor), only valid when custom y-label is enabled.
<br>
<em>${__url_time_range}</em> refers to graph range in the form of 'from=...&to=...'.
<br>
<em>${__value}</em> refers to current bucket value or max value if multiple values mode is on.
<br>
<em>${__value_N}</em> refers to Nth value in current bucket. Value indexes are started from 0. For instance,
<em>${__value_1}</em> refers to second value.
<br>
<em>${__value_date}</em> refers to __value formatted as date.
<em>${__value_N_date}</em> refers to Nth value in current bucket formatted as date.
</span>
</info-popover>
</label>
<textarea type="text" class="gf-form-input" placeholder="" data-placement="top" cols="100"
bs-tooltip="'Extra Tooltip info'" ng-model="ctrl.panel.tooltip.customContent" ng-change="ctrl.refresh()" ng-model-onblur> </textarea>
</div>
</div>
<br>
<div class="section gf-form-group">
<h5 class="section-heading">Items</h5>
<div class="gf-form" ng-show="ctrl.panel.tooltip.items.length == 0">
<label class="gf-form-label width-2">0</label>
<label class="gf-form-input width-30">No items defined.</label>
</div>
<div>
<div ng-repeat="item in ctrl.panel.tooltip.items">
<div class="gf-form gf-form--grow">
<label class="gf-form-label width-6">
URL
<info-popover mode="left-normal">
<p>Specify an URL (relative or absolute)</p>
<span>
Use special variables:
<br>
<em>${__y_label}</em> name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_trim}</em> trimmed name of the time series (alias or legend in the query editor).
<br>
<em>${__y_label_N}</em> partial name of the time series (alias or legend in the query editor), only valid when custom y-label is enabled.
<br>
<em>${__url_time_range}</em> refers to graph range in the form of 'from=...&to=...'.
<br>
<em>${__value}</em> refers to current bucket value or max value if multiple values mode is on.
<br>
<em>${__value_N}</em> refers to Nth value in current bucket. Value indexes are started from 0. For instance,
<em>${__value_1}</em> refers to second value.
<br>
<em>${__value_date}</em> refers to __value formatted as date.
<em>${__value_N_date}</em> refers to Nth value in current bucket formatted as date.
</span>
</info-popover>
</label>
<input type="text" class="gf-form-input" placeholder="https://www.google.es" data-placement="top"
bs-tooltip="'This is the url to be shown when the user clicks on it'" ng-model="item.urlTemplate"
ng-change="ctrl.refresh()">
<label class="gf-form-label">
<i class="fa fa-trash pointer" ng-click="editor.onRemoveUrl($index)"></i>
</label>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label width-4">Icon</label>
<label class="gf-form-label width-2">
<i class="fa fa-{{item.urlIcon}}"></i>
</label>
<input
class="gf-form-input width-10"
type="text"
ng-model="item.urlIcon"
bs-typeahead="editor.getFAIconClasses"
bs-tooltip="'The icon for URL link'"
data-placement="top"
ng-blur="ctrl.render()"
data-min-length="0"
data-items="100"
/>
</div>
<div class="gf-form">
<label class="gf-form-label width-4">Label</label>
<input type="text" class="gf-form-input width-16" placeholder="My URL" data-placement="top"
bs-tooltip="'Text for URL link'"
ng-model="item.urlText" ng-change="ctrl.refresh()">
</div>
<div class="gf-form">
<gf-form-switch class="gf-form" label-class="width-8" label="Lowercase link" checked="item.urlToLowerCase"
on-change="ctrl.render()">
</gf-form-switch>
</div>
<div class="gf-form">
<label class="gf-form-label width-8">Date format</label>
<input type="text" class="gf-form-input width-12" placeholder="YYYY/MM/DD/HH_mm_ss"
data-placement="top" bs-tooltip="'Date format for __value_date'"
bs-typeahead="editor.getValueDateFormats"
data-min-length="0"
data-items="100"
ng-model="item.valueDateFormat"
ng-blur="ctrl.render()">
</div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form"></div>
<div class="gf-form">
<button class="btn btn-inverse" ng-click="editor.onAddUrl()">
<i class="fa fa-plus"></i> Add URL
</button>
</div>
<div class="gf-form">
<button class="btn btn-inverse" ng-click="editor.onRemoveUrls()">
<i class="fa fa-minus"></i> Remove all
</button>
</div>
</div>
</div>
</div>
</div>
-37
View File
@@ -1,37 +0,0 @@
{
"type": "panel",
"name": "Statusmap",
"id": "flant-statusmap-panel",
"info": {
"description": "Statusmap panel for grafana",
"author": {
"name": "Flant JSC",
"url": "http://flant.com"
},
"keywords": ["status", "statusmap", "heatmap", "panel"],
"logos": {
"small": "img/logo.svg",
"large": "img/logo.svg"
},
"links": [
{"name": "Github", "url": "https://github.com/flant/grafana-statusmap"},
{"name": "MIT Licence", "url": "https://github.com/flant/grafana-statusmap/blob/master/LICENSE"},
{"name": "Developer", "url": "https://flant.com"}
],
"screenshots": [
{"name": "Panel with light theme", "path": "img/flant-statusmap-panel.png"},
{"name": "Panel with dark theme", "path": "img/flant-statusmap-panel-dark.png"},
{"name": "Color mapping", "path": "img/color-mapping.png"},
{"name": "Queries example", "path": "img/queries-example.png"}
],
"version": "0.4.0-pre",
"updated": "2021-02-17"
},
"dependencies": {
"grafanaDependency": ">=5.4.3",
"grafanaVersion": "5.4.x",
"plugins": [ ]
}
}
-1
View File
@@ -1 +0,0 @@
.status-heatmap-canvas-wrapper{cursor:crosshair}.status-heatmap-canvas-wrapper .datapoints-warning{pointer-events:none}.status-heatmap-canvas-wrapper .datapoints-warning span{background-color:#333;color:#d8d9da;padding:1px}.statusmap-panel{position:relative}.statusmap-panel .axis .tick text{fill:#d8d9da;color:#d8d9da;font-size:11px}.statusmap-panel .axis .tick line{opacity:.4;stroke:#8e8e8e}.statusmap-panel svg{pointer-events:none}.statusmap-panel svg rect{pointer-events:visiblePainted}.statusmap-tooltip{position:absolute;padding:10px;font-weight:200;border-radius:5px;max-width:800px;max-height:600px;overflow:hidden;line-height:14px;z-index:9999;white-space:nowrap;font-size:12px;background-color:#141414;color:#d8d9da}.statusmap-tooltip .discrete-item{color:#fff;padding:1px;font-weight:700;text-shadow:0 0 .2em #212124,0 0 .2em #212124,0 0 .2em #212124}.statusmap-tooltip-frozen{position:relative;z-index:1}.statusmap-histogram rect{fill:#8e8e8e}.status-heatmap-crosshair line{stroke:#9f3023;stroke-width:1}.status-heatmap-selection{stroke-width:1;fill:hsla(0,0%,40%,.4);stroke:hsla(0,0%,40%,.8)}.width-c-40{width:40rem!important}.width-c-50{width:50rem!important}.width-c-60{width:60rem!important}.width-c-70{width:70rem!important}.statusmap-pagination{margin-top:5px}.statusmap-pagination input,.statusmap-pagination label{margin-right:0}.statusmap-pagination .last-in-group{margin-right:4px}.pagination-buttons{text-align:right}.status-heatmap-legend-wrapper{margin:0 10px}.status-heatmap-legend-wrapper svg{height:24px;float:left;white-space:nowrap}.status-heatmap-legend-wrapper .status-heatmap-color-legend{margin-top:4px}.status-heatmap-legend-wrapper .status-heatmap-legend-values{display:inline-block}.status-heatmap-legend-wrapper .axis .tick text{fill:#d8d9da;color:#d8d9da;font-size:11px}.status-heatmap-legend-wrapper .axis .tick .domain,.status-heatmap-legend-wrapper .axis .tick line{opacity:.4;stroke:#8e8e8e}
-1
View File
@@ -1 +0,0 @@
.status-heatmap-canvas-wrapper{cursor:crosshair}.status-heatmap-canvas-wrapper .datapoints-warning{pointer-events:none}.status-heatmap-canvas-wrapper .datapoints-warning span{background-color:#e9edf2;color:#52545c;padding:1px}.statusmap-panel{position:relative}.statusmap-panel .axis .tick text{fill:#52545c;color:#52545c;font-size:11px}.statusmap-panel .axis .tick line{opacity:.4;stroke:#767980}.statusmap-panel svg{pointer-events:none}.statusmap-panel svg rect{pointer-events:visiblePainted}.statusmap-tooltip{position:absolute;padding:10px;font-weight:200;border-radius:5px;max-width:800px;max-height:600px;overflow:hidden;line-height:14px;z-index:9999;white-space:nowrap;font-size:12px;background-color:#dde4ed;color:#52545c}.statusmap-tooltip .discrete-item{color:#fff;padding:1px;font-weight:700;text-shadow:0 0 .2em #212124,0 0 .2em #212124,0 0 .2em #212124}.statusmap-tooltip-frozen{position:relative;z-index:1}.statusmap-histogram rect{fill:#767980}.status-heatmap-crosshair line{stroke:#9e2f22;stroke-width:1}.status-heatmap-selection{stroke-width:1;fill:hsla(0,0%,40%,.4);stroke:hsla(0,0%,40%,.8)}.width-c-40{width:40rem!important}.width-c-50{width:50rem!important}.width-c-60{width:60rem!important}.width-c-70{width:70rem!important}.statusmap-pagination{margin-top:5px}.statusmap-pagination input,.statusmap-pagination label{margin-right:0}.statusmap-pagination .last-in-group{margin-right:4px}.pagination-buttons{text-align:right}.status-heatmap-legend-wrapper{margin:0 10px}.status-heatmap-legend-wrapper svg{height:24px;float:left;white-space:nowrap}.status-heatmap-legend-wrapper .status-heatmap-color-legend{margin-top:4px}.status-heatmap-legend-wrapper .status-heatmap-legend-values{display:inline-block}.status-heatmap-legend-wrapper .axis .tick text{fill:#52545c;color:#52545c;font-size:11px}.status-heatmap-legend-wrapper .axis .tick .domain,.status-heatmap-legend-wrapper .axis .tick line{opacity:.4;stroke:#767980}