diff --git a/server/src/models/analytic_unit_cache_model.ts b/server/src/models/analytic_unit_cache_model.ts index 80de419..97dbc1e 100644 --- a/server/src/models/analytic_unit_cache_model.ts +++ b/server/src/models/analytic_unit_cache_model.ts @@ -29,6 +29,13 @@ export class AnalyticUnitCache { }; } + public toTemplate(): any { + return { + ...this.toObject(), + _id: undefined + }; + } + static fromObject(obj: any): AnalyticUnitCache { return new AnalyticUnitCache( obj._id, diff --git a/server/src/models/analytic_units/analytic_unit_model.ts b/server/src/models/analytic_units/analytic_unit_model.ts index 84759e6..1e68d92 100644 --- a/server/src/models/analytic_units/analytic_unit_model.ts +++ b/server/src/models/analytic_units/analytic_unit_model.ts @@ -84,6 +84,7 @@ export abstract class AnalyticUnit { public toTemplate(): any { const obj = _.cloneDeep(this.toObject()); + delete obj._id; obj.grafanaUrl = '${GRAFANA_URL}'; obj.panelId = '${PANEL_ID}'; obj.metric.datasource.url = '${DATASOURCE_URL}'; diff --git a/server/src/models/detection_model.ts b/server/src/models/detection_model.ts index afca0cc..483890f 100644 --- a/server/src/models/detection_model.ts +++ b/server/src/models/detection_model.ts @@ -57,6 +57,14 @@ export class DetectionSpan { }; } + public toTemplate(): any { + return { + ...this.toObject(), + _id: undefined, + analyticUnitId: undefined + }; + } + static fromObject(obj: any): DetectionSpan { if(obj === undefined) { throw new Error('obj is undefined'); diff --git a/server/src/models/grafana_panel_model.ts b/server/src/models/grafana_panel_model.ts index d1c74e4..a94639f 100644 --- a/server/src/models/grafana_panel_model.ts +++ b/server/src/models/grafana_panel_model.ts @@ -1,13 +1,6 @@ -import * as AnalyticUnit from './analytic_units'; -import * as AnalyticUnitCache from '../models/analytic_unit_cache_model'; -import * as DetectionSpan from '../models/detection_model'; -import * as Segment from '../models/segment_model'; - export type GrafanaPanelTemplate = { - analyticUnits: AnalyticUnit.AnalyticUnit[], - caches: AnalyticUnitCache.AnalyticUnitCache[], - detectionSpans: DetectionSpan.DetectionSpan[], - segments: Segment.Segment[] + // TODO: not any + analyticUnitTemplates: any[] } export type GrafanaTemplateVariables = { diff --git a/server/src/models/segment_model.ts b/server/src/models/segment_model.ts index 992a218..0598c74 100644 --- a/server/src/models/segment_model.ts +++ b/server/src/models/segment_model.ts @@ -49,6 +49,14 @@ export class Segment { }; } + public toTemplate(): any { + return { + ...this.toObject(), + _id: undefined, + analyticUnitId: undefined + }; + } + static fromObject(obj: any): Segment { if(obj === undefined) { throw new Error('obj is undefined'); diff --git a/server/src/routes/panel_router.ts b/server/src/routes/panel_router.ts index 6334ab9..68909b9 100644 --- a/server/src/routes/panel_router.ts +++ b/server/src/routes/panel_router.ts @@ -12,38 +12,17 @@ async function exportGrafanaPanelTemplate(ctx: Router.IRouterContext) { const panelTemplate = await exportPanel(panelId); ctx.response.body = panelTemplate; -} +} async function importGrafanaPanelTemplate(ctx: Router.IRouterContext) { const { panelTemplate, templateVariables } = ctx.request.body as { - panelTemplate: GrafanaPanelTemplate, + panelTemplate: GrafanaPanelTemplate, templateVariables: GrafanaTemplateVariables }; - // TODO: move to model - if(panelTemplate.analyticUnits === undefined) { - throw new Error('Cannot import analytic units with undefined analyticUnits'); - } - if(panelTemplate.caches === undefined) { - throw new Error('Cannot import analytic units with undefined caches'); - } - if(panelTemplate.detectionSpans === undefined) { - throw new Error('Cannot import analytic units with undefined detectionSpans'); + if(panelTemplate.analyticUnitTemplates === undefined) { + throw new Error('Cannot import analytic units with undefined analyticUnitTemplates'); } - if(panelTemplate.segments === undefined) { - throw new Error('Cannot import analytic units with undefined segments'); - } - - if(templateVariables.grafanaUrl === undefined) { - throw new Error('Cannot make analytic unit from template with undefined grafanaUrl'); - } - if(templateVariables.panelId === undefined) { - throw new Error('Cannot make analytic unit from template with undefined panelId'); - } - if(templateVariables.datasourceUrl === undefined) { - throw new Error('Cannot make analytic unit from template with undefined datasourceUrl'); - } - await importPanel(panelTemplate, templateVariables); ctx.response.status = 200; } diff --git a/server/src/services/grafana_service.ts b/server/src/services/grafana_service.ts index 4960321..7ff9053 100644 --- a/server/src/services/grafana_service.ts +++ b/server/src/services/grafana_service.ts @@ -5,11 +5,12 @@ import * as AnalyticUnitCache from '../models/analytic_unit_cache_model'; import * as DetectionSpan from '../models/detection_model'; import * as Segment from '../models/segment_model'; +import * as _ from 'lodash'; + export async function exportPanel(panelId: string): Promise { const analyticUnits = await AnalyticUnit.findMany({ panelId }); const analyticUnitIds = analyticUnits.map(analyticUnit => analyticUnit.id); - const analyticUnitTemplates = analyticUnits.map(analyticUnit => analyticUnit.toTemplate()); const [caches, detectionSpans, segments] = await Promise.all([ AnalyticUnitCache.findMany({ _id: { $in: analyticUnitIds } }), @@ -17,25 +18,70 @@ export async function exportPanel(panelId: string): Promise { + const analyticUnitTemplate = analyticUnit.toTemplate(); + + let analyticUnitCache = _.find(caches, cache => cache.id === analyticUnit.id) || null; + if(analyticUnitCache !== null) { + analyticUnitCache = analyticUnitCache.toTemplate(); + } + + const analyticUnitSegments = segments + .filter(segment => segment.analyticUnitId === analyticUnit.id) + .map(segment => segment.toTemplate()); + + const analyticUnitSpans = detectionSpans + .filter(span => span.analyticUnitId === analyticUnit.id) + .map(span => span.toTemplate()); + + analyticUnitTemplates.push({ + ...analyticUnitTemplate, + cache: analyticUnitCache, + segments: analyticUnitSegments, + detectionSpans: analyticUnitSpans + }); + }); + + return { analyticUnitTemplates }; } export async function importPanel( panelTemplate: GrafanaPanelTemplate, variables: GrafanaTemplateVariables ): Promise { - panelTemplate.analyticUnits.forEach(analyticUnit => { - analyticUnit.grafanaUrl = variables.grafanaUrl; - analyticUnit.panelId = variables.panelId; - analyticUnit.metric.datasource.url = variables.datasourceUrl; - }); - await AnalyticUnit.insertMany(panelTemplate.analyticUnits); - await AnalyticUnitCache.insertMany(panelTemplate.caches); - await Segment.insertMany(panelTemplate.segments); - await DetectionSpan.insertMany(panelTemplate.detectionSpans); + await Promise.all(panelTemplate.analyticUnitTemplates.map( + template => _importAnalyticUnitTemplate(template, variables) + )); +} + +export async function _importAnalyticUnitTemplate(analyticUnitTemplate: any, variables: GrafanaTemplateVariables) { + analyticUnitTemplate.grafanaUrl = variables.grafanaUrl; + analyticUnitTemplate.panelId = variables.panelId; + analyticUnitTemplate.metric.datasource.url = variables.datasourceUrl; + + const cache = _.clone(analyticUnitTemplate.cache); + const segments = _.clone(analyticUnitTemplate.segments); + const detectionSpans = _.clone(analyticUnitTemplate.detectionSpans); + + delete analyticUnitTemplate.cache; + delete analyticUnitTemplate.segments; + delete analyticUnitTemplate.detectionSpans; + + const [ newAnalyticUnitId ] = await AnalyticUnit.insertMany([analyticUnitTemplate]); + + if(cache !== null) { + cache._id = newAnalyticUnitId; + } + + segments.forEach(segment => segment.analyticUnitId = newAnalyticUnitId); + detectionSpans.forEach(detectionSpan => detectionSpan.analyticUnitId = newAnalyticUnitId); + + return Promise.all([ + AnalyticUnitCache.insertMany([cache]), + Segment.insertMany(segments), + DetectionSpan.insertMany(detectionSpans) + ]); }