| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- import _ from 'lodash';
- import config from 'app/core/config';
- import { DashboardModel } from '../../state/DashboardModel';
- import DatasourceSrv from 'app/features/plugins/datasource_srv';
- import { PanelModel } from 'app/features/dashboard/state';
- import { PanelPlugin } from 'app/types/plugins';
- interface Input {
- name: string;
- type: string;
- label: string;
- value: any;
- description: string;
- }
- interface Requires {
- [key: string]: {
- type: string;
- id: string;
- name: string;
- version: string;
- };
- }
- interface DataSources {
- [key: string]: {
- name: string;
- label: string;
- description: string;
- type: string;
- pluginId: string;
- pluginName: string;
- };
- }
- export class DashboardExporter {
- constructor(private datasourceSrv: DatasourceSrv) {}
- makeExportable(dashboard: DashboardModel) {
- // clean up repeated rows and panels,
- // this is done on the live real dashboard instance, not on a clone
- // so we need to undo this
- // this is pretty hacky and needs to be changed
- dashboard.cleanUpRepeats();
- const saveModel = dashboard.getSaveModelClone();
- saveModel.id = null;
- // undo repeat cleanup
- dashboard.processRepeats();
- const inputs: Input[] = [];
- const requires: Requires = {};
- const datasources: DataSources = {};
- const promises: Array<Promise<void>> = [];
- const variableLookup: { [key: string]: any } = {};
- for (const variable of saveModel.templating.list) {
- variableLookup[variable.name] = variable;
- }
- const templateizeDatasourceUsage = (obj: any) => {
- let datasource: string = obj.datasource;
- let datasourceVariable: any = null;
- // ignore data source properties that contain a variable
- if (datasource && datasource.indexOf('$') === 0) {
- datasourceVariable = variableLookup[datasource.substring(1)];
- if (datasourceVariable && datasourceVariable.current) {
- datasource = datasourceVariable.current.value;
- }
- }
- promises.push(
- this.datasourceSrv.get(datasource).then(ds => {
- if (ds.meta.builtIn) {
- return;
- }
- // add data source type to require list
- requires['datasource' + ds.meta.id] = {
- type: 'datasource',
- id: ds.meta.id,
- name: ds.meta.name,
- version: ds.meta.info.version || '1.0.0',
- };
- // if used via variable we can skip templatizing usage
- if (datasourceVariable) {
- return;
- }
- const refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase();
- datasources[refName] = {
- name: refName,
- label: ds.name,
- description: '',
- type: 'datasource',
- pluginId: ds.meta.id,
- pluginName: ds.meta.name,
- };
- obj.datasource = '${' + refName + '}';
- })
- );
- };
- const processPanel = (panel: PanelModel) => {
- if (panel.datasource !== undefined) {
- templateizeDatasourceUsage(panel);
- }
- if (panel.targets) {
- for (const target of panel.targets) {
- if (target.datasource !== undefined) {
- templateizeDatasourceUsage(target);
- }
- }
- }
- const panelDef: PanelPlugin = config.panels[panel.type];
- if (panelDef) {
- requires['panel' + panelDef.id] = {
- type: 'panel',
- id: panelDef.id,
- name: panelDef.name,
- version: panelDef.info.version,
- };
- }
- };
- // check up panel data sources
- for (const panel of saveModel.panels) {
- processPanel(panel);
- // handle collapsed rows
- if (panel.collapsed !== undefined && panel.collapsed === true && panel.panels) {
- for (const rowPanel of panel.panels) {
- processPanel(rowPanel);
- }
- }
- }
- // templatize template vars
- for (const variable of saveModel.templating.list) {
- if (variable.type === 'query') {
- templateizeDatasourceUsage(variable);
- variable.options = [];
- variable.current = {};
- variable.refresh = variable.refresh > 0 ? variable.refresh : 1;
- }
- }
- // templatize annotations vars
- for (const annotationDef of saveModel.annotations.list) {
- templateizeDatasourceUsage(annotationDef);
- }
- // add grafana version
- requires['grafana'] = {
- type: 'grafana',
- id: 'grafana',
- name: 'Grafana',
- version: config.buildInfo.version,
- };
- return Promise.all(promises)
- .then(() => {
- _.each(datasources, (value: any) => {
- inputs.push(value);
- });
- // templatize constants
- for (const variable of saveModel.templating.list) {
- if (variable.type === 'constant') {
- const refName = 'VAR_' + variable.name.replace(' ', '_').toUpperCase();
- inputs.push({
- name: refName,
- type: 'constant',
- label: variable.label || variable.name,
- value: variable.current.value,
- description: '',
- });
- // update current and option
- variable.query = '${' + refName + '}';
- variable.options[0] = variable.current = {
- value: variable.query,
- text: variable.query,
- };
- }
- }
- // make inputs and requires a top thing
- const newObj: { [key: string]: {} } = {};
- newObj['__inputs'] = inputs;
- newObj['__requires'] = _.sortBy(requires, ['id']);
- _.defaults(newObj, saveModel);
- return newObj;
- })
- .catch(err => {
- console.log('Export failed:', err);
- return {
- error: err,
- };
- });
- }
- }
|