├── .gitignore ├── .jscs.json ├── Gruntfile.js ├── LICENSE ├── MIGRATION.md ├── README.md ├── dist ├── README.md ├── css │ └── query-editor.css ├── datasource.js ├── datasource.js.map ├── img │ └── simpleJson_logo.svg ├── module.js ├── module.js.map ├── partials │ ├── annotations.editor.html │ ├── config.html │ ├── query.editor.html │ └── query.options.html ├── plugin.json ├── query_ctrl.js └── query_ctrl.js.map ├── docker-compose.yaml ├── package.json ├── provisioning ├── dashboards-actual │ └── migration.json ├── dashboards │ └── default.yaml └── datasources │ └── default.yaml ├── server └── Dockerfile ├── spec ├── datasource_spec.js └── test-main.js ├── src ├── css │ └── query-editor.css ├── datasource.js ├── img │ └── simpleJson_logo.svg ├── module.js ├── partials │ ├── annotations.editor.html │ ├── config.html │ ├── query.editor.html │ └── query.options.html ├── plugin.json └── query_ctrl.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | coverage/ 4 | .aws-config.json 5 | awsconfig 6 | /emails/dist 7 | /public_gen 8 | /tmp 9 | vendor/phantomjs/phantomjs 10 | 11 | docs/AWS_S3_BUCKET 12 | docs/GIT_BRANCH 13 | docs/VERSION 14 | docs/GITCOMMIT 15 | docs/changed-files 16 | docs/changed-files 17 | 18 | # locally required config files 19 | public/css/*.min.css 20 | 21 | # Editor junk 22 | *.sublime-workspace 23 | *.swp 24 | .idea/ 25 | *.iml 26 | 27 | /data/* 28 | /bin/* 29 | 30 | conf/custom.ini 31 | fig.yml 32 | profile.cov 33 | grafana 34 | .notouch 35 | 36 | # Test artifacts 37 | /dist/test/ 38 | -------------------------------------------------------------------------------- /.jscs.json: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "disallowImplicitTypeConversion": ["string"], 4 | "disallowKeywords": ["with"], 5 | "disallowMultipleLineBreaks": true, 6 | "disallowMixedSpacesAndTabs": true, 7 | "disallowTrailingWhitespace": true, 8 | "requireSpacesInFunctionExpression": { 9 | "beforeOpeningCurlyBrace": true 10 | }, 11 | "disallowSpacesInsideArrayBrackets": true, 12 | "disallowSpacesInsideParentheses": true, 13 | "validateIndentation": 2 14 | } 15 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | require('load-grunt-tasks')(grunt); 4 | 5 | grunt.loadNpmTasks('grunt-execute'); 6 | grunt.loadNpmTasks('grunt-contrib-clean'); 7 | 8 | grunt.initConfig({ 9 | 10 | clean: ["dist"], 11 | 12 | copy: { 13 | src_to_dist: { 14 | cwd: 'src', 15 | expand: true, 16 | src: ['**/*', '!**/*.js', '!**/*.scss'], 17 | dest: 'dist' 18 | }, 19 | pluginDef: { 20 | expand: true, 21 | src: ['README.md'], 22 | dest: 'dist' 23 | } 24 | }, 25 | 26 | watch: { 27 | rebuild_all: { 28 | files: ['src/**/*'], 29 | tasks: ['default'], 30 | options: {spawn: false} 31 | } 32 | }, 33 | 34 | babel: { 35 | options: { 36 | sourceMap: true, 37 | presets: ['env'], 38 | plugins: ['transform-object-rest-spread'] 39 | }, 40 | dist: { 41 | files: [{ 42 | cwd: 'src', 43 | expand: true, 44 | src: ['**/*.js'], 45 | dest: 'dist', 46 | ext:'.js' 47 | }] 48 | }, 49 | distTestNoSystemJs: { 50 | files: [{ 51 | cwd: 'src', 52 | expand: true, 53 | src: ['**/*.js'], 54 | dest: 'dist/test', 55 | ext:'.js' 56 | }] 57 | }, 58 | distTestsSpecsNoSystemJs: { 59 | files: [{ 60 | expand: true, 61 | cwd: 'spec', 62 | src: ['**/*.js'], 63 | dest: 'dist/test/spec', 64 | ext:'.js' 65 | }] 66 | } 67 | }, 68 | 69 | mochaTest: { 70 | test: { 71 | options: { 72 | reporter: 'spec' 73 | }, 74 | src: ['dist/test/spec/test-main.js', 'dist/test/spec/*_spec.js'] 75 | } 76 | } 77 | }); 78 | 79 | grunt.registerTask('default', ['clean', 'copy:src_to_dist', 'copy:pluginDef', 'babel', 'mochaTest']); 80 | }; 81 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Grafana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MIGRATION.md: -------------------------------------------------------------------------------- 1 | # Migration Guide 2 | 3 | This plugin is now deprecated and **no longer maintained** by the Grafana team. This deprecation means that this plugin won't receive any feature updates or bug fixes. After 6 months (End of June 2024), the plugin will reach EOL and the repository will be archived. You can use [Grafana Infinity data source plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) as an alternative for connecting to JSON/CSV/XML/GraphQL endpoints. Refer the migration guide [here](https://github.com/grafana/grafana-infinity-datasource/discussions/740), if you still prefer connecting to existing grafana simple JSON backend server implementation. Alternatively, you can also build your own plugin. 4 | 5 | ## Building your own plugin 6 | 7 | If you are looking for building your own plugin, consider the examples [here](https://github.com/grafana/grafana-plugin-examples) and documentation [here](https://grafana.com/developers). 8 | 9 | ## Migrating to Infinity data source plugin 10 | 11 |

12 | => 13 | 14 |

15 | 16 | > [!IMPORTANT] 17 | > Infinity is not a drop-in replacement for simple JSON datasource plugin. This require manual migration efforts. But migrating to infinity is strongly recommended approach if you are using simple JSON API datasource plugin. 18 | 19 | ### Approach 1: Direct API connection / Simple approach / Recommended approach 20 | 21 | This is much easier and **recommended approach** to connect JSON api endpoints directly. Infinity allows you to connect directly to your JSON endpoints instead of requiring you to write your server implementation comparing to grafana simple json server approach. Refer [Infinity plugin website](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) for more details about connecting your APIs directly. 22 | 23 | With this approach, you can get rid of your custom json server and directly connect your API endpoints via Infinity plugin. If this approach is not possible for any reason, use the below alternate migration approach. 24 | 25 | ### Approach 2: Migrating using Grafana simple json server approach 26 | 27 | With this approach, Instead of connecting your API endpoints directly, you will be connecting via grafana simple JSON server (legacy server). Also in grafana, instead of using simple json datasource plugin, you will be using Infinity plugin. 28 | 29 | #### Migrating the configuration 30 | 31 | In terms of configuration editor, there is no much change. The URL used in simple json datasource goes into infinity config misc/url section. Other options such as proxy, tls/ca certificates, headers goes into network and headers section. 32 | 33 | | Before | After | 34 | |--|--| 35 | | image | image| 36 | 37 | #### Provisioning 38 | 39 | Provisioning of simple json and infinity is almost similar only the plugin id differs. Refer the infinity plugin [provisioning documentation](https://grafana.com/docs/plugins/yesoreyeram-infinity-datasource/latest/setup/provisioning/) for more examples. 40 | 41 | | Before | After | 42 | |--|--| 43 | | image | image| 44 | 45 | 46 | #### Migrating the queries ( quick migration / frontend parser ) 47 | 48 | If you are using one or more queries using Simple JSON as shown below, you can migrate to infinity using the steps provided below. This approach is simple but less powerful. Doesn't support grafana backend features such as alerting. 49 | 50 | | Before | After | 51 | |---|---| 52 | | image| imageimage| 53 | | Select the target in the query editor. Example `upper_25`| Select `JSON` as query type.
Select `Default`/`Frontend` as your parser.
Source: `URL`.
Format: `As IS`/`Legacy`.
HTTP Method: `POST`.
URL : `/query`
HTTP Body: In your http body you need to specify the targets: `{ "targets": [{ "target":"upper_25" }] }`| 54 | 55 | 56 | #### Migrating the queries ( recommended migration / backend parser ) 57 | 58 | Use this approach to migrate to get support for features such as alerting, public dashboards, query caching etc. 59 | 60 | | Before | After | 61 | |---|--| 62 | |image|imageimage| 63 | |Select the target in the query editor. Example `upper_25`|Query Type: `URL`
Parser: `Backend`
Source: `URL`
Format: `Time series`
HTTP method: `POST`
URL: `/query`
BODY: `{ "targets": [{ "target":"upper_25" }]}`
Parsing options/Root: `datapoints`
Column 1: `0` as selector. `upper_25` as alias. `Number` as format.
Column 2: `1` as selector. `Time` as alias. `Unix (ms)` as format.
| 64 | 65 | ### Migrating the annotations 66 | 67 | Migrating the annotations is similar to query. For example, below screenoshots show different annotation creations 68 | 69 | ###### Using Simple JSON 70 | image 71 | 72 | ###### Using Infinity 73 | image 74 | 75 | 76 | #### Troubleshooting 77 | 78 | > [!NOTE] 79 | > Infinity doesn't support direct browser connection to your API endpoints. All the requests will be proxied from grafana server. 80 | 81 | #### Sample migration dashboard 82 | 83 | image 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deprecated plugin. Use [Infinity data source plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) instead 2 | 3 | ## Project status 4 | 5 | > [!CAUTION] 6 | > This plugin is now **DEPRECATED** and **no longer maintained** by the Grafana team. You can use [Grafana Infinity data source plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) as an alternative for connecting to JSON/CSV/XML/GraphQL endpoints. Refer the migration guide [here](https://github.com/grafana/grafana-infinity-datasource/discussions/740), if you still prefer connecting to existing grafana simple JSON backend server implementation. This deprecation means that this plugin won't receive any feature updates or bug fixes. After 6 months (End of June 2024), the plugin will reach EOL and the repository will be archived. If you are looking for building your own plugin, consider the examples [here](https://github.com/grafana/grafana-plugin-examples) and documentation [here](https://grafana.com/developers). 7 | 8 | ## Simple JSON Datasource - a generic backend datasource 9 | 10 | You can find more documentation about datasource plugins in Grafana's [Docs](https://grafana.com/docs/grafana/latest/developers/plugins/). 11 | 12 | This also serves as a living example implementation of a datasource. 13 | 14 | Your backend needs to implement 4 urls: 15 | 16 | * `/` should return 200 ok. Used for "Test connection" on the datasource config page. 17 | * `/search` used by the find metric options on the query tab in panels. 18 | * `/query` should return metrics based on input. 19 | * `/annotations` should return annotations. 20 | 21 | Those two urls are optional: 22 | 23 | * `/tag-keys` should return tag keys for ad hoc filters. 24 | * `/tag-values` should return tag values for ad hoc filters. 25 | 26 | ## Installation 27 | 28 | To install this plugin using the `grafana-cli` tool: 29 | ``` 30 | sudo grafana-cli plugins install grafana-simple-json-datasource 31 | sudo service grafana-server restart 32 | ``` 33 | See [here](https://grafana.com/plugins/grafana-simple-json-datasource/installation) for more 34 | information. 35 | 36 | ### Example backend implementations 37 | - https://github.com/bergquist/fake-simple-json-datasource 38 | - https://github.com/smcquay/jsonds 39 | - https://github.com/ContextLogic/eventmaster 40 | - https://gist.github.com/linar-jether/95ff412f9d19fdf5e51293eb0c09b850 (Python/pandas backend) 41 | 42 | ### Query API 43 | 44 | Example `timeserie` request 45 | ``` javascript 46 | { 47 | "panelId": 1, 48 | "range": { 49 | "from": "2016-10-31T06:33:44.866Z", 50 | "to": "2016-10-31T12:33:44.866Z", 51 | "raw": { 52 | "from": "now-6h", 53 | "to": "now" 54 | } 55 | }, 56 | "rangeRaw": { 57 | "from": "now-6h", 58 | "to": "now" 59 | }, 60 | "interval": "30s", 61 | "intervalMs": 30000, 62 | "targets": [ 63 | { "target": "upper_50", "refId": "A", "type": "timeserie" }, 64 | { "target": "upper_75", "refId": "B", "type": "timeserie" } 65 | ], 66 | "adhocFilters": [{ 67 | "key": "City", 68 | "operator": "=", 69 | "value": "Berlin" 70 | }], 71 | "format": "json", 72 | "maxDataPoints": 550 73 | } 74 | ``` 75 | 76 | Example `timeserie` response 77 | ``` javascript 78 | [ 79 | { 80 | "target":"upper_75", // The field being queried for 81 | "datapoints":[ 82 | [622,1450754160000], // Metric value as a float , unixtimestamp in milliseconds 83 | [365,1450754220000] 84 | ] 85 | }, 86 | { 87 | "target":"upper_90", 88 | "datapoints":[ 89 | [861,1450754160000], 90 | [767,1450754220000] 91 | ] 92 | } 93 | ] 94 | ``` 95 | 96 | If the metric selected is `"type": "table"`, an example `table` response: 97 | ``` json 98 | [ 99 | { 100 | "columns":[ 101 | {"text":"Time","type":"time"}, 102 | {"text":"Country","type":"string"}, 103 | {"text":"Number","type":"number"} 104 | ], 105 | "rows":[ 106 | [1234567,"SE",123], 107 | [1234567,"DE",231], 108 | [1234567,"US",321] 109 | ], 110 | "type":"table" 111 | } 112 | ] 113 | ``` 114 | 115 | ### Annotation API 116 | 117 | The annotation request from the Simple JSON Datasource is a POST request to 118 | the `/annotations` endpoint in your datasource. The JSON request body looks like this: 119 | ``` javascript 120 | { 121 | "range": { 122 | "from": "2016-04-15T13:44:39.070Z", 123 | "to": "2016-04-15T14:44:39.070Z" 124 | }, 125 | "rangeRaw": { 126 | "from": "now-1h", 127 | "to": "now" 128 | }, 129 | "annotation": { 130 | "name": "deploy", 131 | "datasource": "Simple JSON Datasource", 132 | "iconColor": "rgba(255, 96, 96, 1)", 133 | "enable": true, 134 | "query": "#deploy" 135 | } 136 | } 137 | ``` 138 | 139 | Grafana expects a response containing an array of annotation objects in the 140 | following format: 141 | 142 | ``` javascript 143 | [ 144 | { 145 | annotation: annotation, // The original annotation sent from Grafana. 146 | time: time, // Time since UNIX Epoch in milliseconds. (required) 147 | title: title, // The title for the annotation tooltip. (required) 148 | tags: tags, // Tags for the annotation. (optional) 149 | text: text // Text for the annotation. (optional) 150 | } 151 | ] 152 | ``` 153 | 154 | Note: If the datasource is configured to connect directly to the backend, you 155 | also need to implement an OPTIONS endpoint at `/annotations` that responds 156 | with the correct CORS headers: 157 | 158 | ``` 159 | Access-Control-Allow-Headers:accept, content-type 160 | Access-Control-Allow-Methods:POST 161 | Access-Control-Allow-Origin:* 162 | ``` 163 | 164 | ### Search API 165 | 166 | Example request 167 | ``` javascript 168 | { target: 'upper_50' } 169 | ``` 170 | 171 | The search api can either return an array or map. 172 | 173 | Example array response 174 | ``` javascript 175 | ["upper_25","upper_50","upper_75","upper_90","upper_95"] 176 | ``` 177 | 178 | Example map response 179 | ``` javascript 180 | [ { "text" :"upper_25", "value": 1}, { "text" :"upper_75", "value": 2} ] 181 | ``` 182 | 183 | ### Tag Keys API 184 | 185 | Example request 186 | ``` javascript 187 | { } 188 | ``` 189 | 190 | The tag keys api returns: 191 | ```javascript 192 | [ 193 | {"type":"string","text":"City"}, 194 | {"type":"string","text":"Country"} 195 | ] 196 | ``` 197 | 198 | ### Tag Values API 199 | 200 | Example request 201 | ``` javascript 202 | {"key": "City"} 203 | ``` 204 | 205 | The tag values api returns: 206 | ```javascript 207 | [ 208 | {'text': 'Eins!'}, 209 | {'text': 'Zwei'}, 210 | {'text': 'Drei!'} 211 | ] 212 | ``` 213 | 214 | ### Dev setup 215 | 216 | This plugin requires node 6.10.0 217 | 218 | ``` 219 | npm install -g yarn 220 | yarn install 221 | npm run build 222 | ``` 223 | 224 | ### Changelog 225 | 226 | 1.4.1 227 | - Fix for query editor to be compatible with Grafana 7+ (broke due to change in Grafana). 228 | 229 | 1.4.0 230 | - Support for adhoc filters: 231 | - added tag-keys + tag-values api 232 | - added adHocFilters parameter to query body 233 | 234 | 1.3.5 235 | - Fix for dropdowns in query editor to allow writing template variables (broke due to change in Grafana). 236 | 237 | 1.3.4 238 | - Adds support for With Credentials (sends grafana cookies with request) when using Direct mode 239 | - Fix for the typeahead component for metrics dropdown (`/search` endpoint). 240 | 241 | 1.3.3 242 | - Adds support for basic authentication 243 | 244 | 1.2.4 245 | - Add support returning sets in the search endpoint 246 | 247 | 1.2.3 248 | - Allow nested templates in find metric query. #23 249 | 250 | 1.2.2 251 | - Dont execute hidden queries 252 | - Template support for metrics queries 253 | - Template support for annotation queries 254 | 255 | ### If using Grafana 2.6 256 | NOTE! 257 | for grafana 2.6 please use [this version](https://github.com/grafana/simple-json-datasource/commit/b78720f6e00c115203d8f4c0e81ccd3c16001f94) 258 | 259 | Copy the data source you want to `/public/app/plugins/datasource/`. Then restart grafana-server. The new data source should now be available in the data source type dropdown in the Add Data Source View. 260 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # Deprecated plugin. Use [Infinity data source plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) instead 2 | 3 | ## Project status 4 | 5 | > [!CAUTION] 6 | > This plugin is now **DEPRECATED** and **no longer maintained** by the Grafana team. You can use [Grafana Infinity data source plugin](https://grafana.com/grafana/plugins/yesoreyeram-infinity-datasource/) as an alternative for connecting to JSON/CSV/XML/GraphQL endpoints. Refer the migration guide [here](https://github.com/grafana/grafana-infinity-datasource/discussions/740), if you still prefer connecting to existing grafana simple JSON backend server implementation. This deprecation means that this plugin won't receive any feature updates or bug fixes. After 6 months (End of June 2024), the plugin will reach EOL and the repository will be archived. If you are looking for building your own plugin, consider the examples [here](https://github.com/grafana/grafana-plugin-examples) and documentation [here](https://grafana.com/developers). 7 | 8 | ## Simple JSON Datasource - a generic backend datasource 9 | 10 | You can find more documentation about datasource plugins in Grafana's [Docs](https://grafana.com/docs/grafana/latest/developers/plugins/). 11 | 12 | This also serves as a living example implementation of a datasource. 13 | 14 | Your backend needs to implement 4 urls: 15 | 16 | * `/` should return 200 ok. Used for "Test connection" on the datasource config page. 17 | * `/search` used by the find metric options on the query tab in panels. 18 | * `/query` should return metrics based on input. 19 | * `/annotations` should return annotations. 20 | 21 | Those two urls are optional: 22 | 23 | * `/tag-keys` should return tag keys for ad hoc filters. 24 | * `/tag-values` should return tag values for ad hoc filters. 25 | 26 | ## Installation 27 | 28 | To install this plugin using the `grafana-cli` tool: 29 | ``` 30 | sudo grafana-cli plugins install grafana-simple-json-datasource 31 | sudo service grafana-server restart 32 | ``` 33 | See [here](https://grafana.com/plugins/grafana-simple-json-datasource/installation) for more 34 | information. 35 | 36 | ### Example backend implementations 37 | - https://github.com/bergquist/fake-simple-json-datasource 38 | - https://github.com/smcquay/jsonds 39 | - https://github.com/ContextLogic/eventmaster 40 | - https://gist.github.com/linar-jether/95ff412f9d19fdf5e51293eb0c09b850 (Python/pandas backend) 41 | 42 | ### Query API 43 | 44 | Example `timeserie` request 45 | ``` javascript 46 | { 47 | "panelId": 1, 48 | "range": { 49 | "from": "2016-10-31T06:33:44.866Z", 50 | "to": "2016-10-31T12:33:44.866Z", 51 | "raw": { 52 | "from": "now-6h", 53 | "to": "now" 54 | } 55 | }, 56 | "rangeRaw": { 57 | "from": "now-6h", 58 | "to": "now" 59 | }, 60 | "interval": "30s", 61 | "intervalMs": 30000, 62 | "targets": [ 63 | { "target": "upper_50", "refId": "A", "type": "timeserie" }, 64 | { "target": "upper_75", "refId": "B", "type": "timeserie" } 65 | ], 66 | "adhocFilters": [{ 67 | "key": "City", 68 | "operator": "=", 69 | "value": "Berlin" 70 | }], 71 | "format": "json", 72 | "maxDataPoints": 550 73 | } 74 | ``` 75 | 76 | Example `timeserie` response 77 | ``` javascript 78 | [ 79 | { 80 | "target":"upper_75", // The field being queried for 81 | "datapoints":[ 82 | [622,1450754160000], // Metric value as a float , unixtimestamp in milliseconds 83 | [365,1450754220000] 84 | ] 85 | }, 86 | { 87 | "target":"upper_90", 88 | "datapoints":[ 89 | [861,1450754160000], 90 | [767,1450754220000] 91 | ] 92 | } 93 | ] 94 | ``` 95 | 96 | If the metric selected is `"type": "table"`, an example `table` response: 97 | ``` json 98 | [ 99 | { 100 | "columns":[ 101 | {"text":"Time","type":"time"}, 102 | {"text":"Country","type":"string"}, 103 | {"text":"Number","type":"number"} 104 | ], 105 | "rows":[ 106 | [1234567,"SE",123], 107 | [1234567,"DE",231], 108 | [1234567,"US",321] 109 | ], 110 | "type":"table" 111 | } 112 | ] 113 | ``` 114 | 115 | ### Annotation API 116 | 117 | The annotation request from the Simple JSON Datasource is a POST request to 118 | the `/annotations` endpoint in your datasource. The JSON request body looks like this: 119 | ``` javascript 120 | { 121 | "range": { 122 | "from": "2016-04-15T13:44:39.070Z", 123 | "to": "2016-04-15T14:44:39.070Z" 124 | }, 125 | "rangeRaw": { 126 | "from": "now-1h", 127 | "to": "now" 128 | }, 129 | "annotation": { 130 | "name": "deploy", 131 | "datasource": "Simple JSON Datasource", 132 | "iconColor": "rgba(255, 96, 96, 1)", 133 | "enable": true, 134 | "query": "#deploy" 135 | } 136 | } 137 | ``` 138 | 139 | Grafana expects a response containing an array of annotation objects in the 140 | following format: 141 | 142 | ``` javascript 143 | [ 144 | { 145 | annotation: annotation, // The original annotation sent from Grafana. 146 | time: time, // Time since UNIX Epoch in milliseconds. (required) 147 | title: title, // The title for the annotation tooltip. (required) 148 | tags: tags, // Tags for the annotation. (optional) 149 | text: text // Text for the annotation. (optional) 150 | } 151 | ] 152 | ``` 153 | 154 | Note: If the datasource is configured to connect directly to the backend, you 155 | also need to implement an OPTIONS endpoint at `/annotations` that responds 156 | with the correct CORS headers: 157 | 158 | ``` 159 | Access-Control-Allow-Headers:accept, content-type 160 | Access-Control-Allow-Methods:POST 161 | Access-Control-Allow-Origin:* 162 | ``` 163 | 164 | ### Search API 165 | 166 | Example request 167 | ``` javascript 168 | { target: 'upper_50' } 169 | ``` 170 | 171 | The search api can either return an array or map. 172 | 173 | Example array response 174 | ``` javascript 175 | ["upper_25","upper_50","upper_75","upper_90","upper_95"] 176 | ``` 177 | 178 | Example map response 179 | ``` javascript 180 | [ { "text" :"upper_25", "value": 1}, { "text" :"upper_75", "value": 2} ] 181 | ``` 182 | 183 | ### Tag Keys API 184 | 185 | Example request 186 | ``` javascript 187 | { } 188 | ``` 189 | 190 | The tag keys api returns: 191 | ```javascript 192 | [ 193 | {"type":"string","text":"City"}, 194 | {"type":"string","text":"Country"} 195 | ] 196 | ``` 197 | 198 | ### Tag Values API 199 | 200 | Example request 201 | ``` javascript 202 | {"key": "City"} 203 | ``` 204 | 205 | The tag values api returns: 206 | ```javascript 207 | [ 208 | {'text': 'Eins!'}, 209 | {'text': 'Zwei'}, 210 | {'text': 'Drei!'} 211 | ] 212 | ``` 213 | 214 | ### Dev setup 215 | 216 | This plugin requires node 6.10.0 217 | 218 | ``` 219 | npm install -g yarn 220 | yarn install 221 | npm run build 222 | ``` 223 | 224 | ### Changelog 225 | 226 | 1.4.1 227 | - Fix for query editor to be compatible with Grafana 7+ (broke due to change in Grafana). 228 | 229 | 1.4.0 230 | - Support for adhoc filters: 231 | - added tag-keys + tag-values api 232 | - added adHocFilters parameter to query body 233 | 234 | 1.3.5 235 | - Fix for dropdowns in query editor to allow writing template variables (broke due to change in Grafana). 236 | 237 | 1.3.4 238 | - Adds support for With Credentials (sends grafana cookies with request) when using Direct mode 239 | - Fix for the typeahead component for metrics dropdown (`/search` endpoint). 240 | 241 | 1.3.3 242 | - Adds support for basic authentication 243 | 244 | 1.2.4 245 | - Add support returning sets in the search endpoint 246 | 247 | 1.2.3 248 | - Allow nested templates in find metric query. #23 249 | 250 | 1.2.2 251 | - Dont execute hidden queries 252 | - Template support for metrics queries 253 | - Template support for annotation queries 254 | 255 | ### If using Grafana 2.6 256 | NOTE! 257 | for grafana 2.6 please use [this version](https://github.com/grafana/simple-json-datasource/commit/b78720f6e00c115203d8f4c0e81ccd3c16001f94) 258 | 259 | Copy the data source you want to `/public/app/plugins/datasource/`. Then restart grafana-server. The new data source should now be available in the data source type dropdown in the Add Data Source View. 260 | -------------------------------------------------------------------------------- /dist/css/query-editor.css: -------------------------------------------------------------------------------- 1 | .generic-datasource-query-row .query-keyword { 2 | width: 75px; 3 | } -------------------------------------------------------------------------------- /dist/datasource.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.GenericDatasource = undefined; 7 | 8 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 9 | 10 | var _lodash = require('lodash'); 11 | 12 | var _lodash2 = _interopRequireDefault(_lodash); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 17 | 18 | var GenericDatasource = exports.GenericDatasource = function () { 19 | function GenericDatasource(instanceSettings, $q, backendSrv, templateSrv) { 20 | _classCallCheck(this, GenericDatasource); 21 | 22 | this.type = instanceSettings.type; 23 | this.url = instanceSettings.url; 24 | this.name = instanceSettings.name; 25 | this.q = $q; 26 | this.backendSrv = backendSrv; 27 | this.templateSrv = templateSrv; 28 | this.withCredentials = instanceSettings.withCredentials; 29 | this.headers = { 'Content-Type': 'application/json' }; 30 | if (typeof instanceSettings.basicAuth === 'string' && instanceSettings.basicAuth.length > 0) { 31 | this.headers['Authorization'] = instanceSettings.basicAuth; 32 | } 33 | } 34 | 35 | _createClass(GenericDatasource, [{ 36 | key: 'query', 37 | value: function query(options) { 38 | var query = this.buildQueryParameters(options); 39 | query.targets = query.targets.filter(function (t) { 40 | return !t.hide; 41 | }); 42 | 43 | if (query.targets.length <= 0) { 44 | return this.q.when({ data: [] }); 45 | } 46 | 47 | if (this.templateSrv.getAdhocFilters) { 48 | query.adhocFilters = this.templateSrv.getAdhocFilters(this.name); 49 | } else { 50 | query.adhocFilters = []; 51 | } 52 | 53 | return this.doRequest({ 54 | url: this.url + '/query', 55 | data: query, 56 | method: 'POST' 57 | }); 58 | } 59 | }, { 60 | key: 'testDatasource', 61 | value: function testDatasource() { 62 | return this.doRequest({ 63 | url: this.url + '/', 64 | method: 'GET' 65 | }).then(function (response) { 66 | if (response.status === 200) { 67 | return { status: "success", message: "Data source is working", title: "Success" }; 68 | } 69 | }); 70 | } 71 | }, { 72 | key: 'annotationQuery', 73 | value: function annotationQuery(options) { 74 | var query = this.templateSrv.replace(options.annotation.query, {}, 'glob'); 75 | var annotationQuery = { 76 | range: options.range, 77 | annotation: { 78 | name: options.annotation.name, 79 | datasource: options.annotation.datasource, 80 | enable: options.annotation.enable, 81 | iconColor: options.annotation.iconColor, 82 | query: query 83 | }, 84 | rangeRaw: options.rangeRaw 85 | }; 86 | 87 | return this.doRequest({ 88 | url: this.url + '/annotations', 89 | method: 'POST', 90 | data: annotationQuery 91 | }).then(function (result) { 92 | return result.data; 93 | }); 94 | } 95 | }, { 96 | key: 'metricFindQuery', 97 | value: function metricFindQuery(query) { 98 | var interpolated = { 99 | target: this.templateSrv.replace(query, null, 'regex') 100 | }; 101 | 102 | return this.doRequest({ 103 | url: this.url + '/search', 104 | data: interpolated, 105 | method: 'POST' 106 | }).then(this.mapToTextValue); 107 | } 108 | }, { 109 | key: 'mapToTextValue', 110 | value: function mapToTextValue(result) { 111 | return _lodash2.default.map(result.data, function (d, i) { 112 | if (d && d.text && d.value) { 113 | return { text: d.text, value: d.value }; 114 | } else if (_lodash2.default.isObject(d)) { 115 | return { text: d, value: i }; 116 | } 117 | return { text: d, value: d }; 118 | }); 119 | } 120 | }, { 121 | key: 'doRequest', 122 | value: function doRequest(options) { 123 | options.withCredentials = this.withCredentials; 124 | options.headers = this.headers; 125 | 126 | return this.backendSrv.datasourceRequest(options); 127 | } 128 | }, { 129 | key: 'buildQueryParameters', 130 | value: function buildQueryParameters(options) { 131 | var _this = this; 132 | 133 | //remove placeholder targets 134 | options.targets = _lodash2.default.filter(options.targets, function (target) { 135 | return target.target !== 'select metric'; 136 | }); 137 | 138 | var targets = _lodash2.default.map(options.targets, function (target) { 139 | return { 140 | target: _this.templateSrv.replace(target.target, options.scopedVars, 'regex'), 141 | refId: target.refId, 142 | hide: target.hide, 143 | type: target.type || 'timeserie' 144 | }; 145 | }); 146 | 147 | options.targets = targets; 148 | 149 | return options; 150 | } 151 | }, { 152 | key: 'getTagKeys', 153 | value: function getTagKeys(options) { 154 | var _this2 = this; 155 | 156 | return new Promise(function (resolve, reject) { 157 | _this2.doRequest({ 158 | url: _this2.url + '/tag-keys', 159 | method: 'POST', 160 | data: options 161 | }).then(function (result) { 162 | return resolve(result.data); 163 | }); 164 | }); 165 | } 166 | }, { 167 | key: 'getTagValues', 168 | value: function getTagValues(options) { 169 | var _this3 = this; 170 | 171 | return new Promise(function (resolve, reject) { 172 | _this3.doRequest({ 173 | url: _this3.url + '/tag-values', 174 | method: 'POST', 175 | data: options 176 | }).then(function (result) { 177 | return resolve(result.data); 178 | }); 179 | }); 180 | } 181 | }]); 182 | 183 | return GenericDatasource; 184 | }(); 185 | //# sourceMappingURL=datasource.js.map 186 | -------------------------------------------------------------------------------- /dist/datasource.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/datasource.js"],"names":["GenericDatasource","instanceSettings","$q","backendSrv","templateSrv","type","url","name","q","withCredentials","headers","basicAuth","length","options","query","buildQueryParameters","targets","filter","t","hide","when","data","getAdhocFilters","adhocFilters","doRequest","method","then","response","status","message","title","replace","annotation","annotationQuery","range","datasource","enable","iconColor","rangeRaw","result","interpolated","target","mapToTextValue","_","map","d","i","text","value","isObject","datasourceRequest","scopedVars","refId","Promise","resolve","reject"],"mappings":";;;;;;;;;AAAA;;;;;;;;IAEaA,iB,WAAAA,iB;AAEX,6BAAYC,gBAAZ,EAA8BC,EAA9B,EAAkCC,UAAlC,EAA8CC,WAA9C,EAA2D;AAAA;;AACzD,SAAKC,IAAL,GAAYJ,iBAAiBI,IAA7B;AACA,SAAKC,GAAL,GAAWL,iBAAiBK,GAA5B;AACA,SAAKC,IAAL,GAAYN,iBAAiBM,IAA7B;AACA,SAAKC,CAAL,GAASN,EAAT;AACA,SAAKC,UAAL,GAAkBA,UAAlB;AACA,SAAKC,WAAL,GAAmBA,WAAnB;AACA,SAAKK,eAAL,GAAuBR,iBAAiBQ,eAAxC;AACA,SAAKC,OAAL,GAAe,EAAC,gBAAgB,kBAAjB,EAAf;AACA,QAAI,OAAOT,iBAAiBU,SAAxB,KAAsC,QAAtC,IAAkDV,iBAAiBU,SAAjB,CAA2BC,MAA3B,GAAoC,CAA1F,EAA6F;AAC3F,WAAKF,OAAL,CAAa,eAAb,IAAgCT,iBAAiBU,SAAjD;AACD;AACF;;;;0BAEKE,O,EAAS;AACb,UAAIC,QAAQ,KAAKC,oBAAL,CAA0BF,OAA1B,CAAZ;AACAC,YAAME,OAAN,GAAgBF,MAAME,OAAN,CAAcC,MAAd,CAAqB;AAAA,eAAK,CAACC,EAAEC,IAAR;AAAA,OAArB,CAAhB;;AAEA,UAAIL,MAAME,OAAN,CAAcJ,MAAd,IAAwB,CAA5B,EAA+B;AAC7B,eAAO,KAAKJ,CAAL,CAAOY,IAAP,CAAY,EAACC,MAAM,EAAP,EAAZ,CAAP;AACD;;AAED,UAAI,KAAKjB,WAAL,CAAiBkB,eAArB,EAAsC;AACpCR,cAAMS,YAAN,GAAqB,KAAKnB,WAAL,CAAiBkB,eAAjB,CAAiC,KAAKf,IAAtC,CAArB;AACD,OAFD,MAEO;AACLO,cAAMS,YAAN,GAAqB,EAArB;AACD;;AAED,aAAO,KAAKC,SAAL,CAAe;AACpBlB,aAAK,KAAKA,GAAL,GAAW,QADI;AAEpBe,cAAMP,KAFc;AAGpBW,gBAAQ;AAHY,OAAf,CAAP;AAKD;;;qCAEgB;AACf,aAAO,KAAKD,SAAL,CAAe;AACpBlB,aAAK,KAAKA,GAAL,GAAW,GADI;AAEpBmB,gBAAQ;AAFY,OAAf,EAGJC,IAHI,CAGC,oBAAY;AAClB,YAAIC,SAASC,MAAT,KAAoB,GAAxB,EAA6B;AAC3B,iBAAO,EAAEA,QAAQ,SAAV,EAAqBC,SAAS,wBAA9B,EAAwDC,OAAO,SAA/D,EAAP;AACD;AACF,OAPM,CAAP;AAQD;;;oCAEejB,O,EAAS;AACvB,UAAIC,QAAQ,KAAKV,WAAL,CAAiB2B,OAAjB,CAAyBlB,QAAQmB,UAAR,CAAmBlB,KAA5C,EAAmD,EAAnD,EAAuD,MAAvD,CAAZ;AACA,UAAImB,kBAAkB;AACpBC,eAAOrB,QAAQqB,KADK;AAEpBF,oBAAY;AACVzB,gBAAMM,QAAQmB,UAAR,CAAmBzB,IADf;AAEV4B,sBAAYtB,QAAQmB,UAAR,CAAmBG,UAFrB;AAGVC,kBAAQvB,QAAQmB,UAAR,CAAmBI,MAHjB;AAIVC,qBAAWxB,QAAQmB,UAAR,CAAmBK,SAJpB;AAKVvB,iBAAOA;AALG,SAFQ;AASpBwB,kBAAUzB,QAAQyB;AATE,OAAtB;;AAYA,aAAO,KAAKd,SAAL,CAAe;AACpBlB,aAAK,KAAKA,GAAL,GAAW,cADI;AAEpBmB,gBAAQ,MAFY;AAGpBJ,cAAMY;AAHc,OAAf,EAIJP,IAJI,CAIC,kBAAU;AAChB,eAAOa,OAAOlB,IAAd;AACD,OANM,CAAP;AAOD;;;oCAEeP,K,EAAO;AACrB,UAAI0B,eAAe;AACfC,gBAAQ,KAAKrC,WAAL,CAAiB2B,OAAjB,CAAyBjB,KAAzB,EAAgC,IAAhC,EAAsC,OAAtC;AADO,OAAnB;;AAIA,aAAO,KAAKU,SAAL,CAAe;AACpBlB,aAAK,KAAKA,GAAL,GAAW,SADI;AAEpBe,cAAMmB,YAFc;AAGpBf,gBAAQ;AAHY,OAAf,EAIJC,IAJI,CAIC,KAAKgB,cAJN,CAAP;AAKD;;;mCAEcH,M,EAAQ;AACrB,aAAOI,iBAAEC,GAAF,CAAML,OAAOlB,IAAb,EAAmB,UAACwB,CAAD,EAAIC,CAAJ,EAAU;AAClC,YAAID,KAAKA,EAAEE,IAAP,IAAeF,EAAEG,KAArB,EAA4B;AAC1B,iBAAO,EAAED,MAAMF,EAAEE,IAAV,EAAgBC,OAAOH,EAAEG,KAAzB,EAAP;AACD,SAFD,MAEO,IAAIL,iBAAEM,QAAF,CAAWJ,CAAX,CAAJ,EAAmB;AACxB,iBAAO,EAAEE,MAAMF,CAAR,EAAWG,OAAOF,CAAlB,EAAP;AACD;AACD,eAAO,EAAEC,MAAMF,CAAR,EAAWG,OAAOH,CAAlB,EAAP;AACD,OAPM,CAAP;AAQD;;;8BAEShC,O,EAAS;AACjBA,cAAQJ,eAAR,GAA0B,KAAKA,eAA/B;AACAI,cAAQH,OAAR,GAAkB,KAAKA,OAAvB;;AAEA,aAAO,KAAKP,UAAL,CAAgB+C,iBAAhB,CAAkCrC,OAAlC,CAAP;AACD;;;yCAEoBA,O,EAAS;AAAA;;AAC5B;AACAA,cAAQG,OAAR,GAAkB2B,iBAAE1B,MAAF,CAASJ,QAAQG,OAAjB,EAA0B,kBAAU;AACpD,eAAOyB,OAAOA,MAAP,KAAkB,eAAzB;AACD,OAFiB,CAAlB;;AAIA,UAAIzB,UAAU2B,iBAAEC,GAAF,CAAM/B,QAAQG,OAAd,EAAuB,kBAAU;AAC7C,eAAO;AACLyB,kBAAQ,MAAKrC,WAAL,CAAiB2B,OAAjB,CAAyBU,OAAOA,MAAhC,EAAwC5B,QAAQsC,UAAhD,EAA4D,OAA5D,CADH;AAELC,iBAAOX,OAAOW,KAFT;AAGLjC,gBAAMsB,OAAOtB,IAHR;AAILd,gBAAMoC,OAAOpC,IAAP,IAAe;AAJhB,SAAP;AAMD,OAPa,CAAd;;AASAQ,cAAQG,OAAR,GAAkBA,OAAlB;;AAEA,aAAOH,OAAP;AACD;;;+BAEUA,O,EAAS;AAAA;;AAClB,aAAO,IAAIwC,OAAJ,CAAY,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACtC,eAAK/B,SAAL,CAAe;AACblB,eAAK,OAAKA,GAAL,GAAW,WADH;AAEbmB,kBAAQ,MAFK;AAGbJ,gBAAMR;AAHO,SAAf,EAIGa,IAJH,CAIQ,kBAAU;AAChB,iBAAO4B,QAAQf,OAAOlB,IAAf,CAAP;AACD,SAND;AAOD,OARM,CAAP;AASD;;;iCAEYR,O,EAAS;AAAA;;AACpB,aAAO,IAAIwC,OAAJ,CAAY,UAACC,OAAD,EAAUC,MAAV,EAAqB;AACtC,eAAK/B,SAAL,CAAe;AACblB,eAAK,OAAKA,GAAL,GAAW,aADH;AAEbmB,kBAAQ,MAFK;AAGbJ,gBAAMR;AAHO,SAAf,EAIGa,IAJH,CAIQ,kBAAU;AAChB,iBAAO4B,QAAQf,OAAOlB,IAAf,CAAP;AACD,SAND;AAOD,OARM,CAAP;AASD","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\n\nexport class GenericDatasource {\n\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\n this.type = instanceSettings.type;\n this.url = instanceSettings.url;\n this.name = instanceSettings.name;\n this.q = $q;\n this.backendSrv = backendSrv;\n this.templateSrv = templateSrv;\n this.withCredentials = instanceSettings.withCredentials;\n this.headers = {'Content-Type': 'application/json'};\n if (typeof instanceSettings.basicAuth === 'string' && instanceSettings.basicAuth.length > 0) {\n this.headers['Authorization'] = instanceSettings.basicAuth;\n }\n }\n\n query(options) {\n var query = this.buildQueryParameters(options);\n query.targets = query.targets.filter(t => !t.hide);\n\n if (query.targets.length <= 0) {\n return this.q.when({data: []});\n }\n\n if (this.templateSrv.getAdhocFilters) {\n query.adhocFilters = this.templateSrv.getAdhocFilters(this.name);\n } else {\n query.adhocFilters = [];\n }\n\n return this.doRequest({\n url: this.url + '/query',\n data: query,\n method: 'POST'\n });\n }\n\n testDatasource() {\n return this.doRequest({\n url: this.url + '/',\n method: 'GET',\n }).then(response => {\n if (response.status === 200) {\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\n }\n });\n }\n\n annotationQuery(options) {\n var query = this.templateSrv.replace(options.annotation.query, {}, 'glob');\n var annotationQuery = {\n range: options.range,\n annotation: {\n name: options.annotation.name,\n datasource: options.annotation.datasource,\n enable: options.annotation.enable,\n iconColor: options.annotation.iconColor,\n query: query\n },\n rangeRaw: options.rangeRaw\n };\n\n return this.doRequest({\n url: this.url + '/annotations',\n method: 'POST',\n data: annotationQuery\n }).then(result => {\n return result.data;\n });\n }\n\n metricFindQuery(query) {\n var interpolated = {\n target: this.templateSrv.replace(query, null, 'regex')\n };\n\n return this.doRequest({\n url: this.url + '/search',\n data: interpolated,\n method: 'POST',\n }).then(this.mapToTextValue);\n }\n\n mapToTextValue(result) {\n return _.map(result.data, (d, i) => {\n if (d && d.text && d.value) {\n return { text: d.text, value: d.value };\n } else if (_.isObject(d)) {\n return { text: d, value: i};\n }\n return { text: d, value: d };\n });\n }\n\n doRequest(options) {\n options.withCredentials = this.withCredentials;\n options.headers = this.headers;\n\n return this.backendSrv.datasourceRequest(options);\n }\n\n buildQueryParameters(options) {\n //remove placeholder targets\n options.targets = _.filter(options.targets, target => {\n return target.target !== 'select metric';\n });\n\n var targets = _.map(options.targets, target => {\n return {\n target: this.templateSrv.replace(target.target, options.scopedVars, 'regex'),\n refId: target.refId,\n hide: target.hide,\n type: target.type || 'timeserie'\n };\n });\n\n options.targets = targets;\n\n return options;\n }\n\n getTagKeys(options) {\n return new Promise((resolve, reject) => {\n this.doRequest({\n url: this.url + '/tag-keys',\n method: 'POST',\n data: options\n }).then(result => {\n return resolve(result.data);\n });\n });\n }\n\n getTagValues(options) {\n return new Promise((resolve, reject) => {\n this.doRequest({\n url: this.url + '/tag-values',\n method: 'POST',\n data: options\n }).then(result => {\n return resolve(result.data);\n });\n });\n }\n\n}\n"]} -------------------------------------------------------------------------------- /dist/img/simpleJson_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 634 | 635 | 636 | -------------------------------------------------------------------------------- /dist/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.AnnotationsQueryCtrl = exports.QueryOptionsCtrl = exports.ConfigCtrl = exports.QueryCtrl = exports.Datasource = undefined; 7 | 8 | var _datasource = require('./datasource'); 9 | 10 | var _query_ctrl = require('./query_ctrl'); 11 | 12 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 13 | 14 | var GenericConfigCtrl = function GenericConfigCtrl() { 15 | _classCallCheck(this, GenericConfigCtrl); 16 | }; 17 | 18 | GenericConfigCtrl.templateUrl = 'partials/config.html'; 19 | 20 | var GenericQueryOptionsCtrl = function GenericQueryOptionsCtrl() { 21 | _classCallCheck(this, GenericQueryOptionsCtrl); 22 | }; 23 | 24 | GenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html'; 25 | 26 | var GenericAnnotationsQueryCtrl = function GenericAnnotationsQueryCtrl() { 27 | _classCallCheck(this, GenericAnnotationsQueryCtrl); 28 | }; 29 | 30 | GenericAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'; 31 | 32 | exports.Datasource = _datasource.GenericDatasource; 33 | exports.QueryCtrl = _query_ctrl.GenericDatasourceQueryCtrl; 34 | exports.ConfigCtrl = GenericConfigCtrl; 35 | exports.QueryOptionsCtrl = GenericQueryOptionsCtrl; 36 | exports.AnnotationsQueryCtrl = GenericAnnotationsQueryCtrl; 37 | //# sourceMappingURL=module.js.map 38 | -------------------------------------------------------------------------------- /dist/module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/module.js"],"names":["GenericConfigCtrl","templateUrl","GenericQueryOptionsCtrl","GenericAnnotationsQueryCtrl","Datasource","GenericDatasource","QueryCtrl","GenericDatasourceQueryCtrl","ConfigCtrl","QueryOptionsCtrl","AnnotationsQueryCtrl"],"mappings":";;;;;;;AAAA;;AACA;;;;IAEMA,iB;;;;AACNA,kBAAkBC,WAAlB,GAAgC,sBAAhC;;IAEMC,uB;;;;AACNA,wBAAwBD,WAAxB,GAAsC,6BAAtC;;IAEME,2B;;;;AACNA,4BAA4BF,WAA5B,GAA0C,kCAA1C;;QAGuBG,U,GAArBC,6B;QAC8BC,S,GAA9BC,sC;QACqBC,U,GAArBR,iB;QAC2BS,gB,GAA3BP,uB;QAC+BQ,oB,GAA/BP,2B","file":"module.js","sourcesContent":["import {GenericDatasource} from './datasource';\nimport {GenericDatasourceQueryCtrl} from './query_ctrl';\n\nclass GenericConfigCtrl {}\nGenericConfigCtrl.templateUrl = 'partials/config.html';\n\nclass GenericQueryOptionsCtrl {}\nGenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\n\nclass GenericAnnotationsQueryCtrl {}\nGenericAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'\n\nexport {\n GenericDatasource as Datasource,\n GenericDatasourceQueryCtrl as QueryCtrl,\n GenericConfigCtrl as ConfigCtrl,\n GenericQueryOptionsCtrl as QueryOptionsCtrl,\n GenericAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]} -------------------------------------------------------------------------------- /dist/partials/annotations.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
Query
3 |
4 |
5 | 6 |
7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /dist/partials/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dist/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /dist/partials/query.options.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | -------------------------------------------------------------------------------- /dist/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SimpleJson", 3 | "id": "grafana-simple-json-datasource", 4 | "type": "datasource", 5 | 6 | "partials": { 7 | "config": "public/app/plugins/datasource/simplejson/partials/config.html" 8 | }, 9 | 10 | "metrics": true, 11 | "annotations": true, 12 | 13 | "info": { 14 | "description": "simple json datasource", 15 | "author": { 16 | "name": "Grafana Labs", 17 | "url": "https://grafana.com" 18 | }, 19 | "logos": { 20 | "small": "img/simpleJson_logo.svg", 21 | "large": "img/simpleJson_logo.svg" 22 | }, 23 | "links": [ 24 | {"name": "GitHub", "url": "https://github.com/grafana/simple-json-datasource"}, 25 | {"name": "MIT License", "url": "https://github.com/grafana/simple-json-datasource/blob/master/LICENSE"} 26 | ], 27 | "version": "1.4.3", 28 | "updated": "2024-01-15" 29 | }, 30 | 31 | "dependencies": { 32 | "grafanaVersion": "3.x.x", 33 | "plugins": [ ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /dist/query_ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.GenericDatasourceQueryCtrl = undefined; 7 | 8 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 9 | 10 | var _sdk = require('app/plugins/sdk'); 11 | 12 | require('./css/query-editor.css!'); 13 | 14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 15 | 16 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 17 | 18 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 19 | 20 | var GenericDatasourceQueryCtrl = exports.GenericDatasourceQueryCtrl = function (_QueryCtrl) { 21 | _inherits(GenericDatasourceQueryCtrl, _QueryCtrl); 22 | 23 | function GenericDatasourceQueryCtrl($scope, $injector) { 24 | _classCallCheck(this, GenericDatasourceQueryCtrl); 25 | 26 | var _this = _possibleConstructorReturn(this, (GenericDatasourceQueryCtrl.__proto__ || Object.getPrototypeOf(GenericDatasourceQueryCtrl)).call(this, $scope, $injector)); 27 | 28 | _this.scope = $scope; 29 | _this.target.target = _this.target.target || 'select metric'; 30 | _this.target.type = _this.target.type || 'timeserie'; 31 | return _this; 32 | } 33 | 34 | _createClass(GenericDatasourceQueryCtrl, [{ 35 | key: 'getOptions', 36 | value: function getOptions(query) { 37 | return this.datasource.metricFindQuery(query || ''); 38 | } 39 | }, { 40 | key: 'toggleEditorMode', 41 | value: function toggleEditorMode() { 42 | this.target.rawQuery = !this.target.rawQuery; 43 | } 44 | }, { 45 | key: 'onChangeInternal', 46 | value: function onChangeInternal() { 47 | this.panelCtrl.refresh(); // Asks the panel to refresh data. 48 | } 49 | }]); 50 | 51 | return GenericDatasourceQueryCtrl; 52 | }(_sdk.QueryCtrl); 53 | 54 | GenericDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html'; 55 | //# sourceMappingURL=query_ctrl.js.map 56 | -------------------------------------------------------------------------------- /dist/query_ctrl.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/query_ctrl.js"],"names":["GenericDatasourceQueryCtrl","$scope","$injector","scope","target","type","query","datasource","metricFindQuery","rawQuery","panelCtrl","refresh","QueryCtrl","templateUrl"],"mappings":";;;;;;;;;AAAA;;AACA;;;;;;;;IAEaA,0B,WAAAA,0B;;;AAEX,sCAAYC,MAAZ,EAAoBC,SAApB,EAAgC;AAAA;;AAAA,wJACxBD,MADwB,EAChBC,SADgB;;AAG9B,UAAKC,KAAL,GAAaF,MAAb;AACA,UAAKG,MAAL,CAAYA,MAAZ,GAAqB,MAAKA,MAAL,CAAYA,MAAZ,IAAsB,eAA3C;AACA,UAAKA,MAAL,CAAYC,IAAZ,GAAmB,MAAKD,MAAL,CAAYC,IAAZ,IAAoB,WAAvC;AAL8B;AAM/B;;;;+BAEUC,K,EAAO;AAChB,aAAO,KAAKC,UAAL,CAAgBC,eAAhB,CAAgCF,SAAS,EAAzC,CAAP;AACD;;;uCAEkB;AACjB,WAAKF,MAAL,CAAYK,QAAZ,GAAuB,CAAC,KAAKL,MAAL,CAAYK,QAApC;AACD;;;uCAEkB;AACjB,WAAKC,SAAL,CAAeC,OAAf,GADiB,CACS;AAC3B;;;;EApB6CC,c;;AAuBhDZ,2BAA2Ba,WAA3B,GAAyC,4BAAzC","file":"query_ctrl.js","sourcesContent":["import {QueryCtrl} from 'app/plugins/sdk';\nimport './css/query-editor.css!'\n\nexport class GenericDatasourceQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector) {\n super($scope, $injector);\n\n this.scope = $scope;\n this.target.target = this.target.target || 'select metric';\n this.target.type = this.target.type || 'timeserie';\n }\n\n getOptions(query) {\n return this.datasource.metricFindQuery(query || '');\n }\n\n toggleEditorMode() {\n this.target.rawQuery = !this.target.rawQuery;\n }\n\n onChangeInternal() {\n this.panelCtrl.refresh(); // Asks the panel to refresh data.\n }\n}\n\nGenericDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html';\n\n"]} -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | server: 5 | build: ./server 6 | container_name: server 7 | ports: 8 | - 3333:3333 9 | grafana: 10 | container_name: grafana-simple-json-datasource 11 | platform: linux/amd64 12 | image: grafana/grafana-enterprise:${GF_VERSION:-main} 13 | ports: 14 | - 3000:3000/tcp 15 | volumes: 16 | - ./provisioning/dashboards-actual/:/dashboards/ 17 | - ./provisioning:/etc/grafana/provisioning 18 | environment: 19 | - TERM=linux 20 | - GF_DEFAULT_APP_MODE=development 21 | - GF_AUTH_ANONYMOUS_ENABLED=true 22 | - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin 23 | - GF_ENTERPRISE_LICENSE_TEXT=$GF_ENTERPRISE_LICENSE_TEXT 24 | - GF_INSTALL_PLUGINS=yesoreyeram-infinity-datasource, grafana-simple-json-datasource 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grafana-simple-json", 3 | "private": true, 4 | "version": "1.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "build": "./node_modules/grunt-cli/bin/grunt", 9 | "test": "./node_modules/grunt-cli/bin/grunt mochaTest" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/grafana/simple-json-datasource.git" 14 | }, 15 | "author": "", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/grafana/simple-json-datasource/issues" 19 | }, 20 | "engineStrict": true, 21 | "devDependencies": { 22 | "babel": "^6.23.0", 23 | "babel-preset-env": "^1.7.0", 24 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 25 | "chai": "~3.5.0", 26 | "grunt": "^1.0.1", 27 | "grunt-babel": "~6.0.0", 28 | "grunt-cli": "^1.2.0", 29 | "grunt-contrib-clean": "^1.1.0", 30 | "grunt-contrib-copy": "^1.0.0", 31 | "grunt-contrib-uglify": "^2.3.0", 32 | "grunt-contrib-watch": "^1.0.0", 33 | "grunt-execute": "~0.2.2", 34 | "grunt-mocha-test": "^0.13.2", 35 | "grunt-systemjs-builder": "^1.0.0", 36 | "jsdom": "~9.12.0", 37 | "load-grunt-tasks": "^3.5.2", 38 | "mocha": "^3.2.0", 39 | "prunk": "^1.3.0", 40 | "q": "^1.5.0" 41 | }, 42 | "dependencies": { 43 | "lodash": "^4.17.4" 44 | }, 45 | "homepage": "https://github.com/grafana/simple-json-datasource#readme" 46 | } 47 | -------------------------------------------------------------------------------- /provisioning/dashboards-actual/migration.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_SIMPLE_JSON - FAKE SERVICE", 5 | "label": "Simple JSON - Fake service", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "grafana-simple-json-datasource", 9 | "pluginName": "SimpleJson" 10 | }, 11 | { 12 | "name": "DS_INFINITY_- FAKE SERVICE", 13 | "label": "Infinity - Fake service", 14 | "description": "", 15 | "type": "datasource", 16 | "pluginId": "yesoreyeram-infinity-datasource", 17 | "pluginName": "Infinity" 18 | } 19 | ], 20 | "__elements": {}, 21 | "__requires": [ 22 | { 23 | "type": "grafana", 24 | "id": "grafana", 25 | "name": "Grafana", 26 | "version": "10.3.0-64589" 27 | }, 28 | { 29 | "type": "datasource", 30 | "id": "grafana-simple-json-datasource", 31 | "name": "SimpleJson", 32 | "version": "1.4.2" 33 | }, 34 | { 35 | "type": "panel", 36 | "id": "table", 37 | "name": "Table", 38 | "version": "" 39 | }, 40 | { 41 | "type": "panel", 42 | "id": "timeseries", 43 | "name": "Time series", 44 | "version": "" 45 | }, 46 | { 47 | "type": "datasource", 48 | "id": "yesoreyeram-infinity-datasource", 49 | "name": "Infinity", 50 | "version": "2.3.1" 51 | } 52 | ], 53 | "annotations": { 54 | "list": [ 55 | { 56 | "builtIn": 1, 57 | "datasource": { 58 | "type": "grafana", 59 | "uid": "-- Grafana --" 60 | }, 61 | "enable": true, 62 | "hide": true, 63 | "iconColor": "rgba(0, 211, 255, 1)", 64 | "name": "Annotations & Alerts", 65 | "type": "dashboard" 66 | }, 67 | { 68 | "datasource": { 69 | "type": "grafana-simple-json-datasource", 70 | "uid": "simple-json" 71 | }, 72 | "enable": false, 73 | "iconColor": "red", 74 | "name": "Annotation using simple JSON", 75 | "query": "foo" 76 | }, 77 | { 78 | "datasource": { 79 | "type": "yesoreyeram-infinity-datasource", 80 | "uid": "infinity" 81 | }, 82 | "enable": false, 83 | "iconColor": "green", 84 | "mappings": { 85 | "time": { 86 | "source": "field", 87 | "value": "time" 88 | } 89 | }, 90 | "name": "Annotation using Infinity ( frontend parser )", 91 | "target": { 92 | "columns": [], 93 | "filters": [], 94 | "format": "table", 95 | "global_query_id": "", 96 | "refId": "Anno", 97 | "root_selector": "", 98 | "source": "url", 99 | "type": "json", 100 | "url": "/annotations", 101 | "url_options": { 102 | "data": "", 103 | "method": "GET" 104 | } 105 | } 106 | }, 107 | { 108 | "datasource": { 109 | "type": "yesoreyeram-infinity-datasource", 110 | "uid": "infinity" 111 | }, 112 | "enable": false, 113 | "iconColor": "blue", 114 | "name": "Annotation using Infinity ( backend parser )", 115 | "target": { 116 | "columns": [ 117 | { 118 | "selector": "time", 119 | "text": "", 120 | "type": "timestamp_epoch" 121 | }, 122 | { 123 | "selector": "title", 124 | "text": "", 125 | "type": "string" 126 | }, 127 | { 128 | "selector": "text", 129 | "text": "", 130 | "type": "string" 131 | }, 132 | { 133 | "selector": "tags", 134 | "text": "", 135 | "type": "string" 136 | } 137 | ], 138 | "filters": [], 139 | "format": "table", 140 | "global_query_id": "", 141 | "parser": "backend", 142 | "refId": "Anno", 143 | "root_selector": "", 144 | "source": "url", 145 | "type": "json", 146 | "url": "/annotations", 147 | "url_options": { 148 | "data": "", 149 | "method": "GET" 150 | } 151 | } 152 | } 153 | ] 154 | }, 155 | "editable": true, 156 | "fiscalYearStartMonth": 0, 157 | "graphTooltip": 0, 158 | "id": null, 159 | "links": [], 160 | "liveNow": false, 161 | "panels": [ 162 | { 163 | "collapsed": false, 164 | "gridPos": { 165 | "h": 1, 166 | "w": 24, 167 | "x": 0, 168 | "y": 0 169 | }, 170 | "id": 4, 171 | "panels": [], 172 | "title": "Single time series", 173 | "type": "row" 174 | }, 175 | { 176 | "datasource": { 177 | "type": "grafana-simple-json-datasource", 178 | "uid": "simple-json" 179 | }, 180 | "fieldConfig": { 181 | "defaults": { 182 | "color": { 183 | "mode": "palette-classic" 184 | }, 185 | "custom": { 186 | "axisBorderShow": false, 187 | "axisCenteredZero": false, 188 | "axisColorMode": "text", 189 | "axisLabel": "", 190 | "axisPlacement": "auto", 191 | "barAlignment": 0, 192 | "drawStyle": "line", 193 | "fillOpacity": 0, 194 | "gradientMode": "none", 195 | "hideFrom": { 196 | "legend": false, 197 | "tooltip": false, 198 | "viz": false 199 | }, 200 | "insertNulls": false, 201 | "lineInterpolation": "linear", 202 | "lineWidth": 1, 203 | "pointSize": 5, 204 | "scaleDistribution": { 205 | "type": "linear" 206 | }, 207 | "showPoints": "auto", 208 | "spanNulls": false, 209 | "stacking": { 210 | "group": "A", 211 | "mode": "none" 212 | }, 213 | "thresholdsStyle": { 214 | "mode": "off" 215 | } 216 | }, 217 | "mappings": [], 218 | "thresholds": { 219 | "mode": "absolute", 220 | "steps": [ 221 | { 222 | "color": "green", 223 | "value": null 224 | }, 225 | { 226 | "color": "red", 227 | "value": 80 228 | } 229 | ] 230 | } 231 | }, 232 | "overrides": [] 233 | }, 234 | "gridPos": { 235 | "h": 8, 236 | "w": 8, 237 | "x": 0, 238 | "y": 1 239 | }, 240 | "id": 1, 241 | "options": { 242 | "legend": { 243 | "calcs": [], 244 | "displayMode": "list", 245 | "placement": "bottom", 246 | "showLegend": true 247 | }, 248 | "tooltip": { 249 | "mode": "single", 250 | "sort": "none" 251 | } 252 | }, 253 | "targets": [ 254 | { 255 | "datasource": { 256 | "type": "grafana-simple-json-datasource", 257 | "uid": "simple-json" 258 | }, 259 | "refId": "A", 260 | "target": "upper_25", 261 | "type": "timeserie" 262 | } 263 | ], 264 | "title": "Single time series - ( Simple JSON datasource plugin )", 265 | "type": "timeseries" 266 | }, 267 | { 268 | "datasource": { 269 | "type": "yesoreyeram-infinity-datasource", 270 | "uid": "infinity" 271 | }, 272 | "fieldConfig": { 273 | "defaults": { 274 | "color": { 275 | "mode": "palette-classic" 276 | }, 277 | "custom": { 278 | "axisBorderShow": false, 279 | "axisCenteredZero": false, 280 | "axisColorMode": "text", 281 | "axisLabel": "", 282 | "axisPlacement": "auto", 283 | "barAlignment": 0, 284 | "drawStyle": "line", 285 | "fillOpacity": 0, 286 | "gradientMode": "none", 287 | "hideFrom": { 288 | "legend": false, 289 | "tooltip": false, 290 | "viz": false 291 | }, 292 | "insertNulls": false, 293 | "lineInterpolation": "linear", 294 | "lineWidth": 1, 295 | "pointSize": 5, 296 | "scaleDistribution": { 297 | "type": "linear" 298 | }, 299 | "showPoints": "auto", 300 | "spanNulls": false, 301 | "stacking": { 302 | "group": "A", 303 | "mode": "none" 304 | }, 305 | "thresholdsStyle": { 306 | "mode": "off" 307 | } 308 | }, 309 | "mappings": [], 310 | "thresholds": { 311 | "mode": "absolute", 312 | "steps": [ 313 | { 314 | "color": "green", 315 | "value": null 316 | }, 317 | { 318 | "color": "red", 319 | "value": 80 320 | } 321 | ] 322 | } 323 | }, 324 | "overrides": [] 325 | }, 326 | "gridPos": { 327 | "h": 8, 328 | "w": 8, 329 | "x": 8, 330 | "y": 1 331 | }, 332 | "id": 2, 333 | "options": { 334 | "legend": { 335 | "calcs": [], 336 | "displayMode": "list", 337 | "placement": "bottom", 338 | "showLegend": true 339 | }, 340 | "tooltip": { 341 | "mode": "single", 342 | "sort": "none" 343 | } 344 | }, 345 | "targets": [ 346 | { 347 | "columns": [], 348 | "datasource": { 349 | "type": "yesoreyeram-infinity-datasource", 350 | "uid": "infinity" 351 | }, 352 | "filters": [], 353 | "format": "as-is", 354 | "global_query_id": "", 355 | "refId": "A", 356 | "root_selector": "", 357 | "source": "url", 358 | "type": "json", 359 | "url": "/query", 360 | "url_options": { 361 | "body_content_type": "application/json", 362 | "body_type": "raw", 363 | "data": "{ \n \"targets\": [{ \"target\":\"upper_25\" }]\n}", 364 | "method": "POST" 365 | } 366 | } 367 | ], 368 | "title": "Single time series - ( Infinity plugin - frontend parser )", 369 | "type": "timeseries" 370 | }, 371 | { 372 | "datasource": { 373 | "type": "yesoreyeram-infinity-datasource", 374 | "uid": "infinity" 375 | }, 376 | "fieldConfig": { 377 | "defaults": { 378 | "color": { 379 | "mode": "palette-classic" 380 | }, 381 | "custom": { 382 | "axisBorderShow": false, 383 | "axisCenteredZero": false, 384 | "axisColorMode": "text", 385 | "axisLabel": "", 386 | "axisPlacement": "auto", 387 | "barAlignment": 0, 388 | "drawStyle": "line", 389 | "fillOpacity": 0, 390 | "gradientMode": "none", 391 | "hideFrom": { 392 | "legend": false, 393 | "tooltip": false, 394 | "viz": false 395 | }, 396 | "insertNulls": false, 397 | "lineInterpolation": "linear", 398 | "lineWidth": 1, 399 | "pointSize": 5, 400 | "scaleDistribution": { 401 | "type": "linear" 402 | }, 403 | "showPoints": "auto", 404 | "spanNulls": false, 405 | "stacking": { 406 | "group": "A", 407 | "mode": "none" 408 | }, 409 | "thresholdsStyle": { 410 | "mode": "off" 411 | } 412 | }, 413 | "mappings": [], 414 | "thresholds": { 415 | "mode": "absolute", 416 | "steps": [ 417 | { 418 | "color": "green", 419 | "value": null 420 | }, 421 | { 422 | "color": "red", 423 | "value": 80 424 | } 425 | ] 426 | } 427 | }, 428 | "overrides": [] 429 | }, 430 | "gridPos": { 431 | "h": 8, 432 | "w": 8, 433 | "x": 16, 434 | "y": 1 435 | }, 436 | "id": 7, 437 | "options": { 438 | "legend": { 439 | "calcs": [], 440 | "displayMode": "list", 441 | "placement": "bottom", 442 | "showLegend": true 443 | }, 444 | "tooltip": { 445 | "mode": "single", 446 | "sort": "none" 447 | } 448 | }, 449 | "targets": [ 450 | { 451 | "columns": [ 452 | { 453 | "selector": "0", 454 | "text": "upper_25", 455 | "type": "number" 456 | }, 457 | { 458 | "selector": "1", 459 | "text": "Time", 460 | "type": "timestamp_epoch" 461 | } 462 | ], 463 | "datasource": { 464 | "type": "yesoreyeram-infinity-datasource", 465 | "uid": "infinity" 466 | }, 467 | "filters": [], 468 | "format": "timeseries", 469 | "global_query_id": "", 470 | "parser": "backend", 471 | "refId": "A", 472 | "root_selector": "datapoints", 473 | "source": "url", 474 | "type": "json", 475 | "url": "/query", 476 | "url_options": { 477 | "body_content_type": "application/json", 478 | "body_type": "raw", 479 | "data": "{ \n \"targets\": [{ \"target\":\"upper_25\" }]\n}", 480 | "method": "POST" 481 | } 482 | } 483 | ], 484 | "title": "Single time series - ( Infinity plugin - backend parser )", 485 | "type": "timeseries" 486 | }, 487 | { 488 | "collapsed": false, 489 | "gridPos": { 490 | "h": 1, 491 | "w": 24, 492 | "x": 0, 493 | "y": 9 494 | }, 495 | "id": 5, 496 | "panels": [], 497 | "title": "Multiple time series", 498 | "type": "row" 499 | }, 500 | { 501 | "datasource": { 502 | "type": "grafana-simple-json-datasource", 503 | "uid": "simple-json" 504 | }, 505 | "fieldConfig": { 506 | "defaults": { 507 | "color": { 508 | "mode": "palette-classic" 509 | }, 510 | "custom": { 511 | "axisBorderShow": false, 512 | "axisCenteredZero": false, 513 | "axisColorMode": "text", 514 | "axisLabel": "", 515 | "axisPlacement": "auto", 516 | "barAlignment": 0, 517 | "drawStyle": "line", 518 | "fillOpacity": 0, 519 | "gradientMode": "none", 520 | "hideFrom": { 521 | "legend": false, 522 | "tooltip": false, 523 | "viz": false 524 | }, 525 | "insertNulls": false, 526 | "lineInterpolation": "linear", 527 | "lineWidth": 1, 528 | "pointSize": 5, 529 | "scaleDistribution": { 530 | "type": "linear" 531 | }, 532 | "showPoints": "auto", 533 | "spanNulls": false, 534 | "stacking": { 535 | "group": "A", 536 | "mode": "none" 537 | }, 538 | "thresholdsStyle": { 539 | "mode": "off" 540 | } 541 | }, 542 | "mappings": [], 543 | "thresholds": { 544 | "mode": "absolute", 545 | "steps": [ 546 | { 547 | "color": "green", 548 | "value": null 549 | }, 550 | { 551 | "color": "red", 552 | "value": 80 553 | } 554 | ] 555 | } 556 | }, 557 | "overrides": [] 558 | }, 559 | "gridPos": { 560 | "h": 8, 561 | "w": 8, 562 | "x": 0, 563 | "y": 10 564 | }, 565 | "id": 6, 566 | "options": { 567 | "legend": { 568 | "calcs": [], 569 | "displayMode": "list", 570 | "placement": "bottom", 571 | "showLegend": true 572 | }, 573 | "tooltip": { 574 | "mode": "single", 575 | "sort": "none" 576 | } 577 | }, 578 | "targets": [ 579 | { 580 | "datasource": { 581 | "type": "grafana-simple-json-datasource", 582 | "uid": "simple-json" 583 | }, 584 | "refId": "A", 585 | "target": "upper_25", 586 | "type": "timeserie" 587 | }, 588 | { 589 | "datasource": { 590 | "type": "grafana-simple-json-datasource", 591 | "uid": "simple-json" 592 | }, 593 | "hide": false, 594 | "refId": "B", 595 | "target": "upper_50", 596 | "type": "timeserie" 597 | } 598 | ], 599 | "title": "Multiple time series - ( Simple JSON datasource plugin )", 600 | "type": "timeseries" 601 | }, 602 | { 603 | "datasource": { 604 | "type": "yesoreyeram-infinity-datasource", 605 | "uid": "infinity" 606 | }, 607 | "fieldConfig": { 608 | "defaults": { 609 | "color": { 610 | "mode": "palette-classic" 611 | }, 612 | "custom": { 613 | "axisBorderShow": false, 614 | "axisCenteredZero": false, 615 | "axisColorMode": "text", 616 | "axisLabel": "", 617 | "axisPlacement": "auto", 618 | "barAlignment": 0, 619 | "drawStyle": "line", 620 | "fillOpacity": 0, 621 | "gradientMode": "none", 622 | "hideFrom": { 623 | "legend": false, 624 | "tooltip": false, 625 | "viz": false 626 | }, 627 | "insertNulls": false, 628 | "lineInterpolation": "linear", 629 | "lineWidth": 1, 630 | "pointSize": 5, 631 | "scaleDistribution": { 632 | "type": "linear" 633 | }, 634 | "showPoints": "auto", 635 | "spanNulls": false, 636 | "stacking": { 637 | "group": "A", 638 | "mode": "none" 639 | }, 640 | "thresholdsStyle": { 641 | "mode": "off" 642 | } 643 | }, 644 | "mappings": [], 645 | "thresholds": { 646 | "mode": "absolute", 647 | "steps": [ 648 | { 649 | "color": "green", 650 | "value": null 651 | }, 652 | { 653 | "color": "red", 654 | "value": 80 655 | } 656 | ] 657 | } 658 | }, 659 | "overrides": [] 660 | }, 661 | "gridPos": { 662 | "h": 8, 663 | "w": 8, 664 | "x": 8, 665 | "y": 10 666 | }, 667 | "id": 3, 668 | "options": { 669 | "legend": { 670 | "calcs": [], 671 | "displayMode": "list", 672 | "placement": "bottom", 673 | "showLegend": true 674 | }, 675 | "tooltip": { 676 | "mode": "single", 677 | "sort": "none" 678 | } 679 | }, 680 | "targets": [ 681 | { 682 | "columns": [], 683 | "datasource": { 684 | "type": "yesoreyeram-infinity-datasource", 685 | "uid": "infinity" 686 | }, 687 | "filters": [], 688 | "format": "as-is", 689 | "global_query_id": "", 690 | "parser": "simple", 691 | "refId": "A", 692 | "root_selector": "", 693 | "source": "url", 694 | "type": "json", 695 | "url": "/query", 696 | "url_options": { 697 | "body_content_type": "application/json", 698 | "body_type": "raw", 699 | "data": "{ \n \"targets\": [{ \"target\":\"upper_25\" }]\n}", 700 | "method": "POST" 701 | } 702 | }, 703 | { 704 | "columns": [], 705 | "datasource": { 706 | "type": "yesoreyeram-infinity-datasource", 707 | "uid": "infinity" 708 | }, 709 | "filters": [], 710 | "format": "as-is", 711 | "global_query_id": "", 712 | "hide": false, 713 | "parser": "simple", 714 | "refId": "B", 715 | "root_selector": "", 716 | "source": "url", 717 | "type": "json", 718 | "url": "/query", 719 | "url_options": { 720 | "body_content_type": "application/json", 721 | "body_type": "raw", 722 | "data": "{ \n \"targets\": [{ \"target\":\"upper_50\" }]\n}", 723 | "method": "POST" 724 | } 725 | } 726 | ], 727 | "title": "Multiple time series - ( Infinity plugin - frontend parser )", 728 | "type": "timeseries" 729 | }, 730 | { 731 | "datasource": { 732 | "type": "yesoreyeram-infinity-datasource", 733 | "uid": "infinity" 734 | }, 735 | "fieldConfig": { 736 | "defaults": { 737 | "color": { 738 | "mode": "palette-classic" 739 | }, 740 | "custom": { 741 | "axisBorderShow": false, 742 | "axisCenteredZero": false, 743 | "axisColorMode": "text", 744 | "axisLabel": "", 745 | "axisPlacement": "auto", 746 | "barAlignment": 0, 747 | "drawStyle": "line", 748 | "fillOpacity": 0, 749 | "gradientMode": "none", 750 | "hideFrom": { 751 | "legend": false, 752 | "tooltip": false, 753 | "viz": false 754 | }, 755 | "insertNulls": false, 756 | "lineInterpolation": "linear", 757 | "lineWidth": 1, 758 | "pointSize": 5, 759 | "scaleDistribution": { 760 | "type": "linear" 761 | }, 762 | "showPoints": "auto", 763 | "spanNulls": false, 764 | "stacking": { 765 | "group": "A", 766 | "mode": "none" 767 | }, 768 | "thresholdsStyle": { 769 | "mode": "off" 770 | } 771 | }, 772 | "mappings": [], 773 | "thresholds": { 774 | "mode": "absolute", 775 | "steps": [ 776 | { 777 | "color": "green", 778 | "value": null 779 | }, 780 | { 781 | "color": "red", 782 | "value": 80 783 | } 784 | ] 785 | } 786 | }, 787 | "overrides": [] 788 | }, 789 | "gridPos": { 790 | "h": 8, 791 | "w": 8, 792 | "x": 16, 793 | "y": 10 794 | }, 795 | "id": 8, 796 | "options": { 797 | "legend": { 798 | "calcs": [], 799 | "displayMode": "list", 800 | "placement": "bottom", 801 | "showLegend": true 802 | }, 803 | "tooltip": { 804 | "mode": "single", 805 | "sort": "none" 806 | } 807 | }, 808 | "targets": [ 809 | { 810 | "columns": [ 811 | { 812 | "selector": "0", 813 | "text": "upper_25", 814 | "type": "number" 815 | }, 816 | { 817 | "selector": "1", 818 | "text": "Time", 819 | "type": "timestamp_epoch" 820 | } 821 | ], 822 | "datasource": { 823 | "type": "yesoreyeram-infinity-datasource", 824 | "uid": "infinity" 825 | }, 826 | "filters": [], 827 | "format": "timeseries", 828 | "global_query_id": "", 829 | "parser": "backend", 830 | "refId": "A", 831 | "root_selector": "datapoints", 832 | "source": "url", 833 | "type": "json", 834 | "url": "/query", 835 | "url_options": { 836 | "body_content_type": "application/json", 837 | "body_type": "raw", 838 | "data": "{ \n \"targets\": [{ \"target\":\"upper_25\" }]\n}", 839 | "method": "POST" 840 | } 841 | }, 842 | { 843 | "columns": [ 844 | { 845 | "selector": "0", 846 | "text": "upper_50", 847 | "type": "number" 848 | }, 849 | { 850 | "selector": "1", 851 | "text": "Time", 852 | "type": "timestamp_epoch" 853 | } 854 | ], 855 | "datasource": { 856 | "type": "yesoreyeram-infinity-datasource", 857 | "uid": "infinity" 858 | }, 859 | "filters": [], 860 | "format": "timeseries", 861 | "global_query_id": "", 862 | "hide": false, 863 | "parser": "backend", 864 | "refId": "B", 865 | "root_selector": "datapoints", 866 | "source": "url", 867 | "type": "json", 868 | "url": "/query", 869 | "url_options": { 870 | "body_content_type": "application/json", 871 | "body_type": "raw", 872 | "data": "{ \n \"targets\": [{ \"target\":\"upper_50\" }]\n}", 873 | "method": "POST" 874 | } 875 | } 876 | ], 877 | "title": "Single time series - ( Infinity plugin - backend parser )", 878 | "type": "timeseries" 879 | }, 880 | { 881 | "collapsed": false, 882 | "gridPos": { 883 | "h": 1, 884 | "w": 24, 885 | "x": 0, 886 | "y": 18 887 | }, 888 | "id": 9, 889 | "panels": [], 890 | "title": "Table", 891 | "type": "row" 892 | }, 893 | { 894 | "datasource": { 895 | "type": "grafana-simple-json-datasource", 896 | "uid": "simple-json" 897 | }, 898 | "fieldConfig": { 899 | "defaults": { 900 | "color": { 901 | "mode": "thresholds" 902 | }, 903 | "custom": { 904 | "align": "auto", 905 | "cellOptions": { 906 | "type": "auto" 907 | }, 908 | "inspect": false 909 | }, 910 | "mappings": [], 911 | "thresholds": { 912 | "mode": "absolute", 913 | "steps": [ 914 | { 915 | "color": "green", 916 | "value": null 917 | }, 918 | { 919 | "color": "red", 920 | "value": 80 921 | } 922 | ] 923 | } 924 | }, 925 | "overrides": [] 926 | }, 927 | "gridPos": { 928 | "h": 6, 929 | "w": 8, 930 | "x": 0, 931 | "y": 19 932 | }, 933 | "id": 10, 934 | "options": { 935 | "cellHeight": "sm", 936 | "footer": { 937 | "countRows": false, 938 | "fields": "", 939 | "reducer": ["sum"], 940 | "show": false 941 | }, 942 | "showHeader": true 943 | }, 944 | "pluginVersion": "10.3.0-64589", 945 | "targets": [ 946 | { 947 | "datasource": { 948 | "type": "grafana-simple-json-datasource", 949 | "uid": "simple-json" 950 | }, 951 | "refId": "A", 952 | "target": "upper_25", 953 | "type": "table" 954 | } 955 | ], 956 | "title": "Table query - ( Simple JSON datasource plugin )", 957 | "type": "table" 958 | }, 959 | { 960 | "datasource": { 961 | "type": "yesoreyeram-infinity-datasource", 962 | "uid": "infinity" 963 | }, 964 | "fieldConfig": { 965 | "defaults": { 966 | "color": { 967 | "mode": "thresholds" 968 | }, 969 | "custom": { 970 | "align": "auto", 971 | "cellOptions": { 972 | "type": "auto" 973 | }, 974 | "inspect": false 975 | }, 976 | "mappings": [], 977 | "thresholds": { 978 | "mode": "absolute", 979 | "steps": [ 980 | { 981 | "color": "green", 982 | "value": null 983 | }, 984 | { 985 | "color": "red", 986 | "value": 80 987 | } 988 | ] 989 | } 990 | }, 991 | "overrides": [] 992 | }, 993 | "gridPos": { 994 | "h": 6, 995 | "w": 8, 996 | "x": 8, 997 | "y": 19 998 | }, 999 | "id": 11, 1000 | "options": { 1001 | "cellHeight": "sm", 1002 | "footer": { 1003 | "countRows": false, 1004 | "fields": "", 1005 | "reducer": ["sum"], 1006 | "show": false 1007 | }, 1008 | "showHeader": true 1009 | }, 1010 | "pluginVersion": "10.3.0-64589", 1011 | "targets": [ 1012 | { 1013 | "columns": [], 1014 | "datasource": { 1015 | "type": "yesoreyeram-infinity-datasource", 1016 | "uid": "infinity" 1017 | }, 1018 | "filters": [], 1019 | "format": "as-is", 1020 | "global_query_id": "", 1021 | "refId": "A", 1022 | "root_selector": "", 1023 | "source": "url", 1024 | "type": "json", 1025 | "url": "/query", 1026 | "url_options": { 1027 | "body_content_type": "application/json", 1028 | "body_type": "raw", 1029 | "data": "{ \n \"targets\": [{ \"type\":\"table\" }]\n}", 1030 | "method": "POST" 1031 | } 1032 | } 1033 | ], 1034 | "title": "Table query - ( Infinity plugin - frontend parser )", 1035 | "type": "table" 1036 | }, 1037 | { 1038 | "datasource": { 1039 | "type": "yesoreyeram-infinity-datasource", 1040 | "uid": "infinity" 1041 | }, 1042 | "fieldConfig": { 1043 | "defaults": { 1044 | "color": { 1045 | "mode": "thresholds" 1046 | }, 1047 | "custom": { 1048 | "align": "auto", 1049 | "cellOptions": { 1050 | "type": "auto" 1051 | }, 1052 | "inspect": false 1053 | }, 1054 | "mappings": [], 1055 | "thresholds": { 1056 | "mode": "absolute", 1057 | "steps": [ 1058 | { 1059 | "color": "green", 1060 | "value": null 1061 | }, 1062 | { 1063 | "color": "red", 1064 | "value": 80 1065 | } 1066 | ] 1067 | } 1068 | }, 1069 | "overrides": [] 1070 | }, 1071 | "gridPos": { 1072 | "h": 6, 1073 | "w": 8, 1074 | "x": 16, 1075 | "y": 19 1076 | }, 1077 | "id": 12, 1078 | "options": { 1079 | "cellHeight": "sm", 1080 | "footer": { 1081 | "countRows": false, 1082 | "fields": "", 1083 | "reducer": ["sum"], 1084 | "show": false 1085 | }, 1086 | "showHeader": true 1087 | }, 1088 | "pluginVersion": "10.3.0-64589", 1089 | "targets": [ 1090 | { 1091 | "columns": [ 1092 | { 1093 | "selector": "0", 1094 | "text": "Time", 1095 | "type": "timestamp_epoch" 1096 | }, 1097 | { 1098 | "selector": "1", 1099 | "text": "Country", 1100 | "type": "string" 1101 | }, 1102 | { 1103 | "selector": "2", 1104 | "text": "Number", 1105 | "type": "number" 1106 | } 1107 | ], 1108 | "datasource": { 1109 | "type": "yesoreyeram-infinity-datasource", 1110 | "uid": "infinity" 1111 | }, 1112 | "filters": [], 1113 | "format": "as-is", 1114 | "global_query_id": "", 1115 | "parser": "backend", 1116 | "refId": "A", 1117 | "root_selector": "rows", 1118 | "source": "url", 1119 | "type": "json", 1120 | "url": "/query", 1121 | "url_options": { 1122 | "body_content_type": "application/json", 1123 | "body_type": "raw", 1124 | "data": "{ \n \"targets\": [{ \"type\":\"table\" }]\n}", 1125 | "method": "POST" 1126 | } 1127 | } 1128 | ], 1129 | "title": "Table query - ( Infinity plugin - backend parser )", 1130 | "type": "table" 1131 | } 1132 | ], 1133 | "refresh": "", 1134 | "schemaVersion": 39, 1135 | "tags": [], 1136 | "templating": { 1137 | "list": [] 1138 | }, 1139 | "time": { 1140 | "from": "now-6h", 1141 | "to": "now" 1142 | }, 1143 | "timepicker": {}, 1144 | "timezone": "", 1145 | "title": "Simple JSON plugin to Infinity plugin migration", 1146 | "uid": "migration", 1147 | "version": 2, 1148 | "weekStart": "" 1149 | } 1150 | -------------------------------------------------------------------------------- /provisioning/dashboards/default.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: Default Dashboards 5 | type: file 6 | options: 7 | path: /dashboards 8 | -------------------------------------------------------------------------------- /provisioning/datasources/default.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | datasources: 3 | - name: Simple JSON - Fake service 4 | type: grafana-simple-json-datasource 5 | uid: simple-json 6 | url: http://server:3333 7 | access: proxy 8 | isDefault: true 9 | - name: Infinity - Fake service 10 | type: yesoreyeram-infinity-datasource 11 | uid: infinity 12 | url: http://server:3333 13 | -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:18 2 | 3 | WORKDIR /app 4 | 5 | RUN git clone https://github.com/bergquist/fake-simple-json-datasource && cd fake-simple-json-datasource && yarn install 6 | 7 | WORKDIR /app/fake-simple-json-datasource 8 | 9 | CMD ["node","./index.js"] -------------------------------------------------------------------------------- /spec/datasource_spec.js: -------------------------------------------------------------------------------- 1 | import {Datasource} from "../module"; 2 | import Q from "q"; 3 | 4 | describe('GenericDatasource', function() { 5 | var ctx = {}; 6 | 7 | beforeEach(function() { 8 | ctx.$q = Q; 9 | ctx.backendSrv = {}; 10 | ctx.templateSrv = {}; 11 | ctx.ds = new Datasource({}, ctx.$q, ctx.backendSrv, ctx.templateSrv); 12 | }); 13 | 14 | it('should return an empty array when no targets are set', function(done) { 15 | ctx.ds.query({targets: []}).then(function(result) { 16 | expect(result.data).to.have.length(0); 17 | done(); 18 | }); 19 | }); 20 | 21 | it('should return the server results when a target is set', function(done) { 22 | ctx.backendSrv.datasourceRequest = function(request) { 23 | return ctx.$q.when({ 24 | _request: request, 25 | data: [ 26 | { 27 | target: 'X', 28 | datapoints: [1, 2, 3] 29 | } 30 | ] 31 | }); 32 | }; 33 | 34 | ctx.templateSrv.replace = function(data) { 35 | return data; 36 | } 37 | 38 | ctx.ds.query({targets: ['hits']}).then(function(result) { 39 | expect(result._request.data.targets).to.have.length(1); 40 | 41 | var series = result.data[0]; 42 | expect(series.target).to.equal('X'); 43 | expect(series.datapoints).to.have.length(3); 44 | done(); 45 | }); 46 | }); 47 | 48 | it ('should return the metric results when a target is null', function(done) { 49 | ctx.backendSrv.datasourceRequest = function(request) { 50 | return ctx.$q.when({ 51 | _request: request, 52 | data: [ 53 | "metric_0", 54 | "metric_1", 55 | "metric_2", 56 | ] 57 | }); 58 | }; 59 | 60 | ctx.templateSrv.replace = function(data) { 61 | return data; 62 | } 63 | 64 | ctx.ds.metricFindQuery({target: null}).then(function(result) { 65 | expect(result).to.have.length(3); 66 | expect(result[0].text).to.equal('metric_0'); 67 | expect(result[0].value).to.equal('metric_0'); 68 | expect(result[1].text).to.equal('metric_1'); 69 | expect(result[1].value).to.equal('metric_1'); 70 | expect(result[2].text).to.equal('metric_2'); 71 | expect(result[2].value).to.equal('metric_2'); 72 | done(); 73 | }); 74 | }); 75 | 76 | it ('should return the metric target results when a target is set', function(done) { 77 | ctx.backendSrv.datasourceRequest = function(request) { 78 | var target = request.data.target; 79 | var result = [target + "_0", target + "_1", target + "_2"]; 80 | 81 | return ctx.$q.when({ 82 | _request: request, 83 | data: result 84 | }); 85 | }; 86 | 87 | ctx.templateSrv.replace = function(data) { 88 | return data; 89 | } 90 | 91 | ctx.ds.metricFindQuery('search').then(function(result) { 92 | expect(result).to.have.length(3); 93 | expect(result[0].text).to.equal('search_0'); 94 | expect(result[0].value).to.equal('search_0'); 95 | expect(result[1].text).to.equal('search_1'); 96 | expect(result[1].value).to.equal('search_1'); 97 | expect(result[2].text).to.equal('search_2'); 98 | expect(result[2].value).to.equal('search_2'); 99 | done(); 100 | }); 101 | }); 102 | 103 | it ('should return the metric results when the target is an empty string', function(done) { 104 | ctx.backendSrv.datasourceRequest = function(request) { 105 | return ctx.$q.when({ 106 | _request: request, 107 | data: [ 108 | "metric_0", 109 | "metric_1", 110 | "metric_2", 111 | ] 112 | }); 113 | }; 114 | 115 | ctx.templateSrv.replace = function(data) { 116 | return data; 117 | } 118 | 119 | ctx.ds.metricFindQuery('').then(function(result) { 120 | expect(result).to.have.length(3); 121 | expect(result[0].text).to.equal('metric_0'); 122 | expect(result[0].value).to.equal('metric_0'); 123 | expect(result[1].text).to.equal('metric_1'); 124 | expect(result[1].value).to.equal('metric_1'); 125 | expect(result[2].text).to.equal('metric_2'); 126 | expect(result[2].value).to.equal('metric_2'); 127 | done(); 128 | }); 129 | }); 130 | 131 | it ('should return the metric results when the args are an empty object', function(done) { 132 | ctx.backendSrv.datasourceRequest = function(request) { 133 | return ctx.$q.when({ 134 | _request: request, 135 | data: [ 136 | "metric_0", 137 | "metric_1", 138 | "metric_2", 139 | ] 140 | }); 141 | }; 142 | 143 | ctx.templateSrv.replace = function(data) { 144 | return data; 145 | } 146 | 147 | ctx.ds.metricFindQuery().then(function(result) { 148 | expect(result).to.have.length(3); 149 | expect(result[0].text).to.equal('metric_0'); 150 | expect(result[0].value).to.equal('metric_0'); 151 | expect(result[1].text).to.equal('metric_1'); 152 | expect(result[1].value).to.equal('metric_1'); 153 | expect(result[2].text).to.equal('metric_2'); 154 | expect(result[2].value).to.equal('metric_2'); 155 | done(); 156 | }); 157 | }); 158 | 159 | it ('should return the metric target results when the args are a string', function(done) { 160 | ctx.backendSrv.datasourceRequest = function(request) { 161 | var target = request.data.target; 162 | var result = [target + "_0", target + "_1", target + "_2"]; 163 | 164 | return ctx.$q.when({ 165 | _request: request, 166 | data: result 167 | }); 168 | }; 169 | 170 | ctx.templateSrv.replace = function(data) { 171 | return data; 172 | } 173 | 174 | ctx.ds.metricFindQuery('search').then(function(result) { 175 | expect(result).to.have.length(3); 176 | expect(result[0].text).to.equal('search_0'); 177 | expect(result[0].value).to.equal('search_0'); 178 | expect(result[1].text).to.equal('search_1'); 179 | expect(result[1].value).to.equal('search_1'); 180 | expect(result[2].text).to.equal('search_2'); 181 | expect(result[2].value).to.equal('search_2'); 182 | done(); 183 | }); 184 | }); 185 | 186 | it ('should return data as text and as value', function(done) { 187 | var result = ctx.ds.mapToTextValue({data: ["zero", "one", "two"]}); 188 | 189 | expect(result).to.have.length(3); 190 | expect(result[0].text).to.equal('zero'); 191 | expect(result[0].value).to.equal('zero'); 192 | expect(result[1].text).to.equal('one'); 193 | expect(result[1].value).to.equal('one'); 194 | expect(result[2].text).to.equal('two'); 195 | expect(result[2].value).to.equal('two'); 196 | done(); 197 | }); 198 | 199 | it ('should return text as text and value as value', function(done) { 200 | var data = [ 201 | {text: "zero", value: "value_0"}, 202 | {text: "one", value: "value_1"}, 203 | {text: "two", value: "value_2"}, 204 | ]; 205 | 206 | var result = ctx.ds.mapToTextValue({data: data}); 207 | 208 | expect(result).to.have.length(3); 209 | expect(result[0].text).to.equal('zero'); 210 | expect(result[0].value).to.equal('value_0'); 211 | expect(result[1].text).to.equal('one'); 212 | expect(result[1].value).to.equal('value_1'); 213 | expect(result[2].text).to.equal('two'); 214 | expect(result[2].value).to.equal('value_2'); 215 | done(); 216 | }); 217 | 218 | it ('should return data as text and index as value', function(done) { 219 | var data = [ 220 | {a: "zero", b: "value_0"}, 221 | {a: "one", b: "value_1"}, 222 | {a: "two", b: "value_2"}, 223 | ]; 224 | 225 | var result = ctx.ds.mapToTextValue({data: data}); 226 | 227 | expect(result).to.have.length(3); 228 | expect(result[0].text).to.equal(data[0]); 229 | expect(result[0].value).to.equal(0); 230 | expect(result[1].text).to.equal(data[1]); 231 | expect(result[1].value).to.equal(1); 232 | expect(result[2].text).to.equal(data[2]); 233 | expect(result[2].value).to.equal(2); 234 | done(); 235 | }); 236 | 237 | it('should support tag keys', function(done) { 238 | var data = [{'type': 'string', 'text': 'One', 'key': 'one'}, {'type': 'string', 'text': 'two', 'key': 'Two'}]; 239 | 240 | ctx.backendSrv.datasourceRequest = function(request) { 241 | return ctx.$q.when({ 242 | _request: request, 243 | data: data 244 | }); 245 | }; 246 | 247 | ctx.ds.getTagKeys().then(function(result) { 248 | expect(result).to.have.length(2); 249 | expect(result[0].type).to.equal(data[0].type); 250 | expect(result[0].text).to.equal(data[0].text); 251 | expect(result[0].key).to.equal(data[0].key); 252 | expect(result[1].type).to.equal(data[1].type); 253 | expect(result[1].text).to.equal(data[1].text); 254 | expect(result[1].key).to.equal(data[1].key); 255 | done(); 256 | }); 257 | }); 258 | 259 | it('should support tag values', function(done) { 260 | var data = [{'key': 'eins', 'text': 'Eins!'}, {'key': 'zwei', 'text': 'Zwei'}, {'key': 'drei', 'text': 'Drei!'}]; 261 | 262 | ctx.backendSrv.datasourceRequest = function(request) { 263 | return ctx.$q.when({ 264 | _request: request, 265 | data: data 266 | }); 267 | }; 268 | 269 | ctx.ds.getTagValues().then(function(result) { 270 | expect(result).to.have.length(3); 271 | expect(result[0].text).to.equal(data[0].text); 272 | expect(result[0].key).to.equal(data[0].key); 273 | expect(result[1].text).to.equal(data[1].text); 274 | expect(result[1].key).to.equal(data[1].key); 275 | expect(result[2].text).to.equal(data[2].text); 276 | expect(result[2].key).to.equal(data[2].key); 277 | done(); 278 | }); 279 | }); 280 | 281 | }); 282 | -------------------------------------------------------------------------------- /spec/test-main.js: -------------------------------------------------------------------------------- 1 | import prunk from 'prunk'; 2 | import {jsdom} from 'jsdom'; 3 | import chai from 'chai'; 4 | 5 | // Mock Grafana modules that are not available outside of the core project 6 | // Required for loading module.js 7 | prunk.mock('./css/query-editor.css!', 'no css, dude.'); 8 | prunk.mock('app/plugins/sdk', { 9 | QueryCtrl: null 10 | }); 11 | 12 | // Setup jsdom 13 | // Required for loading angularjs 14 | global.document = jsdom(''); 15 | global.window = global.document.parentWindow; 16 | 17 | // Setup Chai 18 | chai.should(); 19 | global.assert = chai.assert; 20 | global.expect = chai.expect; 21 | -------------------------------------------------------------------------------- /src/css/query-editor.css: -------------------------------------------------------------------------------- 1 | .generic-datasource-query-row .query-keyword { 2 | width: 75px; 3 | } -------------------------------------------------------------------------------- /src/datasource.js: -------------------------------------------------------------------------------- 1 | import _ from "lodash"; 2 | 3 | export class GenericDatasource { 4 | 5 | constructor(instanceSettings, $q, backendSrv, templateSrv) { 6 | this.type = instanceSettings.type; 7 | this.url = instanceSettings.url; 8 | this.name = instanceSettings.name; 9 | this.q = $q; 10 | this.backendSrv = backendSrv; 11 | this.templateSrv = templateSrv; 12 | this.withCredentials = instanceSettings.withCredentials; 13 | this.headers = {'Content-Type': 'application/json'}; 14 | if (typeof instanceSettings.basicAuth === 'string' && instanceSettings.basicAuth.length > 0) { 15 | this.headers['Authorization'] = instanceSettings.basicAuth; 16 | } 17 | } 18 | 19 | query(options) { 20 | var query = this.buildQueryParameters(options); 21 | query.targets = query.targets.filter(t => !t.hide); 22 | 23 | if (query.targets.length <= 0) { 24 | return this.q.when({data: []}); 25 | } 26 | 27 | if (this.templateSrv.getAdhocFilters) { 28 | query.adhocFilters = this.templateSrv.getAdhocFilters(this.name); 29 | } else { 30 | query.adhocFilters = []; 31 | } 32 | 33 | return this.doRequest({ 34 | url: this.url + '/query', 35 | data: query, 36 | method: 'POST' 37 | }); 38 | } 39 | 40 | testDatasource() { 41 | return this.doRequest({ 42 | url: this.url + '/', 43 | method: 'GET', 44 | }).then(response => { 45 | if (response.status === 200) { 46 | return { status: "success", message: "Data source is working", title: "Success" }; 47 | } 48 | }); 49 | } 50 | 51 | annotationQuery(options) { 52 | var query = this.templateSrv.replace(options.annotation.query, {}, 'glob'); 53 | var annotationQuery = { 54 | range: options.range, 55 | annotation: { 56 | name: options.annotation.name, 57 | datasource: options.annotation.datasource, 58 | enable: options.annotation.enable, 59 | iconColor: options.annotation.iconColor, 60 | query: query 61 | }, 62 | rangeRaw: options.rangeRaw 63 | }; 64 | 65 | return this.doRequest({ 66 | url: this.url + '/annotations', 67 | method: 'POST', 68 | data: annotationQuery 69 | }).then(result => { 70 | return result.data; 71 | }); 72 | } 73 | 74 | metricFindQuery(query) { 75 | var interpolated = { 76 | target: this.templateSrv.replace(query, null, 'regex') 77 | }; 78 | 79 | return this.doRequest({ 80 | url: this.url + '/search', 81 | data: interpolated, 82 | method: 'POST', 83 | }).then(this.mapToTextValue); 84 | } 85 | 86 | mapToTextValue(result) { 87 | return _.map(result.data, (d, i) => { 88 | if (d && d.text && d.value) { 89 | return { text: d.text, value: d.value }; 90 | } else if (_.isObject(d)) { 91 | return { text: d, value: i}; 92 | } 93 | return { text: d, value: d }; 94 | }); 95 | } 96 | 97 | doRequest(options) { 98 | options.withCredentials = this.withCredentials; 99 | options.headers = this.headers; 100 | 101 | return this.backendSrv.datasourceRequest(options); 102 | } 103 | 104 | buildQueryParameters(options) { 105 | //remove placeholder targets 106 | options.targets = _.filter(options.targets, target => { 107 | return target.target !== 'select metric'; 108 | }); 109 | 110 | var targets = _.map(options.targets, target => { 111 | return { 112 | target: this.templateSrv.replace(target.target, options.scopedVars, 'regex'), 113 | refId: target.refId, 114 | hide: target.hide, 115 | type: target.type || 'timeserie' 116 | }; 117 | }); 118 | 119 | options.targets = targets; 120 | 121 | return options; 122 | } 123 | 124 | getTagKeys(options) { 125 | return new Promise((resolve, reject) => { 126 | this.doRequest({ 127 | url: this.url + '/tag-keys', 128 | method: 'POST', 129 | data: options 130 | }).then(result => { 131 | return resolve(result.data); 132 | }); 133 | }); 134 | } 135 | 136 | getTagValues(options) { 137 | return new Promise((resolve, reject) => { 138 | this.doRequest({ 139 | url: this.url + '/tag-values', 140 | method: 'POST', 141 | data: options 142 | }).then(result => { 143 | return resolve(result.data); 144 | }); 145 | }); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/img/simpleJson_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 634 | 635 | 636 | -------------------------------------------------------------------------------- /src/module.js: -------------------------------------------------------------------------------- 1 | import {GenericDatasource} from './datasource'; 2 | import {GenericDatasourceQueryCtrl} from './query_ctrl'; 3 | 4 | class GenericConfigCtrl {} 5 | GenericConfigCtrl.templateUrl = 'partials/config.html'; 6 | 7 | class GenericQueryOptionsCtrl {} 8 | GenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html'; 9 | 10 | class GenericAnnotationsQueryCtrl {} 11 | GenericAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html' 12 | 13 | export { 14 | GenericDatasource as Datasource, 15 | GenericDatasourceQueryCtrl as QueryCtrl, 16 | GenericConfigCtrl as ConfigCtrl, 17 | GenericQueryOptionsCtrl as QueryOptionsCtrl, 18 | GenericAnnotationsQueryCtrl as AnnotationsQueryCtrl 19 | }; 20 | -------------------------------------------------------------------------------- /src/partials/annotations.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
Query
3 |
4 |
5 | 6 |
7 |
8 | 9 | 10 | -------------------------------------------------------------------------------- /src/partials/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | -------------------------------------------------------------------------------- /src/partials/query.options.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | -------------------------------------------------------------------------------- /src/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SimpleJson", 3 | "id": "grafana-simple-json-datasource", 4 | "type": "datasource", 5 | 6 | "partials": { 7 | "config": "public/app/plugins/datasource/simplejson/partials/config.html" 8 | }, 9 | 10 | "metrics": true, 11 | "annotations": true, 12 | 13 | "info": { 14 | "description": "simple json datasource", 15 | "author": { 16 | "name": "Grafana Labs", 17 | "url": "https://grafana.com" 18 | }, 19 | "logos": { 20 | "small": "img/simpleJson_logo.svg", 21 | "large": "img/simpleJson_logo.svg" 22 | }, 23 | "links": [ 24 | {"name": "GitHub", "url": "https://github.com/grafana/simple-json-datasource"}, 25 | {"name": "MIT License", "url": "https://github.com/grafana/simple-json-datasource/blob/master/LICENSE"} 26 | ], 27 | "version": "1.4.3", 28 | "updated": "2024-01-15" 29 | }, 30 | 31 | "dependencies": { 32 | "grafanaVersion": "3.x.x", 33 | "plugins": [ ] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/query_ctrl.js: -------------------------------------------------------------------------------- 1 | import {QueryCtrl} from 'app/plugins/sdk'; 2 | import './css/query-editor.css!' 3 | 4 | export class GenericDatasourceQueryCtrl extends QueryCtrl { 5 | 6 | constructor($scope, $injector) { 7 | super($scope, $injector); 8 | 9 | this.scope = $scope; 10 | this.target.target = this.target.target || 'select metric'; 11 | this.target.type = this.target.type || 'timeserie'; 12 | } 13 | 14 | getOptions(query) { 15 | return this.datasource.metricFindQuery(query || ''); 16 | } 17 | 18 | toggleEditorMode() { 19 | this.target.rawQuery = !this.target.rawQuery; 20 | } 21 | 22 | onChangeInternal() { 23 | this.panelCtrl.refresh(); // Asks the panel to refresh data. 24 | } 25 | } 26 | 27 | GenericDatasourceQueryCtrl.templateUrl = 'partials/query.editor.html'; 28 | 29 | --------------------------------------------------------------------------------