exporter.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import config from 'app/core/config';
  2. import _ from 'lodash';
  3. import { DashboardModel } from '../dashboard_model';
  4. export class DashboardExporter {
  5. constructor(private datasourceSrv) {}
  6. makeExportable(dashboard: DashboardModel) {
  7. // clean up repeated rows and panels,
  8. // this is done on the live real dashboard instance, not on a clone
  9. // so we need to undo this
  10. // this is pretty hacky and needs to be changed
  11. dashboard.cleanUpRepeats();
  12. const saveModel = dashboard.getSaveModelClone();
  13. saveModel.id = null;
  14. // undo repeat cleanup
  15. dashboard.processRepeats();
  16. const inputs = [];
  17. const requires = {};
  18. const datasources = {};
  19. const promises = [];
  20. const variableLookup: any = {};
  21. for (const variable of saveModel.templating.list) {
  22. variableLookup[variable.name] = variable;
  23. }
  24. const templateizeDatasourceUsage = obj => {
  25. // ignore data source properties that contain a variable
  26. if (obj.datasource && obj.datasource.indexOf('$') === 0) {
  27. if (variableLookup[obj.datasource.substring(1)]) {
  28. return;
  29. }
  30. }
  31. promises.push(
  32. this.datasourceSrv.get(obj.datasource).then(ds => {
  33. if (ds.meta.builtIn) {
  34. return;
  35. }
  36. const refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase();
  37. datasources[refName] = {
  38. name: refName,
  39. label: ds.name,
  40. description: '',
  41. type: 'datasource',
  42. pluginId: ds.meta.id,
  43. pluginName: ds.meta.name,
  44. };
  45. obj.datasource = '${' + refName + '}';
  46. requires['datasource' + ds.meta.id] = {
  47. type: 'datasource',
  48. id: ds.meta.id,
  49. name: ds.meta.name,
  50. version: ds.meta.info.version || '1.0.0',
  51. };
  52. })
  53. );
  54. };
  55. const processPanel = panel => {
  56. if (panel.datasource !== undefined) {
  57. templateizeDatasourceUsage(panel);
  58. }
  59. if (panel.targets) {
  60. for (const target of panel.targets) {
  61. if (target.datasource !== undefined) {
  62. templateizeDatasourceUsage(target);
  63. }
  64. }
  65. }
  66. const panelDef = config.panels[panel.type];
  67. if (panelDef) {
  68. requires['panel' + panelDef.id] = {
  69. type: 'panel',
  70. id: panelDef.id,
  71. name: panelDef.name,
  72. version: panelDef.info.version,
  73. };
  74. }
  75. };
  76. // check up panel data sources
  77. for (const panel of saveModel.panels) {
  78. processPanel(panel);
  79. // handle collapsed rows
  80. if (panel.collapsed !== undefined && panel.collapsed === true && panel.panels) {
  81. for (const rowPanel of panel.panels) {
  82. processPanel(rowPanel);
  83. }
  84. }
  85. }
  86. // templatize template vars
  87. for (const variable of saveModel.templating.list) {
  88. if (variable.type === 'query') {
  89. templateizeDatasourceUsage(variable);
  90. variable.options = [];
  91. variable.current = {};
  92. variable.refresh = variable.refresh > 0 ? variable.refresh : 1;
  93. }
  94. }
  95. // templatize annotations vars
  96. for (const annotationDef of saveModel.annotations.list) {
  97. templateizeDatasourceUsage(annotationDef);
  98. }
  99. // add grafana version
  100. requires['grafana'] = {
  101. type: 'grafana',
  102. id: 'grafana',
  103. name: 'Grafana',
  104. version: config.buildInfo.version,
  105. };
  106. return Promise.all(promises)
  107. .then(() => {
  108. _.each(datasources, (value, key) => {
  109. inputs.push(value);
  110. });
  111. // templatize constants
  112. for (const variable of saveModel.templating.list) {
  113. if (variable.type === 'constant') {
  114. const refName = 'VAR_' + variable.name.replace(' ', '_').toUpperCase();
  115. inputs.push({
  116. name: refName,
  117. type: 'constant',
  118. label: variable.label || variable.name,
  119. value: variable.current.value,
  120. description: '',
  121. });
  122. // update current and option
  123. variable.query = '${' + refName + '}';
  124. variable.options[0] = variable.current = {
  125. value: variable.query,
  126. text: variable.query,
  127. };
  128. }
  129. }
  130. // make inputs and requires a top thing
  131. const newObj = {};
  132. newObj['__inputs'] = inputs;
  133. newObj['__requires'] = _.sortBy(requires, ['id']);
  134. _.defaults(newObj, saveModel);
  135. return newObj;
  136. })
  137. .catch(err => {
  138. console.log('Export failed:', err);
  139. return {
  140. error: err,
  141. };
  142. });
  143. }
  144. }