plugin_component.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. ///<reference path="../../headers/common.d.ts" />
  2. import angular from 'angular';
  3. import _ from 'lodash';
  4. import config from 'app/core/config';
  5. import coreModule from 'app/core/core_module';
  6. /** @ngInject */
  7. function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache) {
  8. function getTemplate(component) {
  9. if (component.template) {
  10. return $q.when(component.template);
  11. }
  12. var cached = $templateCache.get(component.templateUrl);
  13. if (cached) {
  14. return $q.when(cached);
  15. }
  16. return $http.get(component.templateUrl).then(res => {
  17. return res.data;
  18. });
  19. }
  20. function getPluginComponentDirective(options) {
  21. return function() {
  22. return {
  23. templateUrl: options.Component.templateUrl,
  24. template: options.Component.template,
  25. restrict: 'E',
  26. controller: options.Component,
  27. controllerAs: 'ctrl',
  28. bindToController: true,
  29. scope: options.bindings,
  30. link: (scope, elem, attrs, ctrl) => {
  31. if (ctrl.link) {
  32. ctrl.link(scope, elem, attrs, ctrl);
  33. }
  34. if (ctrl.init) {
  35. ctrl.init();
  36. }
  37. }
  38. };
  39. };
  40. }
  41. function loadPanelComponentInfo(scope, attrs) {
  42. var panelElemName = 'panel-' + scope.panel.type;
  43. let panelInfo = config.panels[scope.panel.type];
  44. if (!panelInfo) {
  45. // unknown
  46. }
  47. return System.import(panelInfo.module).then(function(panelModule): any {
  48. var PanelCtrl = panelModule.PanelCtrl;
  49. var componentInfo = {
  50. name: 'panel-plugin-' + panelInfo.id,
  51. bindings: {dashboard: "=", panel: "=", row: "="},
  52. attrs: {dashboard: "dashboard", panel: "panel", row: "row"},
  53. Component: PanelCtrl,
  54. };
  55. if (!PanelCtrl || PanelCtrl.registered) {
  56. return componentInfo;
  57. };
  58. if (PanelCtrl.templatePromise) {
  59. return PanelCtrl.templatePromise.then(res => {
  60. return componentInfo;
  61. });
  62. }
  63. PanelCtrl.templatePromise = getTemplate(PanelCtrl).then(template => {
  64. PanelCtrl.templateUrl = null;
  65. PanelCtrl.template = `<grafana-panel ctrl="ctrl">${template}</grafana-panel>`;
  66. return componentInfo;
  67. });
  68. return PanelCtrl.templatePromise;
  69. });
  70. }
  71. function getModule(scope, attrs) {
  72. switch (attrs.type) {
  73. // QueryCtrl
  74. case "query-ctrl": {
  75. let datasource = scope.target.datasource || scope.ctrl.panel.datasource;
  76. return datasourceSrv.get(datasource).then(ds => {
  77. scope.datasource = ds;
  78. return System.import(ds.meta.module).then(dsModule => {
  79. return {
  80. name: 'query-ctrl-' + ds.meta.id,
  81. bindings: {target: "=", panelCtrl: "=", datasource: "="},
  82. attrs: {"target": "target", "panel-ctrl": "ctrl", datasource: "datasource"},
  83. Component: dsModule.QueryCtrl
  84. };
  85. });
  86. });
  87. }
  88. // QueryOptionsCtrl
  89. case "query-options-ctrl": {
  90. return datasourceSrv.get(scope.ctrl.panel.datasource).then(ds => {
  91. return System.import(ds.meta.module).then((dsModule): any => {
  92. if (!dsModule.QueryOptionsCtrl) {
  93. return {notFound: true};
  94. }
  95. return {
  96. name: 'query-options-ctrl-' + ds.meta.id,
  97. bindings: {panelCtrl: "="},
  98. attrs: {"panel-ctrl": "ctrl"},
  99. Component: dsModule.QueryOptionsCtrl
  100. };
  101. });
  102. });
  103. }
  104. // Annotations
  105. case "annotations-query-ctrl": {
  106. return System.import(scope.currentDatasource.meta.module).then(function(dsModule) {
  107. return {
  108. name: 'annotations-query-ctrl-' + scope.currentDatasource.meta.id,
  109. bindings: {annotation: "=", datasource: "="},
  110. attrs: {"annotation": "currentAnnotation", datasource: "currentDatasource"},
  111. Component: dsModule.AnnotationsQueryCtrl,
  112. };
  113. });
  114. }
  115. // ConfigCtrl
  116. case 'datasource-config-ctrl': {
  117. return System.import(scope.datasourceMeta.module).then(function(dsModule) {
  118. return {
  119. name: 'ds-config-' + scope.datasourceMeta.id,
  120. bindings: {meta: "=", current: "="},
  121. attrs: {meta: "datasourceMeta", current: "current"},
  122. Component: dsModule.ConfigCtrl,
  123. };
  124. });
  125. }
  126. // Panel
  127. case 'panel': {
  128. return loadPanelComponentInfo(scope, attrs);
  129. }
  130. default: {
  131. return $q.reject({message: "Could not find component type: " + attrs.type });
  132. }
  133. }
  134. }
  135. function appendAndCompile(scope, elem, componentInfo) {
  136. var child = angular.element(document.createElement(componentInfo.name));
  137. _.each(componentInfo.attrs, (value, key) => {
  138. child.attr(key, value);
  139. });
  140. $compile(child)(scope);
  141. elem.empty();
  142. elem.append(child);
  143. }
  144. function registerPluginComponent(scope, elem, attrs, componentInfo) {
  145. if (componentInfo.notFound) {
  146. elem.empty();
  147. return;
  148. }
  149. if (!componentInfo.Component) {
  150. throw {message: 'Failed to find exported plugin component for ' + componentInfo.name};
  151. }
  152. if (!componentInfo.Component.registered) {
  153. var directiveName = attrs.$normalize(componentInfo.name);
  154. var directiveFn = getPluginComponentDirective(componentInfo);
  155. coreModule.directive(directiveName, directiveFn);
  156. componentInfo.Component.registered = true;
  157. }
  158. appendAndCompile(scope, elem, componentInfo);
  159. }
  160. return {
  161. restrict: 'E',
  162. link: function(scope, elem, attrs) {
  163. getModule(scope, attrs).then(function (componentInfo) {
  164. registerPluginComponent(scope, elem, attrs, componentInfo);
  165. }).catch(err => {
  166. $rootScope.appEvent('alert-error', ['Plugin Error', err.message || err]);
  167. console.log('Plugin componnet error', err);
  168. });
  169. }
  170. };
  171. }
  172. coreModule.directive('pluginComponent', pluginDirectiveLoader);