├── .gitignore ├── .jscs.json ├── Gruntfile.js ├── LICENSE ├── README.md ├── dist ├── README.md ├── css │ └── query-editor.css ├── datasource.js ├── datasource.js.map ├── img │ ├── logo_large.png │ └── logo_small.png ├── 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 └── serverside │ ├── drilldriver.js │ ├── mssqldriver.js │ └── sqlproxyserver.js ├── overview.png ├── package.json ├── query_editor.png ├── spec ├── datasource_spec.js ├── sqlproxyserver_spec.js └── test-main.js └── src ├── css └── query-editor.css ├── datasource.js ├── img ├── logo_large.png └── logo_small.png ├── module.js ├── partials ├── annotations.editor.html ├── config.html ├── query.editor.html └── query.options.html ├── plugin.json ├── query_ctrl.js └── serverside ├── drilldriver.js ├── mssqldriver.js ├── sqlproxy.service └── sqlproxyserver.js /.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 | deploy.bat 39 | .vscode/ 40 | -------------------------------------------------------------------------------- /.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','./bin/*','./serverside/*'], 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: ['es2015'] 38 | }, 39 | dist: { 40 | options: { 41 | plugins: ['transform-es2015-modules-systemjs', 'transform-es2015-for-of'] 42 | }, 43 | files: [{ 44 | cwd: 'src', 45 | expand: true, 46 | src: ['**/*.js','!**/server.js','!serverside/*'], 47 | dest: 'dist', 48 | ext:'.js' 49 | }] 50 | }, 51 | distTestNoSystemJs: { 52 | files: [{ 53 | cwd: 'src', 54 | expand: true, 55 | src: ['**/*.js'], 56 | dest: 'dist/test', 57 | ext:'.js' 58 | }] 59 | }, 60 | distTestsSpecsNoSystemJs: { 61 | files: [{ 62 | expand: true, 63 | cwd: 'spec', 64 | src: ['**/*.js'], 65 | dest: 'dist/test/spec', 66 | ext:'.js' 67 | }] 68 | } 69 | }, 70 | 71 | mochaTest: { 72 | test: { 73 | options: { 74 | reporter: 'spec' 75 | }, 76 | src: ['dist/test/spec/test-main.js', 'dist/test/spec/*_spec.js'] 77 | } 78 | } 79 | }); 80 | 81 | grunt.registerTask('default', ['clean', 'copy:src_to_dist', 'copy:pluginDef', 'babel', 'mochaTest']); 82 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Gustavo Brian 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![repofunding](https://img.shields.io/badge/powered%20by-repofunding-green.svg)](https://github.com/gbrian/repofunding) [![](https://img.shields.io/badge/support-5€-lightgray.svg)](https://www.paypal.me/repofunding/5) 2 | # grafana-simple-sql-datasource 3 | 4 | Allows querying SQL based datasources like SQL Server. 5 | 6 | ![SQL Plugi](https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/master/overview.png "Query editor") 7 | 8 | 9 | ## Usage 10 | Currently the plugin requires a proxy server running to communicate with the database. 11 | 12 | **Install sqlproxyserver** 13 | 14 | * Run `npm install` at the `dist/serverside` folder to install all dependencies 15 | * Run npm install on the plugin directory 16 | * Run server side code `dist/serverside/sqlproxyserver.js` 17 | * Test on your browser `http://myserver:port/con=mssql://user:name@server/database` you must get a `{"status":"sucess"}` response 18 | 19 | **Add new datasource** 20 | Add a new datasource to Grafana and set the url to: 21 | 22 | ```` 23 | http://myserver:port/con=mssql://user:name@server/database 24 | ```` 25 | 26 | Where: 27 | 28 | * **myserver:port** : Is the server where `sqlproxyserver` is running 29 | * **con**: Specifies the sql connection string 30 | 31 | ## SQL Databases 32 | Currently supported SQL databases 33 | 34 | ### SQL Server 35 | SQL Server connection is managed by the mssqp package https://www.npmjs.com/package/mssql 36 | 37 | ## Features 38 | Following features has been implemented 39 | 40 | ![Query editor](https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/master/query_editor.png "Query editor") 41 | 42 | ### Metrics 43 | It is possible to define two different types: `timeseries` and `table` 44 | 45 | ### Annotation 46 | Annotation querires must return the following fields: 47 | 48 | * **title**: Annotation header 49 | * **text**: Annotation description 50 | * **tags**: Annotation tags 51 | * **time**: Annotation time 52 | 53 | ## Notes 54 | ### Time 55 | UTC and Localtime. Currently you must specify if time returned by the query is UTC or local. 56 | The plugin will convert localtime to UTC in order to be correctly renderer. 57 | ### Template 58 | You can use `$from` and `$to` to refer to selected time period in your queries like: 59 | 60 | ```` 61 | select 'Metric Name' as metric, -- Use a literal or group by a column for the labels 62 | count(*) as hits, -- Just counting occurrences 63 | ts as [timestamp] 64 | from ( 65 | Select dbo.scale_interval(dateColumn, '$Interval') as ts -- scale datetime to $Interval (e.g. 10m) 66 | from myTable 67 | where dateColumn >= '$from' and dateColumn < '$to' 68 | ) T 69 | group by ts 70 | order by ts asc 71 | ```` 72 | 73 | ### MISC 74 | #### scale_interval 75 | Simple TSQL to group series by an interval 76 | 77 | ```` 78 | ALTER FUNCTION scale_interval 79 | ( 80 | -- Add the parameters for the function here 81 | @dt as datetime, @interval as varchar(100) 82 | ) 83 | RETURNS DateTime 84 | AS 85 | BEGIN 86 | DECLARE @amount int = 10 87 | 88 | IF CHARINDEX('m', @interval) <> 0 89 | BEGIN 90 | SET @amount = CAST(REPLACE(@interval, 'm', '') as int) 91 | return dateadd(minute, datediff(mi, 0, @dt) / @amount * @amount, 0) 92 | END 93 | IF CHARINDEX('h', @interval) <> 0 94 | BEGIN 95 | SET @amount = CAST(REPLACE(@interval, 'h', '') as int) 96 | return dateadd(hour, datediff(hour, 0, @dt) / @amount * @amount, 0) 97 | END 98 | IF CHARINDEX('d', @interval) <> 0 99 | BEGIN 100 | SET @amount = CAST(REPLACE(@interval, 'd', '') as int) 101 | return dateadd(day, datediff(day, 0, @dt) / @amount * @amount, 0) 102 | END 103 | RETURN NULL 104 | END 105 | GO 106 | ```` 107 | 108 | 109 | ## Thanks to 110 | Grafana team and [@bergquist](https://github.com/bergquist) 111 | 112 | ## *Powered by @repofunding* 113 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | # grafana-simple-sql-datasource 2 | 3 | Allows querying SQL based datasources like SQL Server. 4 | 5 | ![SQL Plugi](https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/master/overview.png "Query editor") 6 | 7 | 8 | ## Usage 9 | Currently the plugin requires a proxy server running to communicate with the database. 10 | 11 | **Install sqlproxyserver** 12 | 13 | * Run `npm install` at the `dist/serverside` folder to install all dependencies 14 | * Run npm install on the plugin directory 15 | * Run server side code `dist/serverside/sqlproxyserver.js` 16 | * Test on your browser `http://myserver:port/con=mssql://user:name@server/database` you must get a `{"status":"sucess"}` response 17 | 18 | **Add new datasource** 19 | Add a new datasource to Grafana and set the url to: 20 | 21 | ```` 22 | http://myserver:port/con=mssql://user:name@server/database 23 | ```` 24 | 25 | Where: 26 | 27 | * **myserver:port** : Is the server where `sqlproxyserver` is running 28 | * **con**: Specifies the sql connection string 29 | 30 | ## SQL Databases 31 | Currently supported SQL databases 32 | 33 | ### SQL Server 34 | SQL Server connection is managed by the mssqp package https://www.npmjs.com/package/mssql 35 | 36 | ## Features 37 | Following features has been implemented 38 | 39 | ![Query editor](https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/master/query_editor.png "Query editor") 40 | 41 | ### Metrics 42 | It is possible to define two different types: `timeseries` and `table` 43 | 44 | ### Annotation 45 | Annotation querires must return the following fields: 46 | 47 | * **title**: Annotation header 48 | * **text**: Annotation description 49 | * **tags**: Annotation tags 50 | * **time**: Annotation time 51 | 52 | ## Notes 53 | ### Time 54 | UTC and Localtime. Currently you must specify if time returned by the query is UTC or local. 55 | The plugin will convert localtime to UTC in order to be correctly renderer. 56 | ### Template 57 | You can use `$from` and `$to` to refer to selected time period in your queries like: 58 | 59 | ```` 60 | SELECT field FROM table WHERE datestart >= '$from' AND dateStart <= '$to' 61 | ```` 62 | 63 | ## Thanks to 64 | Grafana team and [@bergquist](https://github.com/bergquist) 65 | 66 | -------------------------------------------------------------------------------- /dist/css/query-editor.css: -------------------------------------------------------------------------------- 1 | .grafana-simple-sql-datasource .hidden { 2 | display: none; 3 | } 4 | 5 | .ace-sql-editor{ 6 | position: absolute; 7 | top: 0; 8 | right: 0; 9 | bottom: 0; 10 | left: 0; 11 | } -------------------------------------------------------------------------------- /dist/datasource.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | System.register(["lodash"], function (_export, _context) { 4 | "use strict"; 5 | 6 | var _, _createClass, GenericDatasource; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | return { 15 | setters: [function (_lodash) { 16 | _ = _lodash.default; 17 | }], 18 | execute: function () { 19 | _createClass = function () { 20 | function defineProperties(target, props) { 21 | for (var i = 0; i < props.length; i++) { 22 | var descriptor = props[i]; 23 | descriptor.enumerable = descriptor.enumerable || false; 24 | descriptor.configurable = true; 25 | if ("value" in descriptor) descriptor.writable = true; 26 | Object.defineProperty(target, descriptor.key, descriptor); 27 | } 28 | } 29 | 30 | return function (Constructor, protoProps, staticProps) { 31 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 32 | if (staticProps) defineProperties(Constructor, staticProps); 33 | return Constructor; 34 | }; 35 | }(); 36 | 37 | _export("GenericDatasource", GenericDatasource = function () { 38 | function GenericDatasource(instanceSettings, $q, backendSrv, templateSrv) { 39 | _classCallCheck(this, GenericDatasource); 40 | 41 | this.type = instanceSettings.type; 42 | this.url = instanceSettings.url || ""; 43 | var m = /con\=(.*)/.exec(this.url.split("?")[1]); 44 | this.connection = m ? m[1] : null; 45 | this.name = instanceSettings.name; 46 | this.q = $q; 47 | this.backendSrv = backendSrv; 48 | this.templateSrv = templateSrv; 49 | } 50 | 51 | _createClass(GenericDatasource, [{ 52 | key: "buildRequest", 53 | value: function buildRequest(rqtype, data) { 54 | return { 55 | type: rqtype, 56 | body: data, 57 | url: this.connection 58 | }; 59 | } 60 | }, { 61 | key: "query", 62 | value: function query(options) { 63 | var query = this.buildQueryParameters(options); 64 | 65 | if (query.targets.length <= 0) { 66 | return this.q.when({ data: [] }); 67 | } 68 | 69 | return this.backendSrv.datasourceRequest({ 70 | url: this.url, 71 | data: this.buildRequest("query", query), 72 | method: 'POST', 73 | headers: { 'Content-Type': 'application/json' } 74 | }); 75 | } 76 | }, { 77 | key: "testDatasource", 78 | value: function testDatasource() { 79 | return this.backendSrv.datasourceRequest({ 80 | url: this.url, 81 | method: 'POST', 82 | data: this.buildRequest("test", null) 83 | }).then(function (result) { 84 | return { status: "success", message: "Data source is working", title: "Success" }; 85 | }).catch(function (result) { 86 | return { status: "error", message: result, title: "Error" }; 87 | }); 88 | } 89 | }, { 90 | key: "annotationQuery", 91 | value: function annotationQuery(options) { 92 | var annotationQuery = _.assignIn({}, options); 93 | annotationQuery.annotation.query = this.templateSrv.replace(options.annotation.query, {}, 'glob'); 94 | 95 | return this.backendSrv.datasourceRequest({ 96 | url: this.url, 97 | method: 'POST', 98 | data: this.buildRequest("annotations", annotationQuery) 99 | }).then(function (result) { 100 | return result.data; 101 | }); 102 | } 103 | }, { 104 | key: "metricFindQuery", 105 | value: function metricFindQuery(options) { 106 | var opsAsString = typeof options === "string"; 107 | if (options && options.type == 'sql') 108 | // TODO: Parser? 109 | return this.q.when([]); 110 | var target = opsAsString ? options : options.target; 111 | var interpolated = { 112 | target: this.templateSrv.replace(target, null, 'regex') 113 | }; 114 | 115 | return this.backendSrv.datasourceRequest({ 116 | url: this.url, 117 | data: this.buildRequest("search", interpolated), 118 | method: 'POST', 119 | headers: { 'Content-Type': 'application/json' } 120 | }).then(this.mapToTextValue); 121 | } 122 | }, { 123 | key: "mapToTextValue", 124 | value: function mapToTextValue(result) { 125 | return _.map(result.data, function (d, i) { 126 | if (d && d.text && d.value) { 127 | return { text: d.text, value: d.value }; 128 | } else if (_.isObject(d)) { 129 | return { text: d, value: i }; 130 | } 131 | return { text: d, value: d }; 132 | }); 133 | } 134 | }, { 135 | key: "buildQueryParameters", 136 | value: function buildQueryParameters(options) { 137 | var _this = this; 138 | 139 | var clonedOptions = _.cloneDeep(options); 140 | var targets = _.filter(clonedOptions.targets, function (target) { 141 | return target.target !== 'select metric' && !target.hide; 142 | }); 143 | 144 | targets = _.map(targets, function (target) { 145 | return _.assignIn(target, { target: _this.templateSrv.replace(target.target, options.scopedVars, "distributed") }); 146 | }); 147 | 148 | clonedOptions.targets = targets; 149 | 150 | return clonedOptions; 151 | } 152 | }]); 153 | 154 | return GenericDatasource; 155 | }()); 156 | 157 | _export("GenericDatasource", GenericDatasource); 158 | } 159 | }; 160 | }); 161 | //# sourceMappingURL=datasource.js.map 162 | -------------------------------------------------------------------------------- /dist/datasource.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/datasource.js"],"names":["_","GenericDatasource","instanceSettings","$q","backendSrv","templateSrv","type","url","m","exec","split","connection","name","q","rqtype","data","body","options","query","buildQueryParameters","targets","length","when","datasourceRequest","buildRequest","method","headers","then","status","message","title","catch","result","annotationQuery","assignIn","annotation","replace","opsAsString","target","interpolated","mapToTextValue","map","d","i","text","value","isObject","clonedOptions","cloneDeep","filter","hide","scopedVars"],"mappings":"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","file":"datasource.js","sourcesContent":["import _ from \"lodash\";\r\n\r\nexport class GenericDatasource {\r\n\r\n constructor(instanceSettings, $q, backendSrv, templateSrv) {\r\n this.type = instanceSettings.type;\r\n this.url = instanceSettings.url || \"\";\r\n var m = /con\\=(.*)/.exec(this.url.split(\"?\")[1]);\r\n this.connection = m ? m[1]: null;\r\n this.name = instanceSettings.name;\r\n this.q = $q;\r\n this.backendSrv = backendSrv;\r\n this.templateSrv = templateSrv;\r\n }\r\n\r\n buildRequest(rqtype, data){\r\n return { \r\n type: rqtype,\r\n body: data,\r\n url: this.connection \r\n };\r\n }\r\n\r\n query(options) {\r\n var query = this.buildQueryParameters(options);\r\n \r\n if (query.targets.length <= 0) {\r\n return this.q.when({data: []});\r\n }\r\n\r\n return this.backendSrv.datasourceRequest({\r\n url: this.url,\r\n data: this.buildRequest(\"query\", query ),\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' }\r\n });\r\n }\r\n\r\n testDatasource() {\r\n return this.backendSrv.datasourceRequest({\r\n url: this.url,\r\n method: 'POST',\r\n data: this.buildRequest(\"test\", null)\r\n }).then(result => {\r\n return { status: \"success\", message: \"Data source is working\", title: \"Success\" };\r\n }).catch(result => {\r\n return { status: \"error\", message: result, title: \"Error\" };\r\n });\r\n }\r\n\r\n annotationQuery(options) {\r\n var annotationQuery = _.assignIn({}, options);\r\n annotationQuery.annotation.query = this.templateSrv.replace(options.annotation.query, {}, 'glob'); \r\n \r\n return this.backendSrv.datasourceRequest({\r\n url: this.url,\r\n method: 'POST',\r\n data: this.buildRequest(\"annotations\", annotationQuery)\r\n }).then(result => {\r\n return result.data;\r\n });\r\n }\r\n\r\n metricFindQuery(options) {\r\n var opsAsString = typeof (options) === \"string\";\r\n if(options && options.type == 'sql')\r\n // TODO: Parser?\r\n return this.q.when([]);\r\n var target = opsAsString ? options : options.target;\r\n var interpolated = {\r\n target: this.templateSrv.replace(target, null, 'regex')\r\n };\r\n\r\n return this.backendSrv.datasourceRequest({\r\n url: this.url,\r\n data: this.buildRequest(\"search\", interpolated ),\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' }\r\n }).then(this.mapToTextValue);\r\n }\r\n\r\n mapToTextValue(result) {\r\n return _.map(result.data, (d, i) => {\r\n if (d && d.text && d.value) {\r\n return { text: d.text, value: d.value };\r\n } else if (_.isObject(d)) {\r\n return { text: d, value: i};\r\n }\r\n return { text: d, value: d };\r\n });\r\n }\r\n\r\n buildQueryParameters(options) {\r\n var clonedOptions = _.cloneDeep(options);\r\n var targets = _.filter(clonedOptions.targets, target => \r\n target.target !== 'select metric' && !target.hide);\r\n\r\n targets = _.map(targets, target => \r\n _.assignIn(target, { target: this.templateSrv.replace(target.target, options.scopedVars, \"distributed\")}));\r\n\r\n clonedOptions.targets = targets;\r\n\r\n return clonedOptions;\r\n }\r\n}\r\n"]} -------------------------------------------------------------------------------- /dist/img/logo_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/14967005e5e2cb3edd3bd1206c5e1aaf5608b51d/dist/img/logo_large.png -------------------------------------------------------------------------------- /dist/img/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbrian/grafana-simple-sql-datasource/14967005e5e2cb3edd3bd1206c5e1aaf5608b51d/dist/img/logo_small.png -------------------------------------------------------------------------------- /dist/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | System.register(['./datasource', './query_ctrl'], function (_export, _context) { 4 | "use strict"; 5 | 6 | var GenericDatasource, GenericDatasourceQueryCtrl, GenericConfigCtrl, GenericQueryOptionsCtrl, GenericAnnotationsQueryCtrl; 7 | 8 | function _classCallCheck(instance, Constructor) { 9 | if (!(instance instanceof Constructor)) { 10 | throw new TypeError("Cannot call a class as a function"); 11 | } 12 | } 13 | 14 | return { 15 | setters: [function (_datasource) { 16 | GenericDatasource = _datasource.GenericDatasource; 17 | }, function (_query_ctrl) { 18 | GenericDatasourceQueryCtrl = _query_ctrl.GenericDatasourceQueryCtrl; 19 | }], 20 | execute: function () { 21 | _export('ConfigCtrl', GenericConfigCtrl = function GenericConfigCtrl() { 22 | _classCallCheck(this, GenericConfigCtrl); 23 | }); 24 | 25 | GenericConfigCtrl.templateUrl = 'partials/config.html'; 26 | 27 | _export('QueryOptionsCtrl', GenericQueryOptionsCtrl = function GenericQueryOptionsCtrl() { 28 | _classCallCheck(this, GenericQueryOptionsCtrl); 29 | }); 30 | 31 | GenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html'; 32 | 33 | _export('AnnotationsQueryCtrl', GenericAnnotationsQueryCtrl = function GenericAnnotationsQueryCtrl() { 34 | _classCallCheck(this, GenericAnnotationsQueryCtrl); 35 | }); 36 | 37 | GenericAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'; 38 | 39 | _export('Datasource', GenericDatasource); 40 | 41 | _export('QueryCtrl', GenericDatasourceQueryCtrl); 42 | 43 | _export('ConfigCtrl', GenericConfigCtrl); 44 | 45 | _export('QueryOptionsCtrl', GenericQueryOptionsCtrl); 46 | 47 | _export('AnnotationsQueryCtrl', GenericAnnotationsQueryCtrl); 48 | } 49 | }; 50 | }); 51 | //# sourceMappingURL=module.js.map 52 | -------------------------------------------------------------------------------- /dist/module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../src/module.js"],"names":["GenericDatasource","GenericDatasourceQueryCtrl","GenericConfigCtrl","templateUrl","GenericQueryOptionsCtrl","GenericAnnotationsQueryCtrl"],"mappings":";;;;;;;;;;;;;;;AAAQA,uB,eAAAA,iB;;AACAC,gC,eAAAA,0B;;;4BAEFC,iB;;;;AACNA,wBAAkBC,WAAlB,GAAgC,sBAAhC;;kCAEMC,uB;;;;AACNA,8BAAwBD,WAAxB,GAAsC,6BAAtC;;sCAEME,2B;;;;AACNA,kCAA4BF,WAA5B,GAA0C,kCAA1C;;4BAGEH,iB;;2BACAC,0B;;4BACAC,iB;;kCACAE,uB;;sCACAC,2B","file":"module.js","sourcesContent":["import {GenericDatasource} from './datasource';\r\nimport {GenericDatasourceQueryCtrl} from './query_ctrl';\r\n\r\nclass GenericConfigCtrl {}\r\nGenericConfigCtrl.templateUrl = 'partials/config.html';\r\n\r\nclass GenericQueryOptionsCtrl {}\r\nGenericQueryOptionsCtrl.templateUrl = 'partials/query.options.html';\r\n\r\nclass GenericAnnotationsQueryCtrl {}\r\nGenericAnnotationsQueryCtrl.templateUrl = 'partials/annotations.editor.html'\r\n\r\nexport {\r\n GenericDatasource as Datasource,\r\n GenericDatasourceQueryCtrl as QueryCtrl,\r\n GenericConfigCtrl as ConfigCtrl,\r\n GenericQueryOptionsCtrl as QueryOptionsCtrl,\r\n GenericAnnotationsQueryCtrl as AnnotationsQueryCtrl\r\n};\r\n"]} -------------------------------------------------------------------------------- /dist/partials/annotations.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
Query
3 |
4 |
5 |
6 | 7 |
8 | 10 | 11 |
12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /dist/partials/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dist/partials/query.editor.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 5 |
6 | 9 |
10 | 11 |
12 |