├── .gitignore ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── dashboards ├── chronix-grafana-csv-file-example.json └── chronix-grafana-default-dashboard.json ├── dist ├── README.md ├── config-controller.js ├── config-controller.js.map ├── datasource.js ├── datasource.js.map ├── img │ ├── logo.png │ └── screenshot.png ├── module.js ├── module.js.map ├── partials │ ├── config.html │ └── query.editor.html ├── plugin.json ├── query-controller.js └── query-controller.js.map ├── img ├── logo.png └── screenshot.png ├── package.json ├── plugin.json ├── src ├── config-controller.js ├── datasource.js ├── module.js ├── partials │ ├── config.html │ └── query.editor.html └── query-controller.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | .idea 15 | 16 | grafana-* 17 | 18 | node_modules 19 | npm-debug-log 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: node 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.initConfig({ 6 | 7 | clean: ['dist'], 8 | 9 | copy: { 10 | srcAssets: { 11 | cwd: 'src', 12 | expand: true, 13 | src: ['**/*', '!**/*.js'], 14 | dest: 'dist' 15 | }, 16 | pluginAssets: { 17 | cwd: '.', 18 | expand: true, 19 | src: ['plugin.json', 'README.md', 'img/**/*'], 20 | dest: 'dist' 21 | } 22 | }, 23 | 24 | babel: { 25 | options: { 26 | sourceMap: true, 27 | presets: ['es2015'], 28 | plugins: ['transform-es2015-modules-systemjs', 'transform-es2015-for-of'] 29 | }, 30 | dist: { 31 | files: [{ 32 | cwd: 'src', 33 | expand: true, 34 | src: ['**/*.js'], 35 | dest: 'dist', 36 | ext: '.js' 37 | }] 38 | } 39 | }, 40 | 41 | watch: { 42 | src: { 43 | files: ['src/**/*.js'], 44 | tasks: ['babel'], 45 | options: { 46 | spawn: false, 47 | atBegin: true 48 | } 49 | }, 50 | srcAssets: { 51 | files: ['**/*', '!**/*.js'], 52 | tasks: ['copy:srcAssets'], 53 | options: { 54 | spawn: false, 55 | atBegin: true 56 | } 57 | }, 58 | pluginAssets: { 59 | files: ['plugin.json', 'README.md', 'img/**/*'], 60 | tasks: ['copy:pluginAssets'], 61 | options: { 62 | spawn: false, 63 | atBegin: true 64 | } 65 | } 66 | } 67 | 68 | }); 69 | 70 | grunt.registerTask('default', ['clean', 'copy', 'babel']); 71 | 72 | grunt.registerTask('test', 'stub for tests', function () { 73 | grunt.log.ok(); 74 | }); 75 | 76 | }; 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/ChronixDB/chronix.grafana](https://badges.gitter.im/ChronixDB/chronix.grafana.svg)](https://gitter.im/ChronixDB/chronix.grafana?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | [![Build Status](https://travis-ci.org/ChronixDB/chronix.grafana.svg?branch=master)](https://travis-ci.org/ChronixDB/chronix.grafana) 3 | [![Dependency Status](https://dependencyci.com/github/ChronixDB/chronix.grafana/badge)](https://dependencyci.com/github/ChronixDB/chronix.grafana) 4 | [![Apache License 2](http://img.shields.io/badge/license-ASF2-blue.svg)](LICENSE) 5 | 6 | # Chronix Grafana Datasource Plugin 7 | 8 | This is a "datasource" plugin that lets you use time series from [Chronix-Server](https://github.com/ChronixDB/chronix.server) 9 | and visualize them with [Grafana](https://grafana.net/). 10 | 11 | It works with Grafana > 3.X.X. 12 | 13 | ![Chronix-Grafana-Integration](img/screenshot.png) 14 | 15 | ## Features 16 | 17 | The plugin supports all the native implemented aggregations, transformations, and analyses of Chronix-Server. 18 | We will provide more details soon ;-) 19 | 20 | ## Usage 21 | 22 | Currently, the plugin is only available at the chronix github repository. It is planned to release the plugin within 23 | the app store of grafana. 24 | 25 | To use the plugin, simply clone this repository into your Grafana installation's `{inst-dir}/data/plugins/` directory. 26 | 27 | Optionally, you can download and start from the example dashboard: 28 | 29 | 1. Download and extract the latest [chronix.server](https://github.com/ChronixDB/chronix.server/releases/latest) and start it by cd'ing into the extracted directory and running `bin/solr start`. 30 | 2. Download and extract the latest *importer.zip* from the latest [chronix.examples](https://github.com/ChronixDB/chronix.examples/releases/latest) release and run it by cd'ing into the extracted folder and running `./import`. 31 | 3. Create a datasource called *Chronix* that points to http://localhost:8983/solr/chronix (no credentials needed). 32 | 4. Import the example dashboard(s) from 'dashboards' into your running Grafana. 33 | 34 | ## Contributing 35 | 36 | Is there anything missing? Do you have ideas for new features or improvements? You are highly welcome to contribute 37 | your improvements to the Chronix projects. All you have to do is to fork this repository, improve the code and issue a 38 | pull request. 39 | 40 | ## Developing the plugin 41 | 42 | ### Basics 43 | 44 | * All actual code sources live in `src` and can be written in ES6 / ES2015 - this allows us to use proper imports, 45 | exports and all the other syntactic goodies. 46 | * The `dist` folder is actually checked into git, too. We do this so that Grafana auto-detects the dist folder and uses 47 | it even if you just cloned the repository into Grafana (as described above). 48 | * This means that whenever you're changing something in `src`, you really should run the build at least once so that the 49 | contents of `dist` are "in sync", too, when you're committing / pushing / issuing a PR. 50 | 51 | ### Set up (only needs to be done once) 52 | 53 | Use a command prompt that provides NodeJS and NPM. In it, simply run 54 | 55 | npm install 56 | 57 | to install all (dev-) dependencies for the build. 58 | 59 | ### Changing stuff 60 | 61 | To run the build once in order to re-create the `dist` folder, run 62 | 63 | npm run build 64 | 65 | If you want the build to watch your `src` files and auto-run whenever you hit save, run 66 | 67 | npm run watch 68 | 69 | (you can end the watcher by pressing CTRL+C in that command prompt) 70 | 71 | ## Maintainer 72 | 73 | Florian Lautenschlager @flolaut 74 | 75 | ## License 76 | 77 | This software is provided under the Apache License, Version 2.0 license. 78 | 79 | See the [LICENSE](LICENSE) file for details. 80 | -------------------------------------------------------------------------------- /dashboards/chronix-grafana-csv-file-example.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 3, 3 | "title": "Chronix-Dashboard", 4 | "tags": [], 5 | "style": "dark", 6 | "timezone": "browser", 7 | "editable": true, 8 | "hideControls": false, 9 | "sharedCrosshair": false, 10 | "rows": [ 11 | { 12 | "collapse": false, 13 | "editable": true, 14 | "height": "300px", 15 | "panels": [ 16 | { 17 | "aliasColors": {}, 18 | "bars": false, 19 | "datasource": null, 20 | "downsampling": "avg", 21 | "editable": true, 22 | "error": false, 23 | "fill": 1, 24 | "grid": { 25 | "threshold1": null, 26 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 27 | "threshold2": null, 28 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 29 | }, 30 | "height": "250px", 31 | "id": 1, 32 | "isNew": true, 33 | "legend": { 34 | "alignAsTable": false, 35 | "avg": true, 36 | "current": false, 37 | "max": false, 38 | "min": true, 39 | "rightSide": false, 40 | "show": true, 41 | "total": true, 42 | "values": true 43 | }, 44 | "lines": true, 45 | "linewidth": 2, 46 | "links": [], 47 | "nullPointMode": "connected", 48 | "percentage": false, 49 | "pointradius": 5, 50 | "points": false, 51 | "renderer": "flot", 52 | "seriesOverrides": [], 53 | "span": 12, 54 | "stack": false, 55 | "steppedLine": false, 56 | "targets": [ 57 | { 58 | "alias": "Load-One", 59 | "downsampling": "avg", 60 | "errors": {}, 61 | "groupBy": { 62 | "timeInterval": "1s" 63 | }, 64 | "hide": false, 65 | "horAggregator": { 66 | "factor": "1", 67 | "percentile": "0.75", 68 | "samplingRate": "1s", 69 | "unit": "millisecond" 70 | }, 71 | "metric": "metric:*Load*one", 72 | "refId": "A" 73 | }, 74 | { 75 | "alias": "Load-Five", 76 | "downsampling": "avg", 77 | "errors": {}, 78 | "groupBy": { 79 | "timeInterval": "1s" 80 | }, 81 | "horAggregator": { 82 | "factor": "1", 83 | "percentile": "0.75", 84 | "samplingRate": "1s", 85 | "unit": "millisecond" 86 | }, 87 | "metric": "metric:*Load*five", 88 | "refId": "B" 89 | }, 90 | { 91 | "alias": "Load-Ten", 92 | "downsampling": "avg", 93 | "errors": {}, 94 | "groupBy": { 95 | "timeInterval": "1s" 96 | }, 97 | "horAggregator": { 98 | "factor": "1", 99 | "percentile": "0.75", 100 | "samplingRate": "1s", 101 | "unit": "millisecond" 102 | }, 103 | "metric": "metric:*Load*fifteen", 104 | "refId": "C" 105 | } 106 | ], 107 | "timeFrom": null, 108 | "timeShift": null, 109 | "title": "System CPU: One / Five / Fifteen Minutes", 110 | "tooltip": { 111 | "msResolution": true, 112 | "shared": true, 113 | "sort": 0, 114 | "value_type": "cumulative" 115 | }, 116 | "transparent": false, 117 | "type": "graph", 118 | "xaxis": { 119 | "show": true 120 | }, 121 | "yaxes": [ 122 | { 123 | "format": "short", 124 | "label": "Load", 125 | "logBase": 1, 126 | "max": null, 127 | "min": null, 128 | "show": true 129 | }, 130 | { 131 | "format": "ms", 132 | "label": "Time", 133 | "logBase": 1, 134 | "max": null, 135 | "min": null, 136 | "show": false 137 | } 138 | ] 139 | } 140 | ], 141 | "showTitle": true, 142 | "title": "System Load" 143 | }, 144 | { 145 | "collapse": false, 146 | "editable": true, 147 | "height": "300px", 148 | "panels": [ 149 | { 150 | "aliasColors": {}, 151 | "bars": false, 152 | "datasource": null, 153 | "downsampling": "avg", 154 | "editable": true, 155 | "error": false, 156 | "fill": 1, 157 | "grid": { 158 | "threshold1": null, 159 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 160 | "threshold2": null, 161 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 162 | }, 163 | "id": 2, 164 | "isNew": true, 165 | "legend": { 166 | "avg": false, 167 | "current": false, 168 | "max": false, 169 | "min": false, 170 | "show": true, 171 | "total": false, 172 | "values": false 173 | }, 174 | "lines": true, 175 | "linewidth": 2, 176 | "links": [], 177 | "nullPointMode": "connected", 178 | "percentage": false, 179 | "pointradius": 5, 180 | "points": false, 181 | "renderer": "flot", 182 | "seriesOverrides": [], 183 | "span": 12, 184 | "stack": false, 185 | "steppedLine": false, 186 | "targets": [ 187 | { 188 | "alias": "Memory", 189 | "downsampling": "avg", 190 | "errors": {}, 191 | "groupBy": { 192 | "timeInterval": "1s" 193 | }, 194 | "horAggregator": { 195 | "factor": "1", 196 | "percentile": "0.75", 197 | "samplingRate": "1s", 198 | "unit": "millisecond" 199 | }, 200 | "metric": "metric:*Memory/HeapMemoryUsage/used", 201 | "refId": "A" 202 | }, 203 | { 204 | "downsampling": "avg", 205 | "errors": {}, 206 | "groupBy": { 207 | "timeInterval": "1s" 208 | }, 209 | "horAggregator": { 210 | "factor": "1", 211 | "percentile": "0.75", 212 | "samplingRate": "1s", 213 | "unit": "millisecond" 214 | }, 215 | "metric": "metric:*Memory/HeapMemoryUsage/init", 216 | "refId": "B" 217 | }, 218 | { 219 | "downsampling": "avg", 220 | "errors": {}, 221 | "groupBy": { 222 | "timeInterval": "1s" 223 | }, 224 | "horAggregator": { 225 | "factor": "1", 226 | "percentile": "0.75", 227 | "samplingRate": "1s", 228 | "unit": "millisecond" 229 | }, 230 | "metric": "metric:*Memory/HeapMemoryUsage/committed", 231 | "refId": "C" 232 | } 233 | ], 234 | "timeFrom": null, 235 | "timeShift": null, 236 | "title": "Heap Memory", 237 | "tooltip": { 238 | "msResolution": true, 239 | "shared": true, 240 | "sort": 0, 241 | "value_type": "cumulative" 242 | }, 243 | "type": "graph", 244 | "xaxis": { 245 | "show": true 246 | }, 247 | "yaxes": [ 248 | { 249 | "format": "bytes", 250 | "label": null, 251 | "logBase": 1, 252 | "max": null, 253 | "min": null, 254 | "show": true 255 | }, 256 | { 257 | "format": "short", 258 | "label": null, 259 | "logBase": 1, 260 | "max": null, 261 | "min": null, 262 | "show": false 263 | } 264 | ] 265 | } 266 | ], 267 | "title": "New row" 268 | }, 269 | { 270 | "collapse": false, 271 | "editable": true, 272 | "height": "250px", 273 | "panels": [ 274 | { 275 | "addFilterTagMode": false, 276 | "aliasColors": {}, 277 | "bars": false, 278 | "datasource": null, 279 | "downsampling": "avg", 280 | "editable": true, 281 | "error": false, 282 | "fill": 1, 283 | "grid": { 284 | "threshold1": null, 285 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 286 | "threshold2": null, 287 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 288 | }, 289 | "id": 3, 290 | "isNew": true, 291 | "legend": { 292 | "avg": false, 293 | "current": false, 294 | "max": false, 295 | "min": false, 296 | "show": true, 297 | "total": false, 298 | "values": false 299 | }, 300 | "lines": true, 301 | "linewidth": 2, 302 | "links": [], 303 | "nullPointMode": "connected", 304 | "percentage": false, 305 | "pointradius": 5, 306 | "points": false, 307 | "renderer": "flot", 308 | "seriesOverrides": [], 309 | "span": 12, 310 | "stack": false, 311 | "steppedLine": false, 312 | "targets": [ 313 | { 314 | "downsampling": "avg", 315 | "errors": {}, 316 | "groupBy": { 317 | "timeInterval": "1s" 318 | }, 319 | "horAggregator": { 320 | "factor": "1", 321 | "percentile": "0.75", 322 | "samplingRate": "1s", 323 | "unit": "millisecond" 324 | }, 325 | "metric": "metric:*duration", 326 | "refId": "A", 327 | "tags": {} 328 | } 329 | ], 330 | "timeFrom": null, 331 | "timeShift": null, 332 | "title": "Garbage Colleciton", 333 | "tooltip": { 334 | "msResolution": true, 335 | "shared": true, 336 | "sort": 0, 337 | "value_type": "cumulative" 338 | }, 339 | "type": "graph", 340 | "xaxis": { 341 | "show": true 342 | }, 343 | "yaxes": [ 344 | { 345 | "format": "ms", 346 | "label": null, 347 | "logBase": 1, 348 | "max": null, 349 | "min": null, 350 | "show": true 351 | }, 352 | { 353 | "format": "short", 354 | "label": null, 355 | "logBase": 1, 356 | "max": null, 357 | "min": null, 358 | "show": true 359 | } 360 | ] 361 | } 362 | ], 363 | "title": "New row" 364 | } 365 | ], 366 | "time": { 367 | "from": "2016-03-09T22:40:09.521Z", 368 | "to": "2016-03-10T13:24:42.454Z" 369 | }, 370 | "timepicker": { 371 | "refresh_intervals": [ 372 | "5s", 373 | "10s", 374 | "30s", 375 | "1m", 376 | "5m", 377 | "15m", 378 | "30m", 379 | "1h", 380 | "2h", 381 | "1d" 382 | ], 383 | "time_options": [ 384 | "5m", 385 | "15m", 386 | "1h", 387 | "6h", 388 | "12h", 389 | "24h", 390 | "2d", 391 | "7d", 392 | "30d" 393 | ] 394 | }, 395 | "templating": { 396 | "list": [] 397 | }, 398 | "annotations": { 399 | "list": [] 400 | }, 401 | "refresh": false, 402 | "schemaVersion": 12, 403 | "version": 2, 404 | "links": [], 405 | "gnetId": null 406 | } -------------------------------------------------------------------------------- /dashboards/chronix-grafana-default-dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 1, 3 | "title": "Chronix Grafana Default Dashboard", 4 | "tags": [], 5 | "style": "dark", 6 | "timezone": "browser", 7 | "editable": true, 8 | "hideControls": false, 9 | "sharedCrosshair": false, 10 | "rows": [ 11 | { 12 | "collapse": false, 13 | "editable": true, 14 | "height": "250px", 15 | "panels": [ 16 | { 17 | "aliasColors": {}, 18 | "bars": false, 19 | "datasource": "Chronix", 20 | "downsampling": "avg", 21 | "editable": true, 22 | "error": false, 23 | "fill": 1, 24 | "grid": { 25 | "threshold1": null, 26 | "threshold1Color": "rgba(216, 200, 27, 0.27)", 27 | "threshold2": null, 28 | "threshold2Color": "rgba(234, 112, 112, 0.22)" 29 | }, 30 | "id": 1, 31 | "isNew": true, 32 | "legend": { 33 | "avg": false, 34 | "current": false, 35 | "max": false, 36 | "min": false, 37 | "show": true, 38 | "total": false, 39 | "values": false 40 | }, 41 | "lines": true, 42 | "linewidth": 2, 43 | "links": [], 44 | "nullPointMode": "connected", 45 | "percentage": false, 46 | "pointradius": 5, 47 | "points": false, 48 | "renderer": "flot", 49 | "seriesOverrides": [], 50 | "span": 12, 51 | "stack": false, 52 | "steppedLine": false, 53 | "targets": [ 54 | { 55 | "downsampling": "avg", 56 | "errors": {}, 57 | "horAggregator": { 58 | "factor": "1", 59 | "percentile": "0.75", 60 | "samplingRate": "1s", 61 | "unit": "millisecond" 62 | }, 63 | "metric": "*Load*", 64 | "refId": "A" 65 | } 66 | ], 67 | "timeFrom": null, 68 | "timeShift": null, 69 | "title": "Chronix Grafana Default", 70 | "tooltip": { 71 | "msResolution": true, 72 | "shared": true, 73 | "sort": 0, 74 | "value_type": "cumulative" 75 | }, 76 | "type": "graph", 77 | "xaxis": { 78 | "show": true 79 | }, 80 | "yaxes": [ 81 | { 82 | "format": "short", 83 | "label": null, 84 | "logBase": 1, 85 | "max": null, 86 | "min": null, 87 | "show": true 88 | }, 89 | { 90 | "format": "short", 91 | "label": null, 92 | "logBase": 1, 93 | "max": null, 94 | "min": null, 95 | "show": true 96 | } 97 | ] 98 | } 99 | ], 100 | "title": "Row" 101 | } 102 | ], 103 | "time": { 104 | "from": "2013-08-25T13:13:51.327Z", 105 | "to": "2013-09-02T16:38:22.691Z" 106 | }, 107 | "timepicker": { 108 | "refresh_intervals": [ 109 | "5s", 110 | "10s", 111 | "30s", 112 | "1m", 113 | "5m", 114 | "15m", 115 | "30m", 116 | "1h", 117 | "2h", 118 | "1d" 119 | ], 120 | "time_options": [ 121 | "5m", 122 | "15m", 123 | "1h", 124 | "6h", 125 | "12h", 126 | "24h", 127 | "2d", 128 | "7d", 129 | "30d" 130 | ] 131 | }, 132 | "templating": { 133 | "list": [] 134 | }, 135 | "annotations": { 136 | "list": [] 137 | }, 138 | "refresh": false, 139 | "schemaVersion": 12, 140 | "version": 4, 141 | "links": [], 142 | "gnetId": null 143 | } -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/ChronixDB/chronix.grafana](https://badges.gitter.im/ChronixDB/chronix.grafana.svg)](https://gitter.im/ChronixDB/chronix.grafana?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | [![Build Status](https://travis-ci.org/ChronixDB/chronix.grafana.svg?branch=master)](https://travis-ci.org/ChronixDB/chronix.grafana) 3 | [![Dependency Status](https://dependencyci.com/github/ChronixDB/chronix.grafana/badge)](https://dependencyci.com/github/ChronixDB/chronix.grafana) 4 | [![Apache License 2](http://img.shields.io/badge/license-ASF2-blue.svg)](LICENSE) 5 | 6 | # Chronix Grafana Datasource Plugin 7 | 8 | This is a "datasource" plugin that lets you use time series from [Chronix-Server](https://github.com/ChronixDB/chronix.server) 9 | and visualize them with [Grafana](https://grafana.net/). 10 | 11 | It works with Grafana > 3.X.X. 12 | 13 | ![Chronix-Grafana-Integration](img/screenshot.png) 14 | 15 | ## Features 16 | 17 | The plugin supports all the native implemented aggregations, transformations, and analyses of Chronix-Server. 18 | We will provide more details soon ;-) 19 | 20 | ## Usage 21 | 22 | Currently, the plugin is only available at the chronix github repository. It is planned to release the plugin within 23 | the app store of grafana. 24 | 25 | To use the plugin, simply clone this repository into your Grafana installation's `{inst-dir}/data/plugins/` directory. 26 | 27 | Optionally, you can download and start from the example dashboard: 28 | 29 | 1. Download the latest [Chronix-Server](https://github.com/ChronixDB/chronix.server/releases/download/0.3/chronix-0.3.zip) 30 | 2. Import the dashboard from 'dashboards' into your running Grafana 31 | 3. Download and execute the [csv importer](https://github.com/ChronixDB/chronix.examples/releases/download/0.3/importer.zip) after the Chronix-Server has started 32 | 33 | ## Contributing 34 | 35 | Is there anything missing? Do you have ideas for new features or improvements? You are highly welcome to contribute 36 | your improvements to the Chronix projects. All you have to do is to fork this repository, improve the code and issue a 37 | pull request. 38 | 39 | ## Developing the plugin 40 | 41 | ### Basics 42 | 43 | * All actual code sources live in `src` and can be written in ES6 / ES2015 - this allows us to use proper imports, 44 | exports and all the other syntactic goodies. 45 | * The `dist` folder is actually checked into git, too. We do this so that Grafana auto-detects the dist folder and uses 46 | it even if you just cloned the repository into Grafana (as described above). 47 | * This means that whenever you're changing something in `src`, you really should run the build at least once so that the 48 | contents of `dist` are "in sync", too, when you're committing / pushing / issuing a PR. 49 | 50 | ### Set up (only needs to be done once) 51 | 52 | Use a command prompt that provides NodeJS and NPM. In it, simply run 53 | 54 | npm install 55 | 56 | to install all (dev-) dependencies for the build. 57 | 58 | ### Changing stuff 59 | 60 | To run the build once in order to re-create the `dist` folder, run 61 | 62 | npm run build 63 | 64 | If you want the build to watch your `src` files and auto-run whenever you hit save, run 65 | 66 | npm run watch 67 | 68 | (you can end the watcher by pressing CTRL+C in that command prompt) 69 | 70 | ## Maintainer 71 | 72 | Florian Lautenschlager @flolaut 73 | 74 | ## License 75 | 76 | This software is provided under the Apache License, Version 2.0 license. 77 | 78 | See the [LICENSE](LICENSE) file for details. 79 | -------------------------------------------------------------------------------- /dist/config-controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register([], function (_export, _context) { 4 | "use strict"; 5 | 6 | var ChronixConfigController; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | return { 15 | setters: [], 16 | execute: function () { 17 | _export('ChronixConfigController', ChronixConfigController = function ChronixConfigController() { 18 | _classCallCheck(this, ChronixConfigController); 19 | }); 20 | 21 | _export('ChronixConfigController', ChronixConfigController); 22 | 23 | ChronixConfigController.templateUrl = 'partials/config.html'; 24 | } 25 | }; 26 | }); 27 | //# sourceMappingURL=config-controller.js.map 28 | -------------------------------------------------------------------------------- /dist/config-controller.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/config-controller.js"],"names":["ChronixConfigController","templateUrl"],"mappings":";;;;;;;;;;;;;;;;yCAAaA,uB;;;;;;AAEbA,8BAAwBC,WAAxB,GAAsC,sBAAtC","file":"config-controller.js","sourcesContent":["export class ChronixConfigController {}\r\n\r\nChronixConfigController.templateUrl = 'partials/config.html';\r\n"]} -------------------------------------------------------------------------------- /dist/datasource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['lodash'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var _, _createClass, requiredFields, ChronixDbDatasource; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | function escapeTag(name) { 15 | return name.indexOf('.') !== -1 ? '"' + name + '"' : name; 16 | } 17 | 18 | function toTagQueryString(tag, tagName) { 19 | return tagName + ':(' + tag.map(escapeTag).join(' OR ') + ')'; 20 | } 21 | 22 | function toTargetQueryString(target) { 23 | if (!target.tags || Object.keys(target.tags).length === 0) { 24 | // simple name-only 25 | return target.name; 26 | } 27 | 28 | // create strings for each tag 29 | var targetQueryStrings = _(target.tags).map(toTagQueryString); 30 | 31 | return '(' + target.name + ' AND ' + targetQueryStrings.join(' AND ') + ')'; 32 | } 33 | 34 | function toTargetJoinString(target) { 35 | if (!target.attributes || Object.keys(target.attributes).length === 0) { 36 | return "name"; 37 | } 38 | // create strings for each tag 39 | return _(target.attributes).join(',') + ",name,type"; 40 | } 41 | 42 | return { 43 | setters: [function (_lodash) { 44 | _ = _lodash.default; 45 | }], 46 | execute: function () { 47 | _createClass = function () { 48 | function defineProperties(target, props) { 49 | for (var i = 0; i < props.length; i++) { 50 | var descriptor = props[i]; 51 | descriptor.enumerable = descriptor.enumerable || false; 52 | descriptor.configurable = true; 53 | if ("value" in descriptor) descriptor.writable = true; 54 | Object.defineProperty(target, descriptor.key, descriptor); 55 | } 56 | } 57 | 58 | return function (Constructor, protoProps, staticProps) { 59 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 60 | if (staticProps) defineProperties(Constructor, staticProps); 61 | return Constructor; 62 | }; 63 | }(); 64 | 65 | requiredFields = ["data", "start", "end", "_version_", "id", "name", "type"]; 66 | 67 | _export('ChronixDbDatasource', ChronixDbDatasource = function () { 68 | function ChronixDbDatasource(instanceSettings, $q, backendSrv, templateSrv) { 69 | _classCallCheck(this, ChronixDbDatasource); 70 | 71 | this.type = instanceSettings.type; 72 | this.url = instanceSettings.url; 73 | this.name = instanceSettings.name; 74 | this.$q = $q; 75 | this.backendSrv = backendSrv; 76 | this.templateSrv = templateSrv; 77 | } 78 | 79 | //region Required Grafana Datasource methods 80 | 81 | _createClass(ChronixDbDatasource, [{ 82 | key: 'query', 83 | value: function query(options) { 84 | // get the start and the end and multiply it with 1000 to get millis since 1970 85 | var start = options.range.from.unix() * 1000; 86 | var end = options.range.to.unix() * 1000; 87 | var targets = options.targets; 88 | 89 | return this.rawQuery(targets, start, end).then(this.extractTimeSeries); 90 | } 91 | }, { 92 | key: 'testDatasource', 93 | value: function testDatasource() { 94 | var options = { 95 | url: this.url + '/select?q=%7B!lucene%7D*%3A*&rows=0', 96 | method: 'GET' 97 | }; 98 | var successMessage = { 99 | status: "success", 100 | message: "Connection to Chronix established", 101 | title: "Success" 102 | }; 103 | var errorMessage = this.$q.reject({ 104 | status: "error", 105 | message: "Connection to Chronix failed", 106 | title: "Error" 107 | }); 108 | 109 | // perform the actual call... 110 | return this.backendSrv.datasourceRequest(options) 111 | // ... check if the response is technically successful ... 112 | .then(function (response) { 113 | return response && response.status === 200; 114 | }) 115 | // ... and respond appropriately 116 | .then(function (success) { 117 | return success ? successMessage : errorMessage; 118 | }) 119 | // ... and react appropriately, too, when the call somehow didn't work 120 | .catch(function (error) { 121 | return errorMessage; 122 | }); 123 | } 124 | }, { 125 | key: 'findTimeSeriesByNames', 126 | value: function findTimeSeriesByNames(tsName) { 127 | var emptyResult = this.$q.when([]); 128 | 129 | if (!tsName || tsName === '*') { 130 | // no "*" accepted from the user 131 | return emptyResult; 132 | } 133 | 134 | if (tsName.indexOf('*') === -1) { 135 | // append an "*" at the end if the user didn't already provide one 136 | tsName = tsName + '*'; 137 | } 138 | 139 | var options = { 140 | //do a facet query 141 | url: this.url + '/select?facet.field=name&facet=on&facet.mincount=1&q=name:' + tsName + '&rows=0&wt=json', 142 | method: 'GET' 143 | }; 144 | 145 | return this.backendSrv.datasourceRequest(options).then(function (response) { 146 | return response && response.data && response.data.facet_counts && response.data.facet_counts.facet_fields && response.data.facet_counts.facet_fields.name; 147 | }).then(function (nameFields) { 148 | // somehow no valid response => empty array 149 | if (!nameFields) { 150 | console.log('could not find any matching time series for "' + tsName + '"'); 151 | return emptyResult; 152 | } 153 | 154 | // take only the names, not the counts 155 | return nameFields.filter(function (unused, index) { 156 | return index % 2 === 0; 157 | }) 158 | // and provide them as objects with the "text" property 159 | .map(function (text) { 160 | return { text: text }; 161 | }); 162 | }) 163 | // if the request itself failed 164 | .catch(function (error) { 165 | return emptyResult; 166 | }); 167 | } 168 | }, { 169 | key: 'rawQuery', 170 | value: function rawQuery(targets, start, end) { 171 | // create strings for each target 172 | var targetsQueryStrings = _(targets).map(toTargetQueryString); 173 | 174 | var query = 'name:(' + targetsQueryStrings.join(' OR ') + ')' + ' AND start:' + start + ' AND end:' + end; 175 | 176 | var joinquery = _(targets).map(toTargetJoinString); 177 | 178 | //At this point we have to query chronix 179 | var RAW_QUERY_BASE = '/select?fl=dataAsJson&wt=json'; 180 | var RAW_QUERY_JOIN = '&cj=' + joinquery; 181 | var RAW_QUERY_FILTER_FUNCTION = ''; //'&cf=metric{vector:0.1}'; 182 | var RAW_QUERY_BASE_WITH_FILTER = RAW_QUERY_BASE + RAW_QUERY_FILTER_FUNCTION + RAW_QUERY_JOIN + '&q='; 183 | 184 | console.log("Chronix Query: " + RAW_QUERY_BASE_WITH_FILTER + query); 185 | 186 | var options = { 187 | method: 'GET', 188 | url: this.url + RAW_QUERY_BASE_WITH_FILTER + query 189 | }; 190 | 191 | return this.backendSrv.datasourceRequest(options).then(function (response) { 192 | return [targets, response]; 193 | }); 194 | } 195 | }, { 196 | key: 'extractTimeSeries', 197 | value: function extractTimeSeries(targetsResponse) { 198 | var response = targetsResponse[1]; 199 | 200 | if (response.data === undefined) { 201 | return { data: [] }; 202 | } 203 | var dataset = response.data.response.docs; 204 | 205 | var tsPoints = {}; 206 | 207 | for (var i = 0; i < dataset.length; i++) { 208 | var currentDataSet = dataset[i]; 209 | var currentTimeSeries = currentDataSet.name; 210 | 211 | if (!(currentTimeSeries in tsPoints)) { 212 | tsPoints[currentTimeSeries] = []; 213 | } 214 | 215 | var jsonData = JSON.parse(currentDataSet.dataAsJson); 216 | 217 | var timestamps = jsonData[0]; 218 | var values = jsonData[1]; 219 | 220 | //add them 221 | for (var j = 0; j < timestamps.length; j++) { 222 | tsPoints[currentTimeSeries].push([values[j], timestamps[j]]); 223 | } 224 | } 225 | 226 | var ret = []; 227 | for (var key in tsPoints) { 228 | ret.push({ target: key, datapoints: tsPoints[key] }); 229 | } 230 | return { data: ret }; 231 | } 232 | }, { 233 | key: 'suggestAttributes', 234 | value: function suggestAttributes() { 235 | var options = { 236 | method: 'GET', 237 | url: this.url + '/admin/luke?numTerms=0&wt=json' 238 | }; 239 | 240 | return this.backendSrv.datasourceRequest(options).then(this.mapToTextValue); 241 | } 242 | }, { 243 | key: 'mapToTextValue', 244 | value: function mapToTextValue(result) { 245 | var fields = result.data.fields; 246 | 247 | var stringFields = []; 248 | //Iterate over the returned fields 249 | for (var property in fields) { 250 | if (fields.hasOwnProperty(property)) { 251 | if (requiredFields.indexOf(property.toLowerCase()) == -1) { 252 | stringFields.push(property); 253 | } 254 | } 255 | } 256 | return _.map(stringFields, function (name) { 257 | return { text: name }; 258 | }); 259 | } 260 | }, { 261 | key: 'suggestAttributesValues', 262 | value: function suggestAttributesValues(name, attribute) { 263 | var options = { 264 | method: 'GET', 265 | url: this.url + '/select?facet.field=' + attribute + '&facet=on&q=name:' + name + '&rows=0&wt=json' 266 | }; 267 | 268 | return this.backendSrv.datasourceRequest(options).then(this.mapValueToText); 269 | } 270 | }, { 271 | key: 'mapValueToText', 272 | value: function mapValueToText(result) { 273 | var fields = result.data.facet_counts.facet_fields; 274 | 275 | var field; 276 | //Iterate over the returned fields 277 | for (var property in fields) { 278 | if (fields.hasOwnProperty(property)) { 279 | field = property; 280 | } 281 | } 282 | 283 | var pairs = []; 284 | var values = fields[field]; 285 | 286 | //Build pairs 287 | for (var i = 0; i < values.length; i++) { 288 | pairs.push([values[i], values[++i]]); 289 | } 290 | 291 | return _.map(pairs, function (pair) { 292 | return { text: pair[0], value: pair[1] }; 293 | }); 294 | } 295 | }]); 296 | 297 | return ChronixDbDatasource; 298 | }()); 299 | 300 | _export('ChronixDbDatasource', ChronixDbDatasource); 301 | } 302 | }; 303 | }); 304 | //# sourceMappingURL=datasource.js.map 305 | -------------------------------------------------------------------------------- /dist/datasource.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/datasource.js"],"names":["escapeTag","name","indexOf","toTagQueryString","tag","tagName","map","join","toTargetQueryString","target","tags","Object","keys","length","targetQueryStrings","_","toTargetJoinString","attributes","requiredFields","ChronixDbDatasource","instanceSettings","$q","backendSrv","templateSrv","type","url","options","start","range","from","unix","end","to","targets","rawQuery","then","extractTimeSeries","method","successMessage","status","message","title","errorMessage","reject","datasourceRequest","response","success","catch","tsName","emptyResult","when","data","facet_counts","facet_fields","nameFields","console","log","filter","unused","index","text","targetsQueryStrings","query","joinquery","RAW_QUERY_BASE","RAW_QUERY_JOIN","RAW_QUERY_FILTER_FUNCTION","RAW_QUERY_BASE_WITH_FILTER","targetsResponse","undefined","dataset","docs","tsPoints","i","currentDataSet","currentTimeSeries","jsonData","JSON","parse","dataAsJson","timestamps","values","j","push","ret","key","datapoints","mapToTextValue","result","fields","stringFields","property","hasOwnProperty","toLowerCase","attribute","mapValueToText","field","pairs","pair","value"],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from 'lodash';\r\n\r\nfunction escapeTag(name) {\r\n return name.indexOf('.') !== -1 ? `\"${name}\"` : name;\r\n}\r\n\r\nfunction toTagQueryString(tag, tagName) {\r\n return tagName + ':(' + tag.map(escapeTag).join(' OR ') + ')'\r\n}\r\n\r\nfunction toTargetQueryString(target) {\r\n if (!target.tags || Object.keys(target.tags).length === 0) {\r\n // simple name-only\r\n return target.name;\r\n }\r\n\r\n // create strings for each tag\r\n const targetQueryStrings = _(target.tags).map(toTagQueryString);\r\n\r\n return '(' + target.name + ' AND ' + targetQueryStrings.join(' AND ') + ')';\r\n}\r\n\r\nfunction toTargetJoinString(target) {\r\n if (!target.attributes || Object.keys(target.attributes).length === 0) {\r\n return \"name\";\r\n }\r\n // create strings for each tag\r\n return _(target.attributes).join(',') + \",name,type\";\r\n}\r\n\r\nvar requiredFields = [\"data\", \"start\", \"end\", \"_version_\", \"id\", \"name\", \"type\"];\r\n\r\nexport class ChronixDbDatasource {\r\n\r\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\r\n this.type = instanceSettings.type;\r\n this.url = instanceSettings.url;\r\n this.name = instanceSettings.name;\r\n this.$q = $q;\r\n this.backendSrv = backendSrv;\r\n this.templateSrv = templateSrv;\r\n }\r\n\r\n //region Required Grafana Datasource methods\r\n\r\n query(options) {\r\n // get the start and the end and multiply it with 1000 to get millis since 1970\r\n var start = options.range.from.unix() * 1000;\r\n var end = options.range.to.unix() * 1000;\r\n var targets = options.targets;\r\n\r\n return this.rawQuery(targets, start, end).then(this.extractTimeSeries);\r\n }\r\n\r\n /**\r\n * Attempts to connect to the URL entered by the user and responds with a promise to either a \"success\" or an\r\n * \"error\" message.\r\n */\r\n testDatasource() {\r\n const options = {\r\n url: `${this.url}/select?q=%7B!lucene%7D*%3A*&rows=0`,\r\n method: 'GET'\r\n };\r\n const successMessage = {\r\n status: \"success\",\r\n message: \"Connection to Chronix established\",\r\n title: \"Success\"\r\n };\r\n const errorMessage = this.$q.reject({\r\n status: \"error\",\r\n message: \"Connection to Chronix failed\",\r\n title: \"Error\"\r\n });\r\n\r\n // perform the actual call...\r\n return this.backendSrv.datasourceRequest(options)\r\n // ... check if the response is technically successful ...\r\n .then(response => response && response.status === 200)\r\n // ... and respond appropriately\r\n .then(success => success ? successMessage : errorMessage)\r\n // ... and react appropriately, too, when the call somehow didn't work\r\n .catch(error => errorMessage);\r\n }\r\n\r\n /**\r\n *\r\n */\r\n findTimeSeriesByNames(tsName) {\r\n const emptyResult = this.$q.when([]);\r\n\r\n if (!tsName || tsName === '*') {\r\n // no \"*\" accepted from the user\r\n return emptyResult;\r\n }\r\n\r\n if (tsName.indexOf('*') === -1) {\r\n // append an \"*\" at the end if the user didn't already provide one\r\n tsName = tsName + '*';\r\n }\r\n\r\n const options = {\r\n //do a facet query\r\n url: `${this.url}/select?facet.field=name&facet=on&facet.mincount=1&q=name:${tsName}&rows=0&wt=json`,\r\n method: 'GET'\r\n };\r\n\r\n return this.backendSrv.datasourceRequest(options)\r\n .then(response => response && response.data && response.data.facet_counts && response.data.facet_counts.facet_fields && response.data.facet_counts.facet_fields.name)\r\n .then((nameFields) => {\r\n // somehow no valid response => empty array\r\n if (!nameFields) {\r\n console.log(`could not find any matching time series for \"${tsName}\"`);\r\n return emptyResult;\r\n }\r\n\r\n // take only the names, not the counts\r\n return nameFields\r\n .filter((unused, index) => index % 2 === 0)\r\n // and provide them as objects with the \"text\" property\r\n .map(text => ({text}));\r\n })\r\n // if the request itself failed\r\n .catch(error => emptyResult);\r\n }\r\n\r\n //endregion\r\n\r\n rawQuery(targets, start, end) {\r\n // create strings for each target\r\n var targetsQueryStrings = _(targets).map(toTargetQueryString);\r\n\r\n var query = 'name:(' + targetsQueryStrings.join(' OR ') + ')'\r\n + ' AND start:' + start\r\n + ' AND end:' + end;\r\n\r\n var joinquery = _(targets).map(toTargetJoinString);\r\n\r\n //At this point we have to query chronix\r\n var RAW_QUERY_BASE = '/select?fl=dataAsJson&wt=json';\r\n var RAW_QUERY_JOIN = '&cj=' + joinquery;\r\n var RAW_QUERY_FILTER_FUNCTION = '';//'&cf=metric{vector:0.1}';\r\n var RAW_QUERY_BASE_WITH_FILTER = RAW_QUERY_BASE + RAW_QUERY_FILTER_FUNCTION + RAW_QUERY_JOIN + '&q=';\r\n\r\n console.log(\"Chronix Query: \" + RAW_QUERY_BASE_WITH_FILTER + query);\r\n\r\n var options = {\r\n method: 'GET',\r\n url: this.url + RAW_QUERY_BASE_WITH_FILTER + query\r\n };\r\n\r\n return this.backendSrv.datasourceRequest(options).then(function (response) {\r\n return [targets, response];\r\n });\r\n }\r\n\r\n extractTimeSeries(targetsResponse) {\r\n var response = targetsResponse[1];\r\n\r\n if (response.data === undefined) {\r\n return {data: []};\r\n }\r\n var dataset = response.data.response.docs;\r\n\r\n var tsPoints = {};\r\n\r\n for (var i = 0; i < dataset.length; i++) {\r\n var currentDataSet = dataset[i];\r\n var currentTimeSeries = currentDataSet.name;\r\n\r\n if (!(currentTimeSeries in tsPoints)) {\r\n tsPoints[currentTimeSeries] = [];\r\n }\r\n\r\n var jsonData = JSON.parse(currentDataSet.dataAsJson);\r\n\r\n var timestamps = jsonData[0];\r\n var values = jsonData[1];\r\n\r\n //add them\r\n for (var j = 0; j < timestamps.length; j++) {\r\n tsPoints[currentTimeSeries].push([values[j], timestamps[j]]);\r\n }\r\n\r\n }\r\n\r\n var ret = [];\r\n for (var key in tsPoints) {\r\n ret.push({target: key, datapoints: tsPoints[key]});\r\n }\r\n return {data: ret};\r\n }\r\n\r\n /**\r\n * Gets the available fields / attributes\r\n */\r\n suggestAttributes() {\r\n var options = {\r\n method: 'GET',\r\n url: this.url + '/admin/luke?numTerms=0&wt=json'\r\n };\r\n\r\n return this.backendSrv.datasourceRequest(options).then(this.mapToTextValue);\r\n }\r\n\r\n mapToTextValue(result) {\r\n var fields = result.data.fields;\r\n\r\n var stringFields = [];\r\n //Iterate over the returned fields\r\n for (var property in fields) {\r\n if (fields.hasOwnProperty(property)) {\r\n if (requiredFields.indexOf(property.toLowerCase()) == -1) {\r\n stringFields.push(property)\r\n }\r\n }\r\n }\r\n return _.map(stringFields, (name) => {\r\n return {text: name};\r\n });\r\n }\r\n\r\n /**\r\n * Gets the available values for the attributes.\r\n *\r\n * @param name The name to get the available attributes.\r\n * @param attribute The attribute.\r\n */\r\n suggestAttributesValues(name, attribute) {\r\n var options = {\r\n method: 'GET',\r\n url: this.url + '/select?facet.field=' + attribute + '&facet=on&q=name:' + name + '&rows=0&wt=json'\r\n };\r\n\r\n return this.backendSrv.datasourceRequest(options).then(this.mapValueToText);\r\n }\r\n\r\n mapValueToText(result) {\r\n var fields = result.data.facet_counts.facet_fields;\r\n\r\n var field;\r\n //Iterate over the returned fields\r\n for (var property in fields) {\r\n if (fields.hasOwnProperty(property)) {\r\n field = property;\r\n }\r\n }\r\n\r\n var pairs = [];\r\n var values = fields[field];\r\n\r\n //Build pairs\r\n for (var i = 0; i < values.length; i++) {\r\n pairs.push([values[i], values[++i]]);\r\n }\r\n\r\n return _.map(pairs, (pair) => {\r\n return {text: pair[0], value: pair[1]};\r\n });\r\n }\r\n\r\n}\r\n"]} -------------------------------------------------------------------------------- /dist/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChronixDB/chronix.grafana/f0fa8361fbf97f9fc860c8fb4e830dfd2e65a9d8/dist/img/logo.png -------------------------------------------------------------------------------- /dist/img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChronixDB/chronix.grafana/f0fa8361fbf97f9fc860c8fb4e830dfd2e65a9d8/dist/img/screenshot.png -------------------------------------------------------------------------------- /dist/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['./datasource', './query-controller', './config-controller'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var ChronixDbDatasource, ChronixDbQueryController, ChronixConfigController; 7 | return { 8 | setters: [function (_datasource) { 9 | ChronixDbDatasource = _datasource.ChronixDbDatasource; 10 | }, function (_queryController) { 11 | ChronixDbQueryController = _queryController.ChronixDbQueryController; 12 | }, function (_configController) { 13 | ChronixConfigController = _configController.ChronixConfigController; 14 | }], 15 | execute: function () { 16 | _export('Datasource', ChronixDbDatasource); 17 | 18 | _export('QueryCtrl', ChronixDbQueryController); 19 | 20 | _export('ConfigCtrl', ChronixConfigController); 21 | } 22 | }; 23 | }); 24 | //# sourceMappingURL=module.js.map 25 | -------------------------------------------------------------------------------- /dist/module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/module.js"],"names":["ChronixDbDatasource","ChronixDbQueryController","ChronixConfigController"],"mappings":";;;;;;;;AAASA,+B,eAAAA,mB;;AACAC,oC,oBAAAA,wB;;AACAC,mC,qBAAAA,uB;;;kCAGLF,mB;;iCACAC,wB;;kCACAC,uB","file":"module.js","sourcesContent":["import { ChronixDbDatasource } from './datasource';\r\nimport { ChronixDbQueryController } from './query-controller';\r\nimport { ChronixConfigController } from './config-controller';\r\n\r\nexport {\r\n ChronixDbDatasource as Datasource,\r\n ChronixDbQueryController as QueryCtrl,\r\n ChronixConfigController as ConfigCtrl\r\n};\r\n"]} -------------------------------------------------------------------------------- /dist/partials/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dist/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |

Time Series

7 | 8 |
Name:
9 |
10 | 19 | 22 | 23 | 24 |
25 |
26 | 27 |
28 |

Attributes

29 | 30 | 31 |
32 | {{ key }} = {{ value }} 33 | 34 | 35 | 36 |
37 | 38 | 39 |
40 | 41 | 42 | 43 |
44 | 45 | 46 |
47 |
48 |
Attribute key:
49 |
50 | 59 |
60 |
61 |
62 |
Attribute value:
63 |
64 | 73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 |
84 |
85 | 86 | 87 |
88 |

Join by

89 | 90 | 91 |
92 | {{ key }} 93 | 94 | 95 | 96 |
97 | 98 | 99 |
100 | 101 | 102 | 103 |
104 | 105 | 106 |
107 |
108 |
Join type:
109 |
110 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 |
127 |
128 |
129 | 130 |
131 | 132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /dist/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "datasource", 3 | "name": "Chronix", 4 | "id": "chronix", 5 | "info": { 6 | "description": "Datasource plugin for Chronix", 7 | "author": { 8 | "name": "QAware", 9 | "url": "http://www.chronix.io" 10 | }, 11 | "keywords": [ 12 | "chronix", 13 | "chronixdb", 14 | "apache solr", 15 | "solr", 16 | "time series", 17 | "timeseries", 18 | "time-series" 19 | ], 20 | "logos": { 21 | "small": "img/logo.png", 22 | "large": "img/logo.png" 23 | }, 24 | "links": [ 25 | { 26 | "name": "Home Page", 27 | "url": "http://www.chronix.io" 28 | }, 29 | { 30 | "name": "GitHub", 31 | "url": "https://github.com/ChronixDB/chronix.grafana" 32 | }, 33 | { 34 | "name": "Issues", 35 | "url": "https://github.com/ChronixDB/chronix.grafana/issues" 36 | }, 37 | { 38 | "name": "License", 39 | "url": "https://github.com/ChronixDB/chronix.grafana/blob/master/LICENSE" 40 | } 41 | ], 42 | "screenshots": [ 43 | { 44 | "name": "ChronixDB in Grafana", 45 | "path": "img/screenshot.png" 46 | } 47 | ], 48 | "version": "0.4.0", 49 | "updated": "2016-11-05" 50 | }, 51 | "metrics": true, 52 | "annotations": false, 53 | "dependencies": { 54 | "grafanaVersion": "3.x.x", 55 | "plugins": [] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /dist/query-controller.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['app/plugins/sdk', 'lodash'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var QueryCtrl, _, _createClass, ChronixDbQueryController; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | function _possibleConstructorReturn(self, call) { 15 | if (!self) { 16 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); 17 | } 18 | 19 | return call && (typeof call === "object" || typeof call === "function") ? call : self; 20 | } 21 | 22 | function _inherits(subClass, superClass) { 23 | if (typeof superClass !== "function" && superClass !== null) { 24 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 25 | } 26 | 27 | subClass.prototype = Object.create(superClass && superClass.prototype, { 28 | constructor: { 29 | value: subClass, 30 | enumerable: false, 31 | writable: true, 32 | configurable: true 33 | } 34 | }); 35 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 36 | } 37 | 38 | function isInt(n) { 39 | return parseInt(n) % 1 === 0; 40 | } 41 | 42 | return { 43 | setters: [function (_appPluginsSdk) { 44 | QueryCtrl = _appPluginsSdk.QueryCtrl; 45 | }, function (_lodash) { 46 | _ = _lodash.default; 47 | }], 48 | execute: function () { 49 | _createClass = function () { 50 | function defineProperties(target, props) { 51 | for (var i = 0; i < props.length; i++) { 52 | var descriptor = props[i]; 53 | descriptor.enumerable = descriptor.enumerable || false; 54 | descriptor.configurable = true; 55 | if ("value" in descriptor) descriptor.writable = true; 56 | Object.defineProperty(target, descriptor.key, descriptor); 57 | } 58 | } 59 | 60 | return function (Constructor, protoProps, staticProps) { 61 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 62 | if (staticProps) defineProperties(Constructor, staticProps); 63 | return Constructor; 64 | }; 65 | }(); 66 | 67 | _export('ChronixDbQueryController', ChronixDbQueryController = function (_QueryCtrl) { 68 | _inherits(ChronixDbQueryController, _QueryCtrl); 69 | 70 | function ChronixDbQueryController($scope, $injector) { 71 | _classCallCheck(this, ChronixDbQueryController); 72 | 73 | var _this = _possibleConstructorReturn(this, (ChronixDbQueryController.__proto__ || Object.getPrototypeOf(ChronixDbQueryController)).call(this, $scope, $injector)); 74 | 75 | _this.panel.stack = false; 76 | 77 | if (!_this.panel.downsampling) { 78 | _this.panel.downsampling = 'avg'; 79 | } 80 | 81 | if (!_this.target.downsampling) { 82 | _this.target.downsampling = _this.panel.downsampling; 83 | _this.target.sampling = _this.panel.sampling; 84 | } 85 | 86 | /** 87 | * Is called if someone types something into a key field of an attribute. 88 | */ 89 | _this.suggestAttributes = function (query, callback) { 90 | _this.datasource.suggestAttributes().then(_this.getTextValues.bind(_this)).then(callback); 91 | }; 92 | 93 | /** 94 | * Is called if someone types something into a value field of an attribute. 95 | */ 96 | _this.suggestTagValues = function (query, callback) { 97 | _this.datasource.suggestAttributesValues(_this.target.name, _this.target.currentTagKey).then(_this.getTextValues.bind(_this)).then(callback); 98 | }; 99 | 100 | /** 101 | * Is called if someone types something into a key field of an attribute. 102 | */ 103 | _this.suggestTagAttributes = function (query, callback) { 104 | _this.datasource.suggestAttributes(query).then(_this.getTextValues.bind(_this)).then(callback); 105 | }; 106 | 107 | _this.suggestMetrics = function (query, callback) { 108 | _this.datasource.findTimeSeriesByNames(query).then(_this.getTextValues.bind(_this)).then(callback); 109 | }; 110 | 111 | _this.validateTarget(); 112 | 113 | _this.getCollapsedText = function () { 114 | return 'Expand to configure Chronix Query data source'; 115 | }; 116 | return _this; 117 | } 118 | 119 | _createClass(ChronixDbQueryController, [{ 120 | key: 'validateTarget', 121 | value: function validateTarget() { 122 | var errs = {}; 123 | 124 | if (!this.target.name) { 125 | errs.name = "You must supply a time series name."; 126 | } 127 | 128 | try { 129 | if (this.target.sampling) { 130 | this.datasource.convertToChronixInterval(this.target.sampling); 131 | } 132 | } catch (err) { 133 | errs.sampling = err.message; 134 | } 135 | 136 | this.target.errors = errs; 137 | } 138 | }, { 139 | key: 'targetBlur', 140 | value: function targetBlur() { 141 | this.validateTarget(); 142 | 143 | if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) { 144 | this.oldTarget = angular.copy(this.target); 145 | this.panelCtrl.refresh(); 146 | } 147 | } 148 | }, { 149 | key: 'getTextValues', 150 | value: function getTextValues(metricFindResult) { 151 | return _.map(metricFindResult, function (value) { 152 | return value.text; 153 | }); 154 | } 155 | }, { 156 | key: 'addJoinByAttribute', 157 | value: function addJoinByAttribute(query, callback) { 158 | console.info("add join by attribute is called for " + query); 159 | 160 | this.datasource.suggestAttributes(query).then(this.getTextValues.bind(this)).then(callback); 161 | } 162 | }, { 163 | key: 'validateJoinAttributes', 164 | value: function validateJoinAttributes() { 165 | console.info("validateJoinAttributes is called"); 166 | this.target.errors.attributes = null; 167 | if (!this.target.currentAttributeKey) { 168 | this.target.errors.attributes = "You must specify a tag name and value."; 169 | } 170 | } 171 | }, { 172 | key: 'removeJoinByAttribute', 173 | value: function removeJoinByAttribute(attribute) { 174 | console.info("removeJoinByAttribute is called for " + attribute); 175 | 176 | var index = this.target.attributes.indexOf(attribute); 177 | 178 | this.target.attributes.splice(index, 1); 179 | 180 | if (_.size(this.target.attributes) === 0) { 181 | this.target.attributes = null; 182 | } 183 | this.targetBlur(); 184 | } 185 | }, { 186 | key: 'addJoinByAttribute', 187 | value: function addJoinByAttribute() { 188 | console.info("addJoinByAttribute is called"); 189 | if (!this.panel.addJoinAttributeMode) { 190 | this.panel.addJoinAttributeMode = true; 191 | this.validateJoinAttributes(); 192 | return; 193 | } 194 | 195 | if (!this.target.attributes) { 196 | this.target.attributes = []; 197 | } 198 | 199 | this.validateJoinAttributes(); 200 | if (!this.target.errors.attributes) { 201 | this.target.attributes.push(this.target.currentAttributeKey); 202 | this.target.currentAttributeKey = ''; 203 | 204 | this.targetBlur(); 205 | } 206 | 207 | this.panel.addJoinAttributeMode = false; 208 | } 209 | }, { 210 | key: 'addFilterTag', 211 | value: function addFilterTag() { 212 | if (!this.panel.addFilterTagMode) { 213 | this.panel.addFilterTagMode = true; 214 | this.validateFilterTag(); 215 | return; 216 | } 217 | 218 | if (!this.target.tags) { 219 | this.target.tags = {}; 220 | } 221 | 222 | this.validateFilterTag(); 223 | if (!this.target.errors.tags) { 224 | if (!_.has(this.target.tags, this.target.currentTagKey)) { 225 | this.target.tags[this.target.currentTagKey] = []; 226 | } 227 | this.target.tags[this.target.currentTagKey].push(this.target.currentTagValue); 228 | this.target.currentTagKey = ''; 229 | this.target.currentTagValue = ''; 230 | this.targetBlur(); 231 | } 232 | 233 | this.panel.addFilterTagMode = false; 234 | } 235 | }, { 236 | key: 'removeFilterTag', 237 | value: function removeFilterTag(key) { 238 | delete this.target.tags[key]; 239 | if (_.size(this.target.tags) === 0) { 240 | this.target.tags = null; 241 | } 242 | this.targetBlur(); 243 | } 244 | }, { 245 | key: 'validateFilterTag', 246 | value: function validateFilterTag() { 247 | this.target.errors.tags = null; 248 | if (!this.target.currentTagKey || !this.target.currentTagValue) { 249 | this.target.errors.tags = "You must specify a tag name and value."; 250 | } 251 | } 252 | }, { 253 | key: 'addGroupBy', 254 | value: function addGroupBy() { 255 | if (!this.panel.addGroupByMode) { 256 | this.target.currentGroupByType = 'tag'; 257 | this.panel.addGroupByMode = true; 258 | this.panel.isTagGroupBy = true; 259 | this.validateGroupBy(); 260 | return; 261 | } 262 | this.validateGroupBy(); 263 | // nb: if error is found, means that user clicked on cross : cancels input 264 | 265 | if (_.isEmpty(this.target.errors.groupBy)) { 266 | if (this.panel.isTagGroupBy) { 267 | if (!this.target.groupByTags) { 268 | this.target.groupByTags = []; 269 | } 270 | if (!_.contains(this.target.groupByTags, this.target.groupBy.tagKey)) { 271 | this.target.groupByTags.push(this.target.groupBy.tagKey); 272 | this.targetBlur(); 273 | } 274 | this.target.groupBy.tagKey = ''; 275 | } else { 276 | if (!this.target.nonTagGroupBys) { 277 | this.target.nonTagGroupBys = []; 278 | } 279 | var groupBy = { 280 | name: this.target.currentGroupByType 281 | }; 282 | if (this.panel.isValueGroupBy) { 283 | groupBy.range_size = this.target.groupBy.valueRange; 284 | } else if (this.panel.isTimeGroupBy) { 285 | groupBy.range_size = this.target.groupBy.timeInterval; 286 | groupBy.group_count = this.target.groupBy.groupCount; 287 | } 288 | this.target.nonTagGroupBys.push(groupBy); 289 | } 290 | this.targetBlur(); 291 | } 292 | 293 | this.panel.isTagGroupBy = false; 294 | this.panel.isValueGroupBy = false; 295 | this.panel.isTimeGroupBy = false; 296 | this.panel.addGroupByMode = false; 297 | } 298 | }, { 299 | key: 'removeGroupByTag', 300 | value: function removeGroupByTag(index) { 301 | this.target.groupByTags.splice(index, 1); 302 | if (_.size(this.target.groupByTags) === 0) { 303 | this.target.groupByTags = null; 304 | } 305 | this.targetBlur(); 306 | } 307 | }, { 308 | key: 'removeNonTagGroupBy', 309 | value: function removeNonTagGroupBy(index) { 310 | this.target.nonTagGroupBys.splice(index, 1); 311 | if (_.size(this.target.nonTagGroupBys) === 0) { 312 | this.target.nonTagGroupBys = null; 313 | } 314 | this.targetBlur(); 315 | } 316 | }, { 317 | key: 'changeGroupByInput', 318 | value: function changeGroupByInput() { 319 | this.panel.isTagGroupBy = this.target.currentGroupByType === 'tag'; 320 | this.panel.isValueGroupBy = this.target.currentGroupByType === 'value'; 321 | this.panel.isTimeGroupBy = this.target.currentGroupByType === 'time'; 322 | this.validateGroupBy(); 323 | } 324 | }, { 325 | key: 'getValuesOfGroupBy', 326 | value: function getValuesOfGroupBy(groupBy) { 327 | return _.values(groupBy); 328 | } 329 | }, { 330 | key: 'validateGroupBy', 331 | value: function validateGroupBy() { 332 | delete this.target.errors.groupBy; 333 | var errors = {}; 334 | this.panel.isGroupByValid = true; 335 | if (this.panel.isTagGroupBy) { 336 | if (!this.target.groupBy.tagKey) { 337 | this.panel.isGroupByValid = false; 338 | errors.tagKey = 'You must supply a tag name'; 339 | } 340 | } 341 | 342 | if (this.panel.isValueGroupBy) { 343 | if (!this.target.groupBy.valueRange || !isInt(this.target.groupBy.valueRange)) { 344 | errors.valueRange = "Range must be an integer"; 345 | this.isGroupByValid = false; 346 | } 347 | } 348 | 349 | if (this.panel.isTimeGroupBy) { 350 | try { 351 | this.datasource.convertToChronixInterval(this.target.groupBy.timeInterval); 352 | } catch (err) { 353 | errors.timeInterval = err.message; 354 | this.isGroupByValid = false; 355 | } 356 | if (!this.target.groupBy.groupCount || !isInt(this.target.groupBy.groupCount)) { 357 | errors.groupCount = "Group count must be an integer"; 358 | this.isGroupByValid = false; 359 | } 360 | } 361 | 362 | if (!_.isEmpty(errors)) { 363 | this.target.errors.groupBy = errors; 364 | } 365 | } 366 | }, { 367 | key: 'addHorizontalAggregator', 368 | value: function addHorizontalAggregator() { 369 | if (!this.panel.addHorizontalAggregatorMode) { 370 | this.panel.addHorizontalAggregatorMode = true; 371 | this.target.currentHorizontalAggregatorName = 'avg'; 372 | this.panel.hasSamplingRate = true; 373 | this.validateHorizontalAggregator(); 374 | return; 375 | } 376 | 377 | this.validateHorizontalAggregator(); 378 | // nb: if error is found, means that user clicked on cross : cancels input 379 | if (_.isEmpty(this.target.errors.horAggregator)) { 380 | if (!this.target.horizontalAggregators) { 381 | this.target.horizontalAggregators = []; 382 | } 383 | var aggregator = { 384 | name: this.target.currentHorizontalAggregatorName 385 | }; 386 | if (this.panel.hasSamplingRate) { 387 | aggregator.sampling_rate = this.target.horAggregator.samplingRate; 388 | } 389 | if (this.panel.hasUnit) { 390 | aggregator.unit = this.target.horAggregator.unit; 391 | } 392 | if (this.panel.hasFactor) { 393 | aggregator.factor = this.target.horAggregator.factor; 394 | } 395 | if (this.panel.hasPercentile) { 396 | aggregator.percentile = this.target.horAggregator.percentile; 397 | } 398 | this.target.horizontalAggregators.push(aggregator); 399 | this.targetBlur(); 400 | } 401 | 402 | this.panel.addHorizontalAggregatorMode = false; 403 | this.panel.hasSamplingRate = false; 404 | this.panel.hasUnit = false; 405 | this.panel.hasFactor = false; 406 | this.panel.hasPercentile = false; 407 | } 408 | }, { 409 | key: 'removeHorizontalAggregator', 410 | value: function removeHorizontalAggregator(index) { 411 | this.target.horizontalAggregators.splice(index, 1); 412 | if (_.size(this.target.horizontalAggregators) === 0) { 413 | this.target.horizontalAggregators = null; 414 | } 415 | 416 | this.targetBlur(); 417 | } 418 | }, { 419 | key: 'changeHorAggregationInput', 420 | value: function changeHorAggregationInput() { 421 | this.panel.hasSamplingRate = _.contains(['avg', 'dev', 'max', 'min', 'sum', 'least_squares', 'count', 'percentile'], this.target.currentHorizontalAggregatorName); 422 | this.panel.hasUnit = _.contains(['sampler', 'rate'], this.target.currentHorizontalAggregatorName); 423 | this.panel.hasFactor = _.contains(['div', 'scale'], this.target.currentHorizontalAggregatorName); 424 | this.panel.hasPercentile = 'percentile' === this.target.currentHorizontalAggregatorName; 425 | this.validateHorizontalAggregator(); 426 | } 427 | }, { 428 | key: 'validateHorizontalAggregator', 429 | value: function validateHorizontalAggregator() { 430 | delete this.target.errors.horAggregator; 431 | var errors = {}; 432 | this.panel.isAggregatorValid = true; 433 | 434 | if (this.panel.hasSamplingRate) { 435 | try { 436 | this.datasource.convertToChronixInterval(this.target.horAggregator.samplingRate); 437 | } catch (err) { 438 | errors.samplingRate = err.message; 439 | this.panel.isAggregatorValid = false; 440 | } 441 | } 442 | 443 | if (this.hasFactor) { 444 | if (!this.target.horAggregator.factor) { 445 | errors.factor = 'You must supply a numeric value for this aggregator'; 446 | this.panel.isAggregatorValid = false; 447 | } else if (parseInt(this.target.horAggregator.factor) === 0 && this.target.currentHorizontalAggregatorName === 'div') { 448 | errors.factor = 'Cannot divide by 0'; 449 | this.panel.isAggregatorValid = false; 450 | } 451 | } 452 | 453 | if (this.panel.hasPercentile) { 454 | if (!this.target.horAggregator.percentile || this.target.horAggregator.percentile <= 0 || this.target.horAggregator.percentile > 1) { 455 | errors.percentile = 'Percentile must be between 0 and 1'; 456 | this.panel.isAggregatorValid = false; 457 | } 458 | } 459 | 460 | if (!_.isEmpty(errors)) { 461 | this.target.errors.horAggregator = errors; 462 | } 463 | } 464 | }, { 465 | key: 'alert', 466 | value: function (_alert) { 467 | function alert(_x) { 468 | return _alert.apply(this, arguments); 469 | } 470 | 471 | alert.toString = function () { 472 | return _alert.toString(); 473 | }; 474 | 475 | return alert; 476 | }(function (message) { 477 | alert(message); 478 | }) 479 | }]); 480 | 481 | return ChronixDbQueryController; 482 | }(QueryCtrl)); 483 | 484 | _export('ChronixDbQueryController', ChronixDbQueryController); 485 | 486 | ChronixDbQueryController.templateUrl = 'partials/query.editor.html'; 487 | } 488 | }; 489 | }); 490 | //# sourceMappingURL=query-controller.js.map 491 | -------------------------------------------------------------------------------- /dist/query-controller.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/query-controller.js"],"names":["isInt","n","parseInt","QueryCtrl","_","ChronixDbQueryController","$scope","$injector","panel","stack","downsampling","target","sampling","suggestAttributes","query","callback","datasource","then","getTextValues","bind","suggestTagValues","suggestAttributesValues","name","currentTagKey","suggestTagAttributes","suggestMetrics","findTimeSeriesByNames","validateTarget","getCollapsedText","errs","convertToChronixInterval","err","message","errors","isEqual","oldTarget","isEmpty","angular","copy","panelCtrl","refresh","metricFindResult","map","value","text","console","info","attributes","currentAttributeKey","attribute","index","indexOf","splice","size","targetBlur","addJoinAttributeMode","validateJoinAttributes","push","addFilterTagMode","validateFilterTag","tags","has","currentTagValue","key","addGroupByMode","currentGroupByType","isTagGroupBy","validateGroupBy","groupBy","groupByTags","contains","tagKey","nonTagGroupBys","isValueGroupBy","range_size","valueRange","isTimeGroupBy","timeInterval","group_count","groupCount","values","isGroupByValid","addHorizontalAggregatorMode","currentHorizontalAggregatorName","hasSamplingRate","validateHorizontalAggregator","horAggregator","horizontalAggregators","aggregator","sampling_rate","samplingRate","hasUnit","unit","hasFactor","factor","hasPercentile","percentile","isAggregatorValid","alert","templateUrl"],"mappings":"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","file":"query-controller.js","sourcesContent":["import { QueryCtrl } from 'app/plugins/sdk';\r\nimport _ from 'lodash';\r\n\r\nfunction isInt (n) {\r\n return parseInt(n) % 1 === 0;\r\n}\r\n\r\nexport class ChronixDbQueryController extends QueryCtrl {\r\n\r\n constructor ($scope, $injector) {\r\n super($scope, $injector);\r\n\r\n this.panel.stack = false;\r\n\r\n if (!this.panel.downsampling) {\r\n this.panel.downsampling = 'avg';\r\n }\r\n\r\n if (!this.target.downsampling) {\r\n this.target.downsampling = this.panel.downsampling;\r\n this.target.sampling = this.panel.sampling;\r\n }\r\n\r\n /**\r\n * Is called if someone types something into a key field of an attribute.\r\n */\r\n this.suggestAttributes = (query, callback) => {\r\n this.datasource.suggestAttributes()\r\n .then(this.getTextValues.bind(this))\r\n .then(callback);\r\n };\r\n\r\n /**\r\n * Is called if someone types something into a value field of an attribute.\r\n */\r\n this.suggestTagValues = (query, callback) => {\r\n this.datasource.suggestAttributesValues(this.target.name, this.target.currentTagKey)\r\n .then(this.getTextValues.bind(this))\r\n .then(callback);\r\n };\r\n\r\n /**\r\n * Is called if someone types something into a key field of an attribute.\r\n */\r\n this.suggestTagAttributes = (query, callback) => {\r\n this.datasource.suggestAttributes(query)\r\n .then(this.getTextValues.bind(this))\r\n .then(callback);\r\n };\r\n\r\n this.suggestMetrics = (query, callback) => {\r\n this.datasource.findTimeSeriesByNames(query)\r\n .then(this.getTextValues.bind(this))\r\n .then(callback);\r\n };\r\n\r\n this.validateTarget();\r\n\r\n this.getCollapsedText = () => {\r\n return 'Expand to configure Chronix Query data source';\r\n };\r\n }\r\n\r\n validateTarget () {\r\n var errs = {};\r\n\r\n if (!this.target.name) {\r\n errs.name = \"You must supply a time series name.\";\r\n }\r\n\r\n try {\r\n if (this.target.sampling) {\r\n this.datasource.convertToChronixInterval(this.target.sampling);\r\n }\r\n } catch (err) {\r\n errs.sampling = err.message;\r\n }\r\n\r\n this.target.errors = errs;\r\n }\r\n\r\n targetBlur () {\r\n this.validateTarget();\r\n\r\n if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) {\r\n this.oldTarget = angular.copy(this.target);\r\n this.panelCtrl.refresh();\r\n }\r\n };\r\n\r\n getTextValues (metricFindResult) {\r\n return _.map(metricFindResult, function (value) {\r\n return value.text;\r\n });\r\n };\r\n\r\n /**\r\n * =========================================================================\r\n *\r\n * Join section\r\n *\r\n * =========================================================================\r\n */\r\n\r\n /**\r\n * Is called if someone types something into the join by box\r\n * @param query\r\n * @param callback\r\n */\r\n addJoinByAttribute (query, callback) {\r\n console.info(\"add join by attribute is called for \" + query);\r\n\r\n this.datasource.suggestAttributes(query)\r\n .then(this.getTextValues.bind(this))\r\n .then(callback);\r\n };\r\n\r\n validateJoinAttributes () {\r\n console.info(\"validateJoinAttributes is called\");\r\n this.target.errors.attributes = null;\r\n if (!this.target.currentAttributeKey) {\r\n this.target.errors.attributes = \"You must specify a tag name and value.\";\r\n }\r\n };\r\n\r\n /**\r\n * Is calls if someone removes a group by tag\r\n * @param attribute\r\n */\r\n removeJoinByAttribute (attribute) {\r\n console.info(\"removeJoinByAttribute is called for \" + attribute);\r\n\r\n var index = this.target.attributes.indexOf(attribute);\r\n\r\n this.target.attributes.splice(index, 1);\r\n\r\n if (_.size(this.target.attributes) === 0) {\r\n this.target.attributes = null;\r\n }\r\n this.targetBlur();\r\n };\r\n\r\n /**\r\n * Add join by attribute\r\n */\r\n addJoinByAttribute () {\r\n console.info(\"addJoinByAttribute is called\");\r\n if (!this.panel.addJoinAttributeMode) {\r\n this.panel.addJoinAttributeMode = true;\r\n this.validateJoinAttributes();\r\n return;\r\n }\r\n\r\n if (!this.target.attributes) {\r\n this.target.attributes = [];\r\n }\r\n\r\n this.validateJoinAttributes();\r\n if (!this.target.errors.attributes) {\r\n this.target.attributes.push(this.target.currentAttributeKey);\r\n this.target.currentAttributeKey = '';\r\n\r\n this.targetBlur();\r\n }\r\n\r\n this.panel.addJoinAttributeMode = false;\r\n };\r\n\r\n // Filter metric by tag\r\n addFilterTag () {\r\n if (!this.panel.addFilterTagMode) {\r\n this.panel.addFilterTagMode = true;\r\n this.validateFilterTag();\r\n return;\r\n }\r\n\r\n if (!this.target.tags) {\r\n this.target.tags = {};\r\n }\r\n\r\n this.validateFilterTag();\r\n if (!this.target.errors.tags) {\r\n if (!_.has(this.target.tags, this.target.currentTagKey)) {\r\n this.target.tags[this.target.currentTagKey] = [];\r\n }\r\n this.target.tags[this.target.currentTagKey].push(this.target.currentTagValue);\r\n this.target.currentTagKey = '';\r\n this.target.currentTagValue = '';\r\n this.targetBlur();\r\n }\r\n\r\n this.panel.addFilterTagMode = false;\r\n };\r\n\r\n removeFilterTag (key) {\r\n delete this.target.tags[key];\r\n if (_.size(this.target.tags) === 0) {\r\n this.target.tags = null;\r\n }\r\n this.targetBlur();\r\n };\r\n\r\n validateFilterTag () {\r\n this.target.errors.tags = null;\r\n if (!this.target.currentTagKey || !this.target.currentTagValue) {\r\n this.target.errors.tags = \"You must specify a tag name and value.\";\r\n }\r\n };\r\n\r\n //////////////////////////////\r\n // GROUP BY\r\n //////////////////////////////\r\n addGroupBy () {\r\n if (!this.panel.addGroupByMode) {\r\n this.target.currentGroupByType = 'tag';\r\n this.panel.addGroupByMode = true;\r\n this.panel.isTagGroupBy = true;\r\n this.validateGroupBy();\r\n return;\r\n }\r\n this.validateGroupBy();\r\n // nb: if error is found, means that user clicked on cross : cancels input\r\n\r\n if (_.isEmpty(this.target.errors.groupBy)) {\r\n if (this.panel.isTagGroupBy) {\r\n if (!this.target.groupByTags) {\r\n this.target.groupByTags = [];\r\n }\r\n if (!_.contains(this.target.groupByTags, this.target.groupBy.tagKey)) {\r\n this.target.groupByTags.push(this.target.groupBy.tagKey);\r\n this.targetBlur();\r\n }\r\n this.target.groupBy.tagKey = '';\r\n }\r\n else {\r\n if (!this.target.nonTagGroupBys) {\r\n this.target.nonTagGroupBys = [];\r\n }\r\n var groupBy = {\r\n name: this.target.currentGroupByType\r\n };\r\n if (this.panel.isValueGroupBy) {\r\n groupBy.range_size = this.target.groupBy.valueRange;\r\n } else if (this.panel.isTimeGroupBy) {\r\n groupBy.range_size = this.target.groupBy.timeInterval;\r\n groupBy.group_count = this.target.groupBy.groupCount;\r\n }\r\n this.target.nonTagGroupBys.push(groupBy);\r\n }\r\n this.targetBlur();\r\n }\r\n\r\n this.panel.isTagGroupBy = false;\r\n this.panel.isValueGroupBy = false;\r\n this.panel.isTimeGroupBy = false;\r\n this.panel.addGroupByMode = false;\r\n };\r\n\r\n removeGroupByTag (index) {\r\n this.target.groupByTags.splice(index, 1);\r\n if (_.size(this.target.groupByTags) === 0) {\r\n this.target.groupByTags = null;\r\n }\r\n this.targetBlur();\r\n };\r\n\r\n removeNonTagGroupBy (index) {\r\n this.target.nonTagGroupBys.splice(index, 1);\r\n if (_.size(this.target.nonTagGroupBys) === 0) {\r\n this.target.nonTagGroupBys = null;\r\n }\r\n this.targetBlur();\r\n };\r\n\r\n changeGroupByInput () {\r\n this.panel.isTagGroupBy = this.target.currentGroupByType === 'tag';\r\n this.panel.isValueGroupBy = this.target.currentGroupByType === 'value';\r\n this.panel.isTimeGroupBy = this.target.currentGroupByType === 'time';\r\n this.validateGroupBy();\r\n };\r\n\r\n getValuesOfGroupBy (groupBy) {\r\n return _.values(groupBy);\r\n };\r\n\r\n validateGroupBy () {\r\n delete this.target.errors.groupBy;\r\n var errors = {};\r\n this.panel.isGroupByValid = true;\r\n if (this.panel.isTagGroupBy) {\r\n if (!this.target.groupBy.tagKey) {\r\n this.panel.isGroupByValid = false;\r\n errors.tagKey = 'You must supply a tag name';\r\n }\r\n }\r\n\r\n if (this.panel.isValueGroupBy) {\r\n if (!this.target.groupBy.valueRange || !isInt(this.target.groupBy.valueRange)) {\r\n errors.valueRange = \"Range must be an integer\";\r\n this.isGroupByValid = false;\r\n }\r\n }\r\n\r\n if (this.panel.isTimeGroupBy) {\r\n try {\r\n this.datasource.convertToChronixInterval(this.target.groupBy.timeInterval);\r\n } catch (err) {\r\n errors.timeInterval = err.message;\r\n this.isGroupByValid = false;\r\n }\r\n if (!this.target.groupBy.groupCount || !isInt(this.target.groupBy.groupCount)) {\r\n errors.groupCount = \"Group count must be an integer\";\r\n this.isGroupByValid = false;\r\n }\r\n }\r\n\r\n if (!_.isEmpty(errors)) {\r\n this.target.errors.groupBy = errors;\r\n }\r\n };\r\n\r\n //////////////////////////////\r\n // HORIZONTAL AGGREGATION\r\n //////////////////////////////\r\n\r\n addHorizontalAggregator () {\r\n if (!this.panel.addHorizontalAggregatorMode) {\r\n this.panel.addHorizontalAggregatorMode = true;\r\n this.target.currentHorizontalAggregatorName = 'avg';\r\n this.panel.hasSamplingRate = true;\r\n this.validateHorizontalAggregator();\r\n return;\r\n }\r\n\r\n this.validateHorizontalAggregator();\r\n // nb: if error is found, means that user clicked on cross : cancels input\r\n if (_.isEmpty(this.target.errors.horAggregator)) {\r\n if (!this.target.horizontalAggregators) {\r\n this.target.horizontalAggregators = [];\r\n }\r\n var aggregator = {\r\n name: this.target.currentHorizontalAggregatorName\r\n };\r\n if (this.panel.hasSamplingRate) {\r\n aggregator.sampling_rate = this.target.horAggregator.samplingRate;\r\n }\r\n if (this.panel.hasUnit) {\r\n aggregator.unit = this.target.horAggregator.unit;\r\n }\r\n if (this.panel.hasFactor) {\r\n aggregator.factor = this.target.horAggregator.factor;\r\n }\r\n if (this.panel.hasPercentile) {\r\n aggregator.percentile = this.target.horAggregator.percentile;\r\n }\r\n this.target.horizontalAggregators.push(aggregator);\r\n this.targetBlur();\r\n }\r\n\r\n this.panel.addHorizontalAggregatorMode = false;\r\n this.panel.hasSamplingRate = false;\r\n this.panel.hasUnit = false;\r\n this.panel.hasFactor = false;\r\n this.panel.hasPercentile = false;\r\n };\r\n\r\n removeHorizontalAggregator (index) {\r\n this.target.horizontalAggregators.splice(index, 1);\r\n if (_.size(this.target.horizontalAggregators) === 0) {\r\n this.target.horizontalAggregators = null;\r\n }\r\n\r\n this.targetBlur();\r\n };\r\n\r\n changeHorAggregationInput () {\r\n this.panel.hasSamplingRate = _.contains(['avg', 'dev', 'max', 'min', 'sum', 'least_squares', 'count', 'percentile'],\r\n this.target.currentHorizontalAggregatorName);\r\n this.panel.hasUnit = _.contains(['sampler', 'rate'], this.target.currentHorizontalAggregatorName);\r\n this.panel.hasFactor = _.contains(['div', 'scale'], this.target.currentHorizontalAggregatorName);\r\n this.panel.hasPercentile = 'percentile' === this.target.currentHorizontalAggregatorName;\r\n this.validateHorizontalAggregator();\r\n };\r\n\r\n validateHorizontalAggregator () {\r\n delete this.target.errors.horAggregator;\r\n var errors = {};\r\n this.panel.isAggregatorValid = true;\r\n\r\n if (this.panel.hasSamplingRate) {\r\n try {\r\n this.datasource.convertToChronixInterval(this.target.horAggregator.samplingRate);\r\n } catch (err) {\r\n errors.samplingRate = err.message;\r\n this.panel.isAggregatorValid = false;\r\n }\r\n }\r\n\r\n if (this.hasFactor) {\r\n if (!this.target.horAggregator.factor) {\r\n errors.factor = 'You must supply a numeric value for this aggregator';\r\n this.panel.isAggregatorValid = false;\r\n }\r\n else if (parseInt(this.target.horAggregator.factor) === 0 && this.target.currentHorizontalAggregatorName === 'div') {\r\n errors.factor = 'Cannot divide by 0';\r\n this.panel.isAggregatorValid = false;\r\n }\r\n }\r\n\r\n if (this.panel.hasPercentile) {\r\n if (!this.target.horAggregator.percentile ||\r\n this.target.horAggregator.percentile <= 0 ||\r\n this.target.horAggregator.percentile > 1) {\r\n errors.percentile = 'Percentile must be between 0 and 1';\r\n this.panel.isAggregatorValid = false;\r\n }\r\n }\r\n\r\n if (!_.isEmpty(errors)) {\r\n this.target.errors.horAggregator = errors;\r\n }\r\n };\r\n\r\n alert (message) {\r\n alert(message);\r\n };\r\n\r\n}\r\n\r\nChronixDbQueryController.templateUrl = 'partials/query.editor.html';\r\n"]} -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChronixDB/chronix.grafana/f0fa8361fbf97f9fc860c8fb4e830dfd2e65a9d8/img/logo.png -------------------------------------------------------------------------------- /img/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChronixDB/chronix.grafana/f0fa8361fbf97f9fc860c8fb4e830dfd2e65a9d8/img/screenshot.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chronix-grafana", 3 | "version": "0.4.0", 4 | "description": "Datasource plugin for Chronix", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/ChronixDB/chronix.grafana" 8 | }, 9 | "author": { 10 | "name": "Florian Lautenschlager", 11 | "email": "florian.lautenschlager@qaware.de" 12 | }, 13 | "contributors": [ 14 | { 15 | "name": "Roland Hummel", 16 | "email": "roland.hummel@qaware.de" 17 | } 18 | ], 19 | "license": "Apache-2.0", 20 | "devDependencies": { 21 | "babel-core": "^6.5.1", 22 | "babel-plugin-transform-es2015-for-of": "^6.8.0", 23 | "babel-plugin-transform-es2015-modules-systemjs": "^6.14.0", 24 | "babel-preset-es2015": "^6.14.0", 25 | "grunt": "^1.0.1", 26 | "grunt-babel": "^6.0.0", 27 | "grunt-cli": "^1.2.0", 28 | "grunt-contrib-clean": "^1.0.0", 29 | "grunt-contrib-copy": "^1.0.0", 30 | "grunt-contrib-watch": "^1.0.0", 31 | "load-grunt-tasks": "^3.5.2" 32 | }, 33 | "dependencies": { 34 | "lodash": "^4.0.0" 35 | }, 36 | "scripts": { 37 | "build": "grunt", 38 | "watch": "grunt watch", 39 | "test": "grunt test" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "datasource", 3 | "name": "Chronix", 4 | "id": "chronix", 5 | "info": { 6 | "description": "Datasource plugin for Chronix", 7 | "author": { 8 | "name": "QAware", 9 | "url": "http://www.chronix.io" 10 | }, 11 | "keywords": [ 12 | "chronix", 13 | "chronixdb", 14 | "apache solr", 15 | "solr", 16 | "time series", 17 | "timeseries", 18 | "time-series" 19 | ], 20 | "logos": { 21 | "small": "img/logo.png", 22 | "large": "img/logo.png" 23 | }, 24 | "links": [ 25 | { 26 | "name": "Home Page", 27 | "url": "http://www.chronix.io" 28 | }, 29 | { 30 | "name": "GitHub", 31 | "url": "https://github.com/ChronixDB/chronix.grafana" 32 | }, 33 | { 34 | "name": "Issues", 35 | "url": "https://github.com/ChronixDB/chronix.grafana/issues" 36 | }, 37 | { 38 | "name": "License", 39 | "url": "https://github.com/ChronixDB/chronix.grafana/blob/master/LICENSE" 40 | } 41 | ], 42 | "screenshots": [ 43 | { 44 | "name": "ChronixDB in Grafana", 45 | "path": "img/screenshot.png" 46 | } 47 | ], 48 | "version": "0.4.0", 49 | "updated": "2016-11-05" 50 | }, 51 | "metrics": true, 52 | "annotations": false, 53 | "dependencies": { 54 | "grafanaVersion": "3.x.x", 55 | "plugins": [] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/config-controller.js: -------------------------------------------------------------------------------- 1 | export class ChronixConfigController {} 2 | 3 | ChronixConfigController.templateUrl = 'partials/config.html'; 4 | -------------------------------------------------------------------------------- /src/datasource.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | function escapeTag(name) { 4 | return name.indexOf('.') !== -1 ? `"${name}"` : name; 5 | } 6 | 7 | function toTagQueryString(tag, tagName) { 8 | return tagName + ':(' + tag.map(escapeTag).join(' OR ') + ')' 9 | } 10 | 11 | function toTargetQueryString(target) { 12 | if (!target.tags || Object.keys(target.tags).length === 0) { 13 | // simple name-only 14 | return target.name; 15 | } 16 | 17 | // create strings for each tag 18 | const targetQueryStrings = _(target.tags).map(toTagQueryString); 19 | 20 | return '(' + target.name + ' AND ' + targetQueryStrings.join(' AND ') + ')'; 21 | } 22 | 23 | function toTargetJoinString(target) { 24 | if (!target.attributes || Object.keys(target.attributes).length === 0) { 25 | return "name"; 26 | } 27 | // create strings for each tag 28 | return _(target.attributes).join(',') + ",name,type"; 29 | } 30 | 31 | var requiredFields = ["data", "start", "end", "_version_", "id", "name", "type"]; 32 | 33 | export class ChronixDbDatasource { 34 | 35 | constructor(instanceSettings, $q, backendSrv, templateSrv) { 36 | this.type = instanceSettings.type; 37 | this.url = instanceSettings.url; 38 | this.name = instanceSettings.name; 39 | this.$q = $q; 40 | this.backendSrv = backendSrv; 41 | this.templateSrv = templateSrv; 42 | } 43 | 44 | //region Required Grafana Datasource methods 45 | 46 | query(options) { 47 | // get the start and the end and multiply it with 1000 to get millis since 1970 48 | var start = options.range.from.unix() * 1000; 49 | var end = options.range.to.unix() * 1000; 50 | var targets = options.targets; 51 | 52 | return this.rawQuery(targets, start, end).then(this.extractTimeSeries); 53 | } 54 | 55 | /** 56 | * Attempts to connect to the URL entered by the user and responds with a promise to either a "success" or an 57 | * "error" message. 58 | */ 59 | testDatasource() { 60 | const options = { 61 | url: `${this.url}/select?q=%7B!lucene%7D*%3A*&rows=0`, 62 | method: 'GET' 63 | }; 64 | const successMessage = { 65 | status: "success", 66 | message: "Connection to Chronix established", 67 | title: "Success" 68 | }; 69 | const errorMessage = this.$q.reject({ 70 | status: "error", 71 | message: "Connection to Chronix failed", 72 | title: "Error" 73 | }); 74 | 75 | // perform the actual call... 76 | return this.backendSrv.datasourceRequest(options) 77 | // ... check if the response is technically successful ... 78 | .then(response => response && response.status === 200) 79 | // ... and respond appropriately 80 | .then(success => success ? successMessage : errorMessage) 81 | // ... and react appropriately, too, when the call somehow didn't work 82 | .catch(error => errorMessage); 83 | } 84 | 85 | /** 86 | * 87 | */ 88 | findTimeSeriesByNames(tsName) { 89 | const emptyResult = this.$q.when([]); 90 | 91 | if (!tsName || tsName === '*') { 92 | // no "*" accepted from the user 93 | return emptyResult; 94 | } 95 | 96 | if (tsName.indexOf('*') === -1) { 97 | // append an "*" at the end if the user didn't already provide one 98 | tsName = tsName + '*'; 99 | } 100 | 101 | const options = { 102 | //do a facet query 103 | url: `${this.url}/select?facet.field=name&facet=on&facet.mincount=1&q=name:${tsName}&rows=0&wt=json`, 104 | method: 'GET' 105 | }; 106 | 107 | return this.backendSrv.datasourceRequest(options) 108 | .then(response => response && response.data && response.data.facet_counts && response.data.facet_counts.facet_fields && response.data.facet_counts.facet_fields.name) 109 | .then((nameFields) => { 110 | // somehow no valid response => empty array 111 | if (!nameFields) { 112 | console.log(`could not find any matching time series for "${tsName}"`); 113 | return emptyResult; 114 | } 115 | 116 | // take only the names, not the counts 117 | return nameFields 118 | .filter((unused, index) => index % 2 === 0) 119 | // and provide them as objects with the "text" property 120 | .map(text => ({text})); 121 | }) 122 | // if the request itself failed 123 | .catch(error => emptyResult); 124 | } 125 | 126 | //endregion 127 | 128 | rawQuery(targets, start, end) { 129 | // create strings for each target 130 | var targetsQueryStrings = _(targets).map(toTargetQueryString); 131 | 132 | var query = 'name:(' + targetsQueryStrings.join(' OR ') + ')' 133 | + ' AND start:' + start 134 | + ' AND end:' + end; 135 | 136 | var joinquery = _(targets).map(toTargetJoinString); 137 | 138 | //At this point we have to query chronix 139 | var RAW_QUERY_BASE = '/select?fl=dataAsJson&wt=json'; 140 | var RAW_QUERY_JOIN = '&cj=' + joinquery; 141 | var RAW_QUERY_FILTER_FUNCTION = '';//'&cf=metric{vector:0.1}'; 142 | var RAW_QUERY_BASE_WITH_FILTER = RAW_QUERY_BASE + RAW_QUERY_FILTER_FUNCTION + RAW_QUERY_JOIN + '&q='; 143 | 144 | console.log("Chronix Query: " + RAW_QUERY_BASE_WITH_FILTER + query); 145 | 146 | var options = { 147 | method: 'GET', 148 | url: this.url + RAW_QUERY_BASE_WITH_FILTER + query 149 | }; 150 | 151 | return this.backendSrv.datasourceRequest(options).then(function (response) { 152 | return [targets, response]; 153 | }); 154 | } 155 | 156 | extractTimeSeries(targetsResponse) { 157 | var response = targetsResponse[1]; 158 | 159 | if (response.data === undefined) { 160 | return {data: []}; 161 | } 162 | var dataset = response.data.response.docs; 163 | 164 | var tsPoints = {}; 165 | 166 | for (var i = 0; i < dataset.length; i++) { 167 | var currentDataSet = dataset[i]; 168 | var currentTimeSeries = currentDataSet.name; 169 | 170 | if (!(currentTimeSeries in tsPoints)) { 171 | tsPoints[currentTimeSeries] = []; 172 | } 173 | 174 | var jsonData = JSON.parse(currentDataSet.dataAsJson); 175 | 176 | var timestamps = jsonData[0]; 177 | var values = jsonData[1]; 178 | 179 | //add them 180 | for (var j = 0; j < timestamps.length; j++) { 181 | tsPoints[currentTimeSeries].push([values[j], timestamps[j]]); 182 | } 183 | 184 | } 185 | 186 | var ret = []; 187 | for (var key in tsPoints) { 188 | ret.push({target: key, datapoints: tsPoints[key]}); 189 | } 190 | return {data: ret}; 191 | } 192 | 193 | /** 194 | * Gets the available fields / attributes 195 | */ 196 | suggestAttributes() { 197 | var options = { 198 | method: 'GET', 199 | url: this.url + '/admin/luke?numTerms=0&wt=json' 200 | }; 201 | 202 | return this.backendSrv.datasourceRequest(options).then(this.mapToTextValue); 203 | } 204 | 205 | mapToTextValue(result) { 206 | var fields = result.data.fields; 207 | 208 | var stringFields = []; 209 | //Iterate over the returned fields 210 | for (var property in fields) { 211 | if (fields.hasOwnProperty(property)) { 212 | if (requiredFields.indexOf(property.toLowerCase()) == -1) { 213 | stringFields.push(property) 214 | } 215 | } 216 | } 217 | return _.map(stringFields, (name) => { 218 | return {text: name}; 219 | }); 220 | } 221 | 222 | /** 223 | * Gets the available values for the attributes. 224 | * 225 | * @param name The name to get the available attributes. 226 | * @param attribute The attribute. 227 | */ 228 | suggestAttributesValues(name, attribute) { 229 | var options = { 230 | method: 'GET', 231 | url: this.url + '/select?facet.field=' + attribute + '&facet=on&q=name:' + name + '&rows=0&wt=json' 232 | }; 233 | 234 | return this.backendSrv.datasourceRequest(options).then(this.mapValueToText); 235 | } 236 | 237 | mapValueToText(result) { 238 | var fields = result.data.facet_counts.facet_fields; 239 | 240 | var field; 241 | //Iterate over the returned fields 242 | for (var property in fields) { 243 | if (fields.hasOwnProperty(property)) { 244 | field = property; 245 | } 246 | } 247 | 248 | var pairs = []; 249 | var values = fields[field]; 250 | 251 | //Build pairs 252 | for (var i = 0; i < values.length; i++) { 253 | pairs.push([values[i], values[++i]]); 254 | } 255 | 256 | return _.map(pairs, (pair) => { 257 | return {text: pair[0], value: pair[1]}; 258 | }); 259 | } 260 | 261 | } 262 | -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | import { ChronixDbDatasource } from './datasource'; 2 | import { ChronixDbQueryController } from './query-controller'; 3 | import { ChronixConfigController } from './config-controller'; 4 | 5 | export { 6 | ChronixDbDatasource as Datasource, 7 | ChronixDbQueryController as QueryCtrl, 8 | ChronixConfigController as ConfigCtrl 9 | }; 10 | -------------------------------------------------------------------------------- /src/partials/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 |

Time Series

7 | 8 |
Name:
9 |
10 | 19 | 22 | 23 | 24 |
25 |
26 | 27 |
28 |

Attributes

29 | 30 | 31 |
32 | {{ key }} = {{ value }} 33 | 34 | 35 | 36 |
37 | 38 | 39 |
40 | 41 | 42 | 43 |
44 | 45 | 46 |
47 |
48 |
Attribute key:
49 |
50 | 59 |
60 |
61 |
62 |
Attribute value:
63 |
64 | 73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 |
83 |
84 |
85 | 86 | 87 |
88 |

Join by

89 | 90 | 91 |
92 | {{ key }} 93 | 94 | 95 | 96 |
97 | 98 | 99 |
100 | 101 | 102 | 103 |
104 | 105 | 106 |
107 |
108 |
Join type:
109 |
110 | 119 | 120 | 121 | 122 | 123 | 124 | 125 |
126 |
127 |
128 |
129 | 130 |
131 | 132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /src/query-controller.js: -------------------------------------------------------------------------------- 1 | import { QueryCtrl } from 'app/plugins/sdk'; 2 | import _ from 'lodash'; 3 | 4 | function isInt (n) { 5 | return parseInt(n) % 1 === 0; 6 | } 7 | 8 | export class ChronixDbQueryController extends QueryCtrl { 9 | 10 | constructor ($scope, $injector) { 11 | super($scope, $injector); 12 | 13 | this.panel.stack = false; 14 | 15 | if (!this.panel.downsampling) { 16 | this.panel.downsampling = 'avg'; 17 | } 18 | 19 | if (!this.target.downsampling) { 20 | this.target.downsampling = this.panel.downsampling; 21 | this.target.sampling = this.panel.sampling; 22 | } 23 | 24 | /** 25 | * Is called if someone types something into a key field of an attribute. 26 | */ 27 | this.suggestAttributes = (query, callback) => { 28 | this.datasource.suggestAttributes() 29 | .then(this.getTextValues.bind(this)) 30 | .then(callback); 31 | }; 32 | 33 | /** 34 | * Is called if someone types something into a value field of an attribute. 35 | */ 36 | this.suggestTagValues = (query, callback) => { 37 | this.datasource.suggestAttributesValues(this.target.name, this.target.currentTagKey) 38 | .then(this.getTextValues.bind(this)) 39 | .then(callback); 40 | }; 41 | 42 | /** 43 | * Is called if someone types something into a key field of an attribute. 44 | */ 45 | this.suggestTagAttributes = (query, callback) => { 46 | this.datasource.suggestAttributes(query) 47 | .then(this.getTextValues.bind(this)) 48 | .then(callback); 49 | }; 50 | 51 | this.suggestMetrics = (query, callback) => { 52 | this.datasource.findTimeSeriesByNames(query) 53 | .then(this.getTextValues.bind(this)) 54 | .then(callback); 55 | }; 56 | 57 | this.validateTarget(); 58 | 59 | this.getCollapsedText = () => { 60 | return 'Expand to configure Chronix Query data source'; 61 | }; 62 | } 63 | 64 | validateTarget () { 65 | var errs = {}; 66 | 67 | if (!this.target.name) { 68 | errs.name = "You must supply a time series name."; 69 | } 70 | 71 | try { 72 | if (this.target.sampling) { 73 | this.datasource.convertToChronixInterval(this.target.sampling); 74 | } 75 | } catch (err) { 76 | errs.sampling = err.message; 77 | } 78 | 79 | this.target.errors = errs; 80 | } 81 | 82 | targetBlur () { 83 | this.validateTarget(); 84 | 85 | if (!_.isEqual(this.oldTarget, this.target) && _.isEmpty(this.target.errors)) { 86 | this.oldTarget = angular.copy(this.target); 87 | this.panelCtrl.refresh(); 88 | } 89 | }; 90 | 91 | getTextValues (metricFindResult) { 92 | return _.map(metricFindResult, function (value) { 93 | return value.text; 94 | }); 95 | }; 96 | 97 | /** 98 | * ========================================================================= 99 | * 100 | * Join section 101 | * 102 | * ========================================================================= 103 | */ 104 | 105 | /** 106 | * Is called if someone types something into the join by box 107 | * @param query 108 | * @param callback 109 | */ 110 | addJoinByAttribute (query, callback) { 111 | console.info("add join by attribute is called for " + query); 112 | 113 | this.datasource.suggestAttributes(query) 114 | .then(this.getTextValues.bind(this)) 115 | .then(callback); 116 | }; 117 | 118 | validateJoinAttributes () { 119 | console.info("validateJoinAttributes is called"); 120 | this.target.errors.attributes = null; 121 | if (!this.target.currentAttributeKey) { 122 | this.target.errors.attributes = "You must specify a tag name and value."; 123 | } 124 | }; 125 | 126 | /** 127 | * Is calls if someone removes a group by tag 128 | * @param attribute 129 | */ 130 | removeJoinByAttribute (attribute) { 131 | console.info("removeJoinByAttribute is called for " + attribute); 132 | 133 | var index = this.target.attributes.indexOf(attribute); 134 | 135 | this.target.attributes.splice(index, 1); 136 | 137 | if (_.size(this.target.attributes) === 0) { 138 | this.target.attributes = null; 139 | } 140 | this.targetBlur(); 141 | }; 142 | 143 | /** 144 | * Add join by attribute 145 | */ 146 | addJoinByAttribute () { 147 | console.info("addJoinByAttribute is called"); 148 | if (!this.panel.addJoinAttributeMode) { 149 | this.panel.addJoinAttributeMode = true; 150 | this.validateJoinAttributes(); 151 | return; 152 | } 153 | 154 | if (!this.target.attributes) { 155 | this.target.attributes = []; 156 | } 157 | 158 | this.validateJoinAttributes(); 159 | if (!this.target.errors.attributes) { 160 | this.target.attributes.push(this.target.currentAttributeKey); 161 | this.target.currentAttributeKey = ''; 162 | 163 | this.targetBlur(); 164 | } 165 | 166 | this.panel.addJoinAttributeMode = false; 167 | }; 168 | 169 | // Filter metric by tag 170 | addFilterTag () { 171 | if (!this.panel.addFilterTagMode) { 172 | this.panel.addFilterTagMode = true; 173 | this.validateFilterTag(); 174 | return; 175 | } 176 | 177 | if (!this.target.tags) { 178 | this.target.tags = {}; 179 | } 180 | 181 | this.validateFilterTag(); 182 | if (!this.target.errors.tags) { 183 | if (!_.has(this.target.tags, this.target.currentTagKey)) { 184 | this.target.tags[this.target.currentTagKey] = []; 185 | } 186 | this.target.tags[this.target.currentTagKey].push(this.target.currentTagValue); 187 | this.target.currentTagKey = ''; 188 | this.target.currentTagValue = ''; 189 | this.targetBlur(); 190 | } 191 | 192 | this.panel.addFilterTagMode = false; 193 | }; 194 | 195 | removeFilterTag (key) { 196 | delete this.target.tags[key]; 197 | if (_.size(this.target.tags) === 0) { 198 | this.target.tags = null; 199 | } 200 | this.targetBlur(); 201 | }; 202 | 203 | validateFilterTag () { 204 | this.target.errors.tags = null; 205 | if (!this.target.currentTagKey || !this.target.currentTagValue) { 206 | this.target.errors.tags = "You must specify a tag name and value."; 207 | } 208 | }; 209 | 210 | ////////////////////////////// 211 | // GROUP BY 212 | ////////////////////////////// 213 | addGroupBy () { 214 | if (!this.panel.addGroupByMode) { 215 | this.target.currentGroupByType = 'tag'; 216 | this.panel.addGroupByMode = true; 217 | this.panel.isTagGroupBy = true; 218 | this.validateGroupBy(); 219 | return; 220 | } 221 | this.validateGroupBy(); 222 | // nb: if error is found, means that user clicked on cross : cancels input 223 | 224 | if (_.isEmpty(this.target.errors.groupBy)) { 225 | if (this.panel.isTagGroupBy) { 226 | if (!this.target.groupByTags) { 227 | this.target.groupByTags = []; 228 | } 229 | if (!_.contains(this.target.groupByTags, this.target.groupBy.tagKey)) { 230 | this.target.groupByTags.push(this.target.groupBy.tagKey); 231 | this.targetBlur(); 232 | } 233 | this.target.groupBy.tagKey = ''; 234 | } 235 | else { 236 | if (!this.target.nonTagGroupBys) { 237 | this.target.nonTagGroupBys = []; 238 | } 239 | var groupBy = { 240 | name: this.target.currentGroupByType 241 | }; 242 | if (this.panel.isValueGroupBy) { 243 | groupBy.range_size = this.target.groupBy.valueRange; 244 | } else if (this.panel.isTimeGroupBy) { 245 | groupBy.range_size = this.target.groupBy.timeInterval; 246 | groupBy.group_count = this.target.groupBy.groupCount; 247 | } 248 | this.target.nonTagGroupBys.push(groupBy); 249 | } 250 | this.targetBlur(); 251 | } 252 | 253 | this.panel.isTagGroupBy = false; 254 | this.panel.isValueGroupBy = false; 255 | this.panel.isTimeGroupBy = false; 256 | this.panel.addGroupByMode = false; 257 | }; 258 | 259 | removeGroupByTag (index) { 260 | this.target.groupByTags.splice(index, 1); 261 | if (_.size(this.target.groupByTags) === 0) { 262 | this.target.groupByTags = null; 263 | } 264 | this.targetBlur(); 265 | }; 266 | 267 | removeNonTagGroupBy (index) { 268 | this.target.nonTagGroupBys.splice(index, 1); 269 | if (_.size(this.target.nonTagGroupBys) === 0) { 270 | this.target.nonTagGroupBys = null; 271 | } 272 | this.targetBlur(); 273 | }; 274 | 275 | changeGroupByInput () { 276 | this.panel.isTagGroupBy = this.target.currentGroupByType === 'tag'; 277 | this.panel.isValueGroupBy = this.target.currentGroupByType === 'value'; 278 | this.panel.isTimeGroupBy = this.target.currentGroupByType === 'time'; 279 | this.validateGroupBy(); 280 | }; 281 | 282 | getValuesOfGroupBy (groupBy) { 283 | return _.values(groupBy); 284 | }; 285 | 286 | validateGroupBy () { 287 | delete this.target.errors.groupBy; 288 | var errors = {}; 289 | this.panel.isGroupByValid = true; 290 | if (this.panel.isTagGroupBy) { 291 | if (!this.target.groupBy.tagKey) { 292 | this.panel.isGroupByValid = false; 293 | errors.tagKey = 'You must supply a tag name'; 294 | } 295 | } 296 | 297 | if (this.panel.isValueGroupBy) { 298 | if (!this.target.groupBy.valueRange || !isInt(this.target.groupBy.valueRange)) { 299 | errors.valueRange = "Range must be an integer"; 300 | this.isGroupByValid = false; 301 | } 302 | } 303 | 304 | if (this.panel.isTimeGroupBy) { 305 | try { 306 | this.datasource.convertToChronixInterval(this.target.groupBy.timeInterval); 307 | } catch (err) { 308 | errors.timeInterval = err.message; 309 | this.isGroupByValid = false; 310 | } 311 | if (!this.target.groupBy.groupCount || !isInt(this.target.groupBy.groupCount)) { 312 | errors.groupCount = "Group count must be an integer"; 313 | this.isGroupByValid = false; 314 | } 315 | } 316 | 317 | if (!_.isEmpty(errors)) { 318 | this.target.errors.groupBy = errors; 319 | } 320 | }; 321 | 322 | ////////////////////////////// 323 | // HORIZONTAL AGGREGATION 324 | ////////////////////////////// 325 | 326 | addHorizontalAggregator () { 327 | if (!this.panel.addHorizontalAggregatorMode) { 328 | this.panel.addHorizontalAggregatorMode = true; 329 | this.target.currentHorizontalAggregatorName = 'avg'; 330 | this.panel.hasSamplingRate = true; 331 | this.validateHorizontalAggregator(); 332 | return; 333 | } 334 | 335 | this.validateHorizontalAggregator(); 336 | // nb: if error is found, means that user clicked on cross : cancels input 337 | if (_.isEmpty(this.target.errors.horAggregator)) { 338 | if (!this.target.horizontalAggregators) { 339 | this.target.horizontalAggregators = []; 340 | } 341 | var aggregator = { 342 | name: this.target.currentHorizontalAggregatorName 343 | }; 344 | if (this.panel.hasSamplingRate) { 345 | aggregator.sampling_rate = this.target.horAggregator.samplingRate; 346 | } 347 | if (this.panel.hasUnit) { 348 | aggregator.unit = this.target.horAggregator.unit; 349 | } 350 | if (this.panel.hasFactor) { 351 | aggregator.factor = this.target.horAggregator.factor; 352 | } 353 | if (this.panel.hasPercentile) { 354 | aggregator.percentile = this.target.horAggregator.percentile; 355 | } 356 | this.target.horizontalAggregators.push(aggregator); 357 | this.targetBlur(); 358 | } 359 | 360 | this.panel.addHorizontalAggregatorMode = false; 361 | this.panel.hasSamplingRate = false; 362 | this.panel.hasUnit = false; 363 | this.panel.hasFactor = false; 364 | this.panel.hasPercentile = false; 365 | }; 366 | 367 | removeHorizontalAggregator (index) { 368 | this.target.horizontalAggregators.splice(index, 1); 369 | if (_.size(this.target.horizontalAggregators) === 0) { 370 | this.target.horizontalAggregators = null; 371 | } 372 | 373 | this.targetBlur(); 374 | }; 375 | 376 | changeHorAggregationInput () { 377 | this.panel.hasSamplingRate = _.contains(['avg', 'dev', 'max', 'min', 'sum', 'least_squares', 'count', 'percentile'], 378 | this.target.currentHorizontalAggregatorName); 379 | this.panel.hasUnit = _.contains(['sampler', 'rate'], this.target.currentHorizontalAggregatorName); 380 | this.panel.hasFactor = _.contains(['div', 'scale'], this.target.currentHorizontalAggregatorName); 381 | this.panel.hasPercentile = 'percentile' === this.target.currentHorizontalAggregatorName; 382 | this.validateHorizontalAggregator(); 383 | }; 384 | 385 | validateHorizontalAggregator () { 386 | delete this.target.errors.horAggregator; 387 | var errors = {}; 388 | this.panel.isAggregatorValid = true; 389 | 390 | if (this.panel.hasSamplingRate) { 391 | try { 392 | this.datasource.convertToChronixInterval(this.target.horAggregator.samplingRate); 393 | } catch (err) { 394 | errors.samplingRate = err.message; 395 | this.panel.isAggregatorValid = false; 396 | } 397 | } 398 | 399 | if (this.hasFactor) { 400 | if (!this.target.horAggregator.factor) { 401 | errors.factor = 'You must supply a numeric value for this aggregator'; 402 | this.panel.isAggregatorValid = false; 403 | } 404 | else if (parseInt(this.target.horAggregator.factor) === 0 && this.target.currentHorizontalAggregatorName === 'div') { 405 | errors.factor = 'Cannot divide by 0'; 406 | this.panel.isAggregatorValid = false; 407 | } 408 | } 409 | 410 | if (this.panel.hasPercentile) { 411 | if (!this.target.horAggregator.percentile || 412 | this.target.horAggregator.percentile <= 0 || 413 | this.target.horAggregator.percentile > 1) { 414 | errors.percentile = 'Percentile must be between 0 and 1'; 415 | this.panel.isAggregatorValid = false; 416 | } 417 | } 418 | 419 | if (!_.isEmpty(errors)) { 420 | this.target.errors.horAggregator = errors; 421 | } 422 | }; 423 | 424 | alert (message) { 425 | alert(message); 426 | }; 427 | 428 | } 429 | 430 | ChronixDbQueryController.templateUrl = 'partials/query.editor.html'; 431 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" 8 | 9 | ansi-regex@^2.0.0: 10 | version "2.1.1" 11 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 12 | 13 | ansi-styles@^2.2.1: 14 | version "2.2.1" 15 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 16 | 17 | argparse@^1.0.2: 18 | version "1.0.9" 19 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 20 | dependencies: 21 | sprintf-js "~1.0.2" 22 | 23 | array-differ@^1.0.0: 24 | version "1.0.0" 25 | resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" 26 | 27 | array-find-index@^1.0.1: 28 | version "1.0.2" 29 | resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" 30 | 31 | array-union@^1.0.1: 32 | version "1.0.2" 33 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 34 | dependencies: 35 | array-uniq "^1.0.1" 36 | 37 | array-uniq@^1.0.1: 38 | version "1.0.3" 39 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 40 | 41 | arrify@^1.0.0: 42 | version "1.0.1" 43 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 44 | 45 | async@^1.5.0, async@^1.5.2, async@~1.5.2: 46 | version "1.5.2" 47 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 48 | 49 | babel-code-frame@^6.22.0: 50 | version "6.22.0" 51 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" 52 | dependencies: 53 | chalk "^1.1.0" 54 | esutils "^2.0.2" 55 | js-tokens "^3.0.0" 56 | 57 | babel-core@^6.0.12, babel-core@^6.24.1, babel-core@^6.5.1: 58 | version "6.24.1" 59 | resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" 60 | dependencies: 61 | babel-code-frame "^6.22.0" 62 | babel-generator "^6.24.1" 63 | babel-helpers "^6.24.1" 64 | babel-messages "^6.23.0" 65 | babel-register "^6.24.1" 66 | babel-runtime "^6.22.0" 67 | babel-template "^6.24.1" 68 | babel-traverse "^6.24.1" 69 | babel-types "^6.24.1" 70 | babylon "^6.11.0" 71 | convert-source-map "^1.1.0" 72 | debug "^2.1.1" 73 | json5 "^0.5.0" 74 | lodash "^4.2.0" 75 | minimatch "^3.0.2" 76 | path-is-absolute "^1.0.0" 77 | private "^0.1.6" 78 | slash "^1.0.0" 79 | source-map "^0.5.0" 80 | 81 | babel-generator@^6.24.1: 82 | version "6.24.1" 83 | resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" 84 | dependencies: 85 | babel-messages "^6.23.0" 86 | babel-runtime "^6.22.0" 87 | babel-types "^6.24.1" 88 | detect-indent "^4.0.0" 89 | jsesc "^1.3.0" 90 | lodash "^4.2.0" 91 | source-map "^0.5.0" 92 | trim-right "^1.0.1" 93 | 94 | babel-helper-call-delegate@^6.24.1: 95 | version "6.24.1" 96 | resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" 97 | dependencies: 98 | babel-helper-hoist-variables "^6.24.1" 99 | babel-runtime "^6.22.0" 100 | babel-traverse "^6.24.1" 101 | babel-types "^6.24.1" 102 | 103 | babel-helper-define-map@^6.24.1: 104 | version "6.24.1" 105 | resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" 106 | dependencies: 107 | babel-helper-function-name "^6.24.1" 108 | babel-runtime "^6.22.0" 109 | babel-types "^6.24.1" 110 | lodash "^4.2.0" 111 | 112 | babel-helper-function-name@^6.24.1: 113 | version "6.24.1" 114 | resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" 115 | dependencies: 116 | babel-helper-get-function-arity "^6.24.1" 117 | babel-runtime "^6.22.0" 118 | babel-template "^6.24.1" 119 | babel-traverse "^6.24.1" 120 | babel-types "^6.24.1" 121 | 122 | babel-helper-get-function-arity@^6.24.1: 123 | version "6.24.1" 124 | resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" 125 | dependencies: 126 | babel-runtime "^6.22.0" 127 | babel-types "^6.24.1" 128 | 129 | babel-helper-hoist-variables@^6.24.1: 130 | version "6.24.1" 131 | resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" 132 | dependencies: 133 | babel-runtime "^6.22.0" 134 | babel-types "^6.24.1" 135 | 136 | babel-helper-optimise-call-expression@^6.24.1: 137 | version "6.24.1" 138 | resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" 139 | dependencies: 140 | babel-runtime "^6.22.0" 141 | babel-types "^6.24.1" 142 | 143 | babel-helper-regex@^6.24.1: 144 | version "6.24.1" 145 | resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" 146 | dependencies: 147 | babel-runtime "^6.22.0" 148 | babel-types "^6.24.1" 149 | lodash "^4.2.0" 150 | 151 | babel-helper-replace-supers@^6.24.1: 152 | version "6.24.1" 153 | resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" 154 | dependencies: 155 | babel-helper-optimise-call-expression "^6.24.1" 156 | babel-messages "^6.23.0" 157 | babel-runtime "^6.22.0" 158 | babel-template "^6.24.1" 159 | babel-traverse "^6.24.1" 160 | babel-types "^6.24.1" 161 | 162 | babel-helpers@^6.24.1: 163 | version "6.24.1" 164 | resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" 165 | dependencies: 166 | babel-runtime "^6.22.0" 167 | babel-template "^6.24.1" 168 | 169 | babel-messages@^6.23.0: 170 | version "6.23.0" 171 | resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" 172 | dependencies: 173 | babel-runtime "^6.22.0" 174 | 175 | babel-plugin-check-es2015-constants@^6.22.0: 176 | version "6.22.0" 177 | resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" 178 | dependencies: 179 | babel-runtime "^6.22.0" 180 | 181 | babel-plugin-transform-es2015-arrow-functions@^6.22.0: 182 | version "6.22.0" 183 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" 184 | dependencies: 185 | babel-runtime "^6.22.0" 186 | 187 | babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: 188 | version "6.22.0" 189 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" 190 | dependencies: 191 | babel-runtime "^6.22.0" 192 | 193 | babel-plugin-transform-es2015-block-scoping@^6.24.1: 194 | version "6.24.1" 195 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" 196 | dependencies: 197 | babel-runtime "^6.22.0" 198 | babel-template "^6.24.1" 199 | babel-traverse "^6.24.1" 200 | babel-types "^6.24.1" 201 | lodash "^4.2.0" 202 | 203 | babel-plugin-transform-es2015-classes@^6.24.1: 204 | version "6.24.1" 205 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" 206 | dependencies: 207 | babel-helper-define-map "^6.24.1" 208 | babel-helper-function-name "^6.24.1" 209 | babel-helper-optimise-call-expression "^6.24.1" 210 | babel-helper-replace-supers "^6.24.1" 211 | babel-messages "^6.23.0" 212 | babel-runtime "^6.22.0" 213 | babel-template "^6.24.1" 214 | babel-traverse "^6.24.1" 215 | babel-types "^6.24.1" 216 | 217 | babel-plugin-transform-es2015-computed-properties@^6.24.1: 218 | version "6.24.1" 219 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" 220 | dependencies: 221 | babel-runtime "^6.22.0" 222 | babel-template "^6.24.1" 223 | 224 | babel-plugin-transform-es2015-destructuring@^6.22.0: 225 | version "6.23.0" 226 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" 227 | dependencies: 228 | babel-runtime "^6.22.0" 229 | 230 | babel-plugin-transform-es2015-duplicate-keys@^6.24.1: 231 | version "6.24.1" 232 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" 233 | dependencies: 234 | babel-runtime "^6.22.0" 235 | babel-types "^6.24.1" 236 | 237 | babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.8.0: 238 | version "6.23.0" 239 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" 240 | dependencies: 241 | babel-runtime "^6.22.0" 242 | 243 | babel-plugin-transform-es2015-function-name@^6.24.1: 244 | version "6.24.1" 245 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" 246 | dependencies: 247 | babel-helper-function-name "^6.24.1" 248 | babel-runtime "^6.22.0" 249 | babel-types "^6.24.1" 250 | 251 | babel-plugin-transform-es2015-literals@^6.22.0: 252 | version "6.22.0" 253 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" 254 | dependencies: 255 | babel-runtime "^6.22.0" 256 | 257 | babel-plugin-transform-es2015-modules-amd@^6.24.1: 258 | version "6.24.1" 259 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" 260 | dependencies: 261 | babel-plugin-transform-es2015-modules-commonjs "^6.24.1" 262 | babel-runtime "^6.22.0" 263 | babel-template "^6.24.1" 264 | 265 | babel-plugin-transform-es2015-modules-commonjs@^6.24.1: 266 | version "6.24.1" 267 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" 268 | dependencies: 269 | babel-plugin-transform-strict-mode "^6.24.1" 270 | babel-runtime "^6.22.0" 271 | babel-template "^6.24.1" 272 | babel-types "^6.24.1" 273 | 274 | babel-plugin-transform-es2015-modules-systemjs@^6.14.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: 275 | version "6.24.1" 276 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" 277 | dependencies: 278 | babel-helper-hoist-variables "^6.24.1" 279 | babel-runtime "^6.22.0" 280 | babel-template "^6.24.1" 281 | 282 | babel-plugin-transform-es2015-modules-umd@^6.24.1: 283 | version "6.24.1" 284 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" 285 | dependencies: 286 | babel-plugin-transform-es2015-modules-amd "^6.24.1" 287 | babel-runtime "^6.22.0" 288 | babel-template "^6.24.1" 289 | 290 | babel-plugin-transform-es2015-object-super@^6.24.1: 291 | version "6.24.1" 292 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" 293 | dependencies: 294 | babel-helper-replace-supers "^6.24.1" 295 | babel-runtime "^6.22.0" 296 | 297 | babel-plugin-transform-es2015-parameters@^6.24.1: 298 | version "6.24.1" 299 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" 300 | dependencies: 301 | babel-helper-call-delegate "^6.24.1" 302 | babel-helper-get-function-arity "^6.24.1" 303 | babel-runtime "^6.22.0" 304 | babel-template "^6.24.1" 305 | babel-traverse "^6.24.1" 306 | babel-types "^6.24.1" 307 | 308 | babel-plugin-transform-es2015-shorthand-properties@^6.24.1: 309 | version "6.24.1" 310 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" 311 | dependencies: 312 | babel-runtime "^6.22.0" 313 | babel-types "^6.24.1" 314 | 315 | babel-plugin-transform-es2015-spread@^6.22.0: 316 | version "6.22.0" 317 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" 318 | dependencies: 319 | babel-runtime "^6.22.0" 320 | 321 | babel-plugin-transform-es2015-sticky-regex@^6.24.1: 322 | version "6.24.1" 323 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" 324 | dependencies: 325 | babel-helper-regex "^6.24.1" 326 | babel-runtime "^6.22.0" 327 | babel-types "^6.24.1" 328 | 329 | babel-plugin-transform-es2015-template-literals@^6.22.0: 330 | version "6.22.0" 331 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" 332 | dependencies: 333 | babel-runtime "^6.22.0" 334 | 335 | babel-plugin-transform-es2015-typeof-symbol@^6.22.0: 336 | version "6.23.0" 337 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" 338 | dependencies: 339 | babel-runtime "^6.22.0" 340 | 341 | babel-plugin-transform-es2015-unicode-regex@^6.24.1: 342 | version "6.24.1" 343 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" 344 | dependencies: 345 | babel-helper-regex "^6.24.1" 346 | babel-runtime "^6.22.0" 347 | regexpu-core "^2.0.0" 348 | 349 | babel-plugin-transform-regenerator@^6.24.1: 350 | version "6.24.1" 351 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" 352 | dependencies: 353 | regenerator-transform "0.9.11" 354 | 355 | babel-plugin-transform-strict-mode@^6.24.1: 356 | version "6.24.1" 357 | resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" 358 | dependencies: 359 | babel-runtime "^6.22.0" 360 | babel-types "^6.24.1" 361 | 362 | babel-preset-es2015@^6.14.0: 363 | version "6.24.1" 364 | resolved "https://registry.yarnpkg.com/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz#d44050d6bc2c9feea702aaf38d727a0210538939" 365 | dependencies: 366 | babel-plugin-check-es2015-constants "^6.22.0" 367 | babel-plugin-transform-es2015-arrow-functions "^6.22.0" 368 | babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" 369 | babel-plugin-transform-es2015-block-scoping "^6.24.1" 370 | babel-plugin-transform-es2015-classes "^6.24.1" 371 | babel-plugin-transform-es2015-computed-properties "^6.24.1" 372 | babel-plugin-transform-es2015-destructuring "^6.22.0" 373 | babel-plugin-transform-es2015-duplicate-keys "^6.24.1" 374 | babel-plugin-transform-es2015-for-of "^6.22.0" 375 | babel-plugin-transform-es2015-function-name "^6.24.1" 376 | babel-plugin-transform-es2015-literals "^6.22.0" 377 | babel-plugin-transform-es2015-modules-amd "^6.24.1" 378 | babel-plugin-transform-es2015-modules-commonjs "^6.24.1" 379 | babel-plugin-transform-es2015-modules-systemjs "^6.24.1" 380 | babel-plugin-transform-es2015-modules-umd "^6.24.1" 381 | babel-plugin-transform-es2015-object-super "^6.24.1" 382 | babel-plugin-transform-es2015-parameters "^6.24.1" 383 | babel-plugin-transform-es2015-shorthand-properties "^6.24.1" 384 | babel-plugin-transform-es2015-spread "^6.22.0" 385 | babel-plugin-transform-es2015-sticky-regex "^6.24.1" 386 | babel-plugin-transform-es2015-template-literals "^6.22.0" 387 | babel-plugin-transform-es2015-typeof-symbol "^6.22.0" 388 | babel-plugin-transform-es2015-unicode-regex "^6.24.1" 389 | babel-plugin-transform-regenerator "^6.24.1" 390 | 391 | babel-register@^6.24.1: 392 | version "6.24.1" 393 | resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" 394 | dependencies: 395 | babel-core "^6.24.1" 396 | babel-runtime "^6.22.0" 397 | core-js "^2.4.0" 398 | home-or-tmp "^2.0.0" 399 | lodash "^4.2.0" 400 | mkdirp "^0.5.1" 401 | source-map-support "^0.4.2" 402 | 403 | babel-runtime@^6.18.0, babel-runtime@^6.22.0: 404 | version "6.23.0" 405 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" 406 | dependencies: 407 | core-js "^2.4.0" 408 | regenerator-runtime "^0.10.0" 409 | 410 | babel-template@^6.24.1: 411 | version "6.24.1" 412 | resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" 413 | dependencies: 414 | babel-runtime "^6.22.0" 415 | babel-traverse "^6.24.1" 416 | babel-types "^6.24.1" 417 | babylon "^6.11.0" 418 | lodash "^4.2.0" 419 | 420 | babel-traverse@^6.24.1: 421 | version "6.24.1" 422 | resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" 423 | dependencies: 424 | babel-code-frame "^6.22.0" 425 | babel-messages "^6.23.0" 426 | babel-runtime "^6.22.0" 427 | babel-types "^6.24.1" 428 | babylon "^6.15.0" 429 | debug "^2.2.0" 430 | globals "^9.0.0" 431 | invariant "^2.2.0" 432 | lodash "^4.2.0" 433 | 434 | babel-types@^6.19.0, babel-types@^6.24.1: 435 | version "6.24.1" 436 | resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" 437 | dependencies: 438 | babel-runtime "^6.22.0" 439 | esutils "^2.0.2" 440 | lodash "^4.2.0" 441 | to-fast-properties "^1.0.1" 442 | 443 | babylon@^6.11.0, babylon@^6.15.0: 444 | version "6.17.1" 445 | resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.1.tgz#17f14fddf361b695981fe679385e4f1c01ebd86f" 446 | 447 | balanced-match@^0.4.1: 448 | version "0.4.2" 449 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 450 | 451 | body-parser@~1.14.0: 452 | version "1.14.2" 453 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.14.2.tgz#1015cb1fe2c443858259581db53332f8d0cf50f9" 454 | dependencies: 455 | bytes "2.2.0" 456 | content-type "~1.0.1" 457 | debug "~2.2.0" 458 | depd "~1.1.0" 459 | http-errors "~1.3.1" 460 | iconv-lite "0.4.13" 461 | on-finished "~2.3.0" 462 | qs "5.2.0" 463 | raw-body "~2.1.5" 464 | type-is "~1.6.10" 465 | 466 | brace-expansion@^1.1.7: 467 | version "1.1.7" 468 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" 469 | dependencies: 470 | balanced-match "^0.4.1" 471 | concat-map "0.0.1" 472 | 473 | builtin-modules@^1.0.0: 474 | version "1.1.1" 475 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 476 | 477 | bytes@2.2.0: 478 | version "2.2.0" 479 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.2.0.tgz#fd35464a403f6f9117c2de3609ecff9cae000588" 480 | 481 | bytes@2.4.0: 482 | version "2.4.0" 483 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" 484 | 485 | camelcase-keys@^2.0.0: 486 | version "2.1.0" 487 | resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" 488 | dependencies: 489 | camelcase "^2.0.0" 490 | map-obj "^1.0.0" 491 | 492 | camelcase@^2.0.0: 493 | version "2.1.1" 494 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" 495 | 496 | chalk@^1.1.0, chalk@^1.1.1, chalk@~1.1.1: 497 | version "1.1.3" 498 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 499 | dependencies: 500 | ansi-styles "^2.2.1" 501 | escape-string-regexp "^1.0.2" 502 | has-ansi "^2.0.0" 503 | strip-ansi "^3.0.0" 504 | supports-color "^2.0.0" 505 | 506 | coffee-script@~1.10.0: 507 | version "1.10.0" 508 | resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.10.0.tgz#12938bcf9be1948fa006f92e0c4c9e81705108c0" 509 | 510 | colors@~1.1.2: 511 | version "1.1.2" 512 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" 513 | 514 | concat-map@0.0.1: 515 | version "0.0.1" 516 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 517 | 518 | content-type@~1.0.1: 519 | version "1.0.2" 520 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 521 | 522 | convert-source-map@^1.1.0: 523 | version "1.5.0" 524 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" 525 | 526 | core-js@^2.4.0: 527 | version "2.4.1" 528 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" 529 | 530 | currently-unhandled@^0.4.1: 531 | version "0.4.1" 532 | resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" 533 | dependencies: 534 | array-find-index "^1.0.1" 535 | 536 | dateformat@~1.0.12: 537 | version "1.0.12" 538 | resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" 539 | dependencies: 540 | get-stdin "^4.0.1" 541 | meow "^3.3.0" 542 | 543 | debug@^2.1.1, debug@^2.2.0: 544 | version "2.6.8" 545 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 546 | dependencies: 547 | ms "2.0.0" 548 | 549 | debug@~2.2.0: 550 | version "2.2.0" 551 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" 552 | dependencies: 553 | ms "0.7.1" 554 | 555 | decamelize@^1.1.2: 556 | version "1.2.0" 557 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 558 | 559 | depd@~1.1.0: 560 | version "1.1.0" 561 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" 562 | 563 | detect-indent@^4.0.0: 564 | version "4.0.0" 565 | resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" 566 | dependencies: 567 | repeating "^2.0.0" 568 | 569 | ee-first@1.1.1: 570 | version "1.1.1" 571 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 572 | 573 | error-ex@^1.2.0: 574 | version "1.3.1" 575 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" 576 | dependencies: 577 | is-arrayish "^0.2.1" 578 | 579 | escape-string-regexp@^1.0.2: 580 | version "1.0.5" 581 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 582 | 583 | esprima@^2.6.0: 584 | version "2.7.3" 585 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 586 | 587 | esutils@^2.0.2: 588 | version "2.0.2" 589 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 590 | 591 | eventemitter2@~0.4.13: 592 | version "0.4.14" 593 | resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" 594 | 595 | exit@~0.1.1: 596 | version "0.1.2" 597 | resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" 598 | 599 | faye-websocket@~0.10.0: 600 | version "0.10.0" 601 | resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" 602 | dependencies: 603 | websocket-driver ">=0.5.1" 604 | 605 | file-sync-cmp@^0.1.0: 606 | version "0.1.1" 607 | resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b" 608 | 609 | find-up@^1.0.0: 610 | version "1.1.2" 611 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 612 | dependencies: 613 | path-exists "^2.0.0" 614 | pinkie-promise "^2.0.0" 615 | 616 | findup-sync@~0.3.0: 617 | version "0.3.0" 618 | resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" 619 | dependencies: 620 | glob "~5.0.0" 621 | 622 | fs.realpath@^1.0.0: 623 | version "1.0.0" 624 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 625 | 626 | gaze@^1.0.0: 627 | version "1.1.2" 628 | resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" 629 | dependencies: 630 | globule "^1.0.0" 631 | 632 | get-stdin@^4.0.1: 633 | version "4.0.1" 634 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" 635 | 636 | getobject@~0.1.0: 637 | version "0.1.0" 638 | resolved "https://registry.yarnpkg.com/getobject/-/getobject-0.1.0.tgz#047a449789fa160d018f5486ed91320b6ec7885c" 639 | 640 | glob@^7.0.5, glob@~7.0.0: 641 | version "7.0.6" 642 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" 643 | dependencies: 644 | fs.realpath "^1.0.0" 645 | inflight "^1.0.4" 646 | inherits "2" 647 | minimatch "^3.0.2" 648 | once "^1.3.0" 649 | path-is-absolute "^1.0.0" 650 | 651 | glob@~5.0.0: 652 | version "5.0.15" 653 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 654 | dependencies: 655 | inflight "^1.0.4" 656 | inherits "2" 657 | minimatch "2 || 3" 658 | once "^1.3.0" 659 | path-is-absolute "^1.0.0" 660 | 661 | glob@~7.1.1: 662 | version "7.1.2" 663 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 664 | dependencies: 665 | fs.realpath "^1.0.0" 666 | inflight "^1.0.4" 667 | inherits "2" 668 | minimatch "^3.0.4" 669 | once "^1.3.0" 670 | path-is-absolute "^1.0.0" 671 | 672 | globals@^9.0.0: 673 | version "9.17.0" 674 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" 675 | 676 | globule@^1.0.0: 677 | version "1.1.0" 678 | resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f" 679 | dependencies: 680 | glob "~7.1.1" 681 | lodash "~4.16.4" 682 | minimatch "~3.0.2" 683 | 684 | graceful-fs@^4.1.2: 685 | version "4.1.11" 686 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 687 | 688 | grunt-babel@^6.0.0: 689 | version "6.0.0" 690 | resolved "https://registry.yarnpkg.com/grunt-babel/-/grunt-babel-6.0.0.tgz#378189b487de1168c4c4a9fc88dd6005b35df960" 691 | dependencies: 692 | babel-core "^6.0.12" 693 | 694 | grunt-cli@^1.2.0, grunt-cli@~1.2.0: 695 | version "1.2.0" 696 | resolved "https://registry.yarnpkg.com/grunt-cli/-/grunt-cli-1.2.0.tgz#562b119ebb069ddb464ace2845501be97b35b6a8" 697 | dependencies: 698 | findup-sync "~0.3.0" 699 | grunt-known-options "~1.1.0" 700 | nopt "~3.0.6" 701 | resolve "~1.1.0" 702 | 703 | grunt-contrib-clean@^1.0.0: 704 | version "1.1.0" 705 | resolved "https://registry.yarnpkg.com/grunt-contrib-clean/-/grunt-contrib-clean-1.1.0.tgz#564abf2d0378a983a15b9e3f30ee75b738c40638" 706 | dependencies: 707 | async "^1.5.2" 708 | rimraf "^2.5.1" 709 | 710 | grunt-contrib-copy@^1.0.0: 711 | version "1.0.0" 712 | resolved "https://registry.yarnpkg.com/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz#7060c6581e904b8ab0d00f076e0a8f6e3e7c3573" 713 | dependencies: 714 | chalk "^1.1.1" 715 | file-sync-cmp "^0.1.0" 716 | 717 | grunt-contrib-watch@^1.0.0: 718 | version "1.0.0" 719 | resolved "https://registry.yarnpkg.com/grunt-contrib-watch/-/grunt-contrib-watch-1.0.0.tgz#84a1a7a1d6abd26ed568413496c73133e990018f" 720 | dependencies: 721 | async "^1.5.0" 722 | gaze "^1.0.0" 723 | lodash "^3.10.1" 724 | tiny-lr "^0.2.1" 725 | 726 | grunt-known-options@~1.1.0: 727 | version "1.1.0" 728 | resolved "https://registry.yarnpkg.com/grunt-known-options/-/grunt-known-options-1.1.0.tgz#a4274eeb32fa765da5a7a3b1712617ce3b144149" 729 | 730 | grunt-legacy-log-utils@~1.0.0: 731 | version "1.0.0" 732 | resolved "https://registry.yarnpkg.com/grunt-legacy-log-utils/-/grunt-legacy-log-utils-1.0.0.tgz#a7b8e2d0fb35b5a50f4af986fc112749ebc96f3d" 733 | dependencies: 734 | chalk "~1.1.1" 735 | lodash "~4.3.0" 736 | 737 | grunt-legacy-log@~1.0.0: 738 | version "1.0.0" 739 | resolved "https://registry.yarnpkg.com/grunt-legacy-log/-/grunt-legacy-log-1.0.0.tgz#fb86f1809847bc07dc47843f9ecd6cacb62df2d5" 740 | dependencies: 741 | colors "~1.1.2" 742 | grunt-legacy-log-utils "~1.0.0" 743 | hooker "~0.2.3" 744 | lodash "~3.10.1" 745 | underscore.string "~3.2.3" 746 | 747 | grunt-legacy-util@~1.0.0: 748 | version "1.0.0" 749 | resolved "https://registry.yarnpkg.com/grunt-legacy-util/-/grunt-legacy-util-1.0.0.tgz#386aa78dc6ed50986c2b18957265b1b48abb9b86" 750 | dependencies: 751 | async "~1.5.2" 752 | exit "~0.1.1" 753 | getobject "~0.1.0" 754 | hooker "~0.2.3" 755 | lodash "~4.3.0" 756 | underscore.string "~3.2.3" 757 | which "~1.2.1" 758 | 759 | grunt@^1.0.1: 760 | version "1.0.1" 761 | resolved "https://registry.yarnpkg.com/grunt/-/grunt-1.0.1.tgz#e8778764e944b18f32bb0f10b9078475c9dfb56b" 762 | dependencies: 763 | coffee-script "~1.10.0" 764 | dateformat "~1.0.12" 765 | eventemitter2 "~0.4.13" 766 | exit "~0.1.1" 767 | findup-sync "~0.3.0" 768 | glob "~7.0.0" 769 | grunt-cli "~1.2.0" 770 | grunt-known-options "~1.1.0" 771 | grunt-legacy-log "~1.0.0" 772 | grunt-legacy-util "~1.0.0" 773 | iconv-lite "~0.4.13" 774 | js-yaml "~3.5.2" 775 | minimatch "~3.0.0" 776 | nopt "~3.0.6" 777 | path-is-absolute "~1.0.0" 778 | rimraf "~2.2.8" 779 | 780 | has-ansi@^2.0.0: 781 | version "2.0.0" 782 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 783 | dependencies: 784 | ansi-regex "^2.0.0" 785 | 786 | home-or-tmp@^2.0.0: 787 | version "2.0.0" 788 | resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" 789 | dependencies: 790 | os-homedir "^1.0.0" 791 | os-tmpdir "^1.0.1" 792 | 793 | hooker@~0.2.3: 794 | version "0.2.3" 795 | resolved "https://registry.yarnpkg.com/hooker/-/hooker-0.2.3.tgz#b834f723cc4a242aa65963459df6d984c5d3d959" 796 | 797 | hosted-git-info@^2.1.4: 798 | version "2.4.2" 799 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" 800 | 801 | http-errors@~1.3.1: 802 | version "1.3.1" 803 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.3.1.tgz#197e22cdebd4198585e8694ef6786197b91ed942" 804 | dependencies: 805 | inherits "~2.0.1" 806 | statuses "1" 807 | 808 | iconv-lite@0.4.13: 809 | version "0.4.13" 810 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" 811 | 812 | iconv-lite@~0.4.13: 813 | version "0.4.17" 814 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.17.tgz#4fdaa3b38acbc2c031b045d0edcdfe1ecab18c8d" 815 | 816 | indent-string@^2.1.0: 817 | version "2.1.0" 818 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" 819 | dependencies: 820 | repeating "^2.0.0" 821 | 822 | inflight@^1.0.4: 823 | version "1.0.6" 824 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 825 | dependencies: 826 | once "^1.3.0" 827 | wrappy "1" 828 | 829 | inherits@2, inherits@~2.0.1: 830 | version "2.0.3" 831 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 832 | 833 | invariant@^2.2.0: 834 | version "2.2.2" 835 | resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" 836 | dependencies: 837 | loose-envify "^1.0.0" 838 | 839 | is-arrayish@^0.2.1: 840 | version "0.2.1" 841 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 842 | 843 | is-builtin-module@^1.0.0: 844 | version "1.0.0" 845 | resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" 846 | dependencies: 847 | builtin-modules "^1.0.0" 848 | 849 | is-finite@^1.0.0: 850 | version "1.0.2" 851 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 852 | dependencies: 853 | number-is-nan "^1.0.0" 854 | 855 | is-utf8@^0.2.0: 856 | version "0.2.1" 857 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 858 | 859 | isexe@^2.0.0: 860 | version "2.0.0" 861 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 862 | 863 | js-tokens@^3.0.0: 864 | version "3.0.1" 865 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" 866 | 867 | js-yaml@~3.5.2: 868 | version "3.5.5" 869 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.5.5.tgz#0377c38017cabc7322b0d1fbcd25a491641f2fbe" 870 | dependencies: 871 | argparse "^1.0.2" 872 | esprima "^2.6.0" 873 | 874 | jsesc@^1.3.0: 875 | version "1.3.0" 876 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" 877 | 878 | jsesc@~0.5.0: 879 | version "0.5.0" 880 | resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" 881 | 882 | json5@^0.5.0: 883 | version "0.5.1" 884 | resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" 885 | 886 | livereload-js@^2.2.0: 887 | version "2.2.2" 888 | resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" 889 | 890 | load-grunt-tasks@^3.5.2: 891 | version "3.5.2" 892 | resolved "https://registry.yarnpkg.com/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz#0728561180fd20ff8a6927505852fc58aaea0c88" 893 | dependencies: 894 | arrify "^1.0.0" 895 | multimatch "^2.0.0" 896 | pkg-up "^1.0.0" 897 | resolve-pkg "^0.1.0" 898 | 899 | load-json-file@^1.0.0: 900 | version "1.1.0" 901 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" 902 | dependencies: 903 | graceful-fs "^4.1.2" 904 | parse-json "^2.2.0" 905 | pify "^2.0.0" 906 | pinkie-promise "^2.0.0" 907 | strip-bom "^2.0.0" 908 | 909 | lodash@^3.10.1, lodash@~3.10.1: 910 | version "3.10.1" 911 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" 912 | 913 | lodash@^4.0.0, lodash@^4.2.0: 914 | version "4.17.4" 915 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 916 | 917 | lodash@~4.16.4: 918 | version "4.16.6" 919 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" 920 | 921 | lodash@~4.3.0: 922 | version "4.3.0" 923 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.3.0.tgz#efd9c4a6ec53f3b05412429915c3e4824e4d25a4" 924 | 925 | loose-envify@^1.0.0: 926 | version "1.3.1" 927 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" 928 | dependencies: 929 | js-tokens "^3.0.0" 930 | 931 | loud-rejection@^1.0.0: 932 | version "1.6.0" 933 | resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" 934 | dependencies: 935 | currently-unhandled "^0.4.1" 936 | signal-exit "^3.0.0" 937 | 938 | map-obj@^1.0.0, map-obj@^1.0.1: 939 | version "1.0.1" 940 | resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" 941 | 942 | media-typer@0.3.0: 943 | version "0.3.0" 944 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 945 | 946 | meow@^3.3.0: 947 | version "3.7.0" 948 | resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" 949 | dependencies: 950 | camelcase-keys "^2.0.0" 951 | decamelize "^1.1.2" 952 | loud-rejection "^1.0.0" 953 | map-obj "^1.0.1" 954 | minimist "^1.1.3" 955 | normalize-package-data "^2.3.4" 956 | object-assign "^4.0.1" 957 | read-pkg-up "^1.0.1" 958 | redent "^1.0.0" 959 | trim-newlines "^1.0.0" 960 | 961 | mime-db@~1.27.0: 962 | version "1.27.0" 963 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 964 | 965 | mime-types@~2.1.15: 966 | version "2.1.15" 967 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 968 | dependencies: 969 | mime-db "~1.27.0" 970 | 971 | "minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.0, minimatch@~3.0.2: 972 | version "3.0.4" 973 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 974 | dependencies: 975 | brace-expansion "^1.1.7" 976 | 977 | minimist@0.0.8: 978 | version "0.0.8" 979 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 980 | 981 | minimist@^1.1.3: 982 | version "1.2.0" 983 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 984 | 985 | mkdirp@^0.5.1: 986 | version "0.5.1" 987 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 988 | dependencies: 989 | minimist "0.0.8" 990 | 991 | ms@0.7.1: 992 | version "0.7.1" 993 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" 994 | 995 | ms@2.0.0: 996 | version "2.0.0" 997 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 998 | 999 | multimatch@^2.0.0: 1000 | version "2.1.0" 1001 | resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" 1002 | dependencies: 1003 | array-differ "^1.0.0" 1004 | array-union "^1.0.1" 1005 | arrify "^1.0.0" 1006 | minimatch "^3.0.0" 1007 | 1008 | nopt@~3.0.6: 1009 | version "3.0.6" 1010 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" 1011 | dependencies: 1012 | abbrev "1" 1013 | 1014 | normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: 1015 | version "2.3.8" 1016 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" 1017 | dependencies: 1018 | hosted-git-info "^2.1.4" 1019 | is-builtin-module "^1.0.0" 1020 | semver "2 || 3 || 4 || 5" 1021 | validate-npm-package-license "^3.0.1" 1022 | 1023 | number-is-nan@^1.0.0: 1024 | version "1.0.1" 1025 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1026 | 1027 | object-assign@^4.0.1: 1028 | version "4.1.1" 1029 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1030 | 1031 | on-finished@~2.3.0: 1032 | version "2.3.0" 1033 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1034 | dependencies: 1035 | ee-first "1.1.1" 1036 | 1037 | once@^1.3.0: 1038 | version "1.4.0" 1039 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1040 | dependencies: 1041 | wrappy "1" 1042 | 1043 | os-homedir@^1.0.0: 1044 | version "1.0.2" 1045 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1046 | 1047 | os-tmpdir@^1.0.1: 1048 | version "1.0.2" 1049 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1050 | 1051 | parse-json@^2.2.0: 1052 | version "2.2.0" 1053 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 1054 | dependencies: 1055 | error-ex "^1.2.0" 1056 | 1057 | parseurl@~1.3.0: 1058 | version "1.3.1" 1059 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 1060 | 1061 | path-exists@^2.0.0: 1062 | version "2.1.0" 1063 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 1064 | dependencies: 1065 | pinkie-promise "^2.0.0" 1066 | 1067 | path-is-absolute@^1.0.0, path-is-absolute@~1.0.0: 1068 | version "1.0.1" 1069 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1070 | 1071 | path-type@^1.0.0: 1072 | version "1.1.0" 1073 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" 1074 | dependencies: 1075 | graceful-fs "^4.1.2" 1076 | pify "^2.0.0" 1077 | pinkie-promise "^2.0.0" 1078 | 1079 | pify@^2.0.0: 1080 | version "2.3.0" 1081 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1082 | 1083 | pinkie-promise@^2.0.0: 1084 | version "2.0.1" 1085 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 1086 | dependencies: 1087 | pinkie "^2.0.0" 1088 | 1089 | pinkie@^2.0.0: 1090 | version "2.0.4" 1091 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 1092 | 1093 | pkg-up@^1.0.0: 1094 | version "1.0.0" 1095 | resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" 1096 | dependencies: 1097 | find-up "^1.0.0" 1098 | 1099 | private@^0.1.6: 1100 | version "0.1.7" 1101 | resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" 1102 | 1103 | qs@5.2.0: 1104 | version "5.2.0" 1105 | resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.0.tgz#a9f31142af468cb72b25b30136ba2456834916be" 1106 | 1107 | qs@~5.1.0: 1108 | version "5.1.0" 1109 | resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9" 1110 | 1111 | raw-body@~2.1.5: 1112 | version "2.1.7" 1113 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" 1114 | dependencies: 1115 | bytes "2.4.0" 1116 | iconv-lite "0.4.13" 1117 | unpipe "1.0.0" 1118 | 1119 | read-pkg-up@^1.0.1: 1120 | version "1.0.1" 1121 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" 1122 | dependencies: 1123 | find-up "^1.0.0" 1124 | read-pkg "^1.0.0" 1125 | 1126 | read-pkg@^1.0.0: 1127 | version "1.1.0" 1128 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" 1129 | dependencies: 1130 | load-json-file "^1.0.0" 1131 | normalize-package-data "^2.3.2" 1132 | path-type "^1.0.0" 1133 | 1134 | redent@^1.0.0: 1135 | version "1.0.0" 1136 | resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" 1137 | dependencies: 1138 | indent-string "^2.1.0" 1139 | strip-indent "^1.0.1" 1140 | 1141 | regenerate@^1.2.1: 1142 | version "1.3.2" 1143 | resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" 1144 | 1145 | regenerator-runtime@^0.10.0: 1146 | version "0.10.5" 1147 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" 1148 | 1149 | regenerator-transform@0.9.11: 1150 | version "0.9.11" 1151 | resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" 1152 | dependencies: 1153 | babel-runtime "^6.18.0" 1154 | babel-types "^6.19.0" 1155 | private "^0.1.6" 1156 | 1157 | regexpu-core@^2.0.0: 1158 | version "2.0.0" 1159 | resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" 1160 | dependencies: 1161 | regenerate "^1.2.1" 1162 | regjsgen "^0.2.0" 1163 | regjsparser "^0.1.4" 1164 | 1165 | regjsgen@^0.2.0: 1166 | version "0.2.0" 1167 | resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" 1168 | 1169 | regjsparser@^0.1.4: 1170 | version "0.1.5" 1171 | resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" 1172 | dependencies: 1173 | jsesc "~0.5.0" 1174 | 1175 | repeating@^2.0.0: 1176 | version "2.0.1" 1177 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" 1178 | dependencies: 1179 | is-finite "^1.0.0" 1180 | 1181 | resolve-from@^2.0.0: 1182 | version "2.0.0" 1183 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" 1184 | 1185 | resolve-pkg@^0.1.0: 1186 | version "0.1.0" 1187 | resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-0.1.0.tgz#02cc993410e2936962bd97166a1b077da9725531" 1188 | dependencies: 1189 | resolve-from "^2.0.0" 1190 | 1191 | resolve@~1.1.0: 1192 | version "1.1.7" 1193 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 1194 | 1195 | rimraf@^2.5.1: 1196 | version "2.6.1" 1197 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" 1198 | dependencies: 1199 | glob "^7.0.5" 1200 | 1201 | rimraf@~2.2.8: 1202 | version "2.2.8" 1203 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" 1204 | 1205 | "semver@2 || 3 || 4 || 5": 1206 | version "5.3.0" 1207 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 1208 | 1209 | signal-exit@^3.0.0: 1210 | version "3.0.2" 1211 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1212 | 1213 | slash@^1.0.0: 1214 | version "1.0.0" 1215 | resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" 1216 | 1217 | source-map-support@^0.4.2: 1218 | version "0.4.15" 1219 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" 1220 | dependencies: 1221 | source-map "^0.5.6" 1222 | 1223 | source-map@^0.5.0, source-map@^0.5.6: 1224 | version "0.5.6" 1225 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 1226 | 1227 | spdx-correct@~1.0.0: 1228 | version "1.0.2" 1229 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" 1230 | dependencies: 1231 | spdx-license-ids "^1.0.2" 1232 | 1233 | spdx-expression-parse@~1.0.0: 1234 | version "1.0.4" 1235 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" 1236 | 1237 | spdx-license-ids@^1.0.2: 1238 | version "1.2.2" 1239 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" 1240 | 1241 | sprintf-js@~1.0.2: 1242 | version "1.0.3" 1243 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1244 | 1245 | statuses@1: 1246 | version "1.3.1" 1247 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 1248 | 1249 | strip-ansi@^3.0.0: 1250 | version "3.0.1" 1251 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1252 | dependencies: 1253 | ansi-regex "^2.0.0" 1254 | 1255 | strip-bom@^2.0.0: 1256 | version "2.0.0" 1257 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 1258 | dependencies: 1259 | is-utf8 "^0.2.0" 1260 | 1261 | strip-indent@^1.0.1: 1262 | version "1.0.1" 1263 | resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" 1264 | dependencies: 1265 | get-stdin "^4.0.1" 1266 | 1267 | supports-color@^2.0.0: 1268 | version "2.0.0" 1269 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1270 | 1271 | tiny-lr@^0.2.1: 1272 | version "0.2.1" 1273 | resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-0.2.1.tgz#b3fdba802e5d56a33c2f6f10794b32e477ac729d" 1274 | dependencies: 1275 | body-parser "~1.14.0" 1276 | debug "~2.2.0" 1277 | faye-websocket "~0.10.0" 1278 | livereload-js "^2.2.0" 1279 | parseurl "~1.3.0" 1280 | qs "~5.1.0" 1281 | 1282 | to-fast-properties@^1.0.1: 1283 | version "1.0.3" 1284 | resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" 1285 | 1286 | trim-newlines@^1.0.0: 1287 | version "1.0.0" 1288 | resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" 1289 | 1290 | trim-right@^1.0.1: 1291 | version "1.0.1" 1292 | resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" 1293 | 1294 | type-is@~1.6.10: 1295 | version "1.6.15" 1296 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 1297 | dependencies: 1298 | media-typer "0.3.0" 1299 | mime-types "~2.1.15" 1300 | 1301 | underscore.string@~3.2.3: 1302 | version "3.2.3" 1303 | resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.2.3.tgz#806992633665d5e5fcb4db1fb3a862eb68e9e6da" 1304 | 1305 | unpipe@1.0.0: 1306 | version "1.0.0" 1307 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1308 | 1309 | validate-npm-package-license@^3.0.1: 1310 | version "3.0.1" 1311 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" 1312 | dependencies: 1313 | spdx-correct "~1.0.0" 1314 | spdx-expression-parse "~1.0.0" 1315 | 1316 | websocket-driver@>=0.5.1: 1317 | version "0.6.5" 1318 | resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" 1319 | dependencies: 1320 | websocket-extensions ">=0.1.1" 1321 | 1322 | websocket-extensions@>=0.1.1: 1323 | version "0.1.1" 1324 | resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.1.tgz#76899499c184b6ef754377c2dbb0cd6cb55d29e7" 1325 | 1326 | which@~1.2.1: 1327 | version "1.2.14" 1328 | resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" 1329 | dependencies: 1330 | isexe "^2.0.0" 1331 | 1332 | wrappy@1: 1333 | version "1.0.2" 1334 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1335 | --------------------------------------------------------------------------------