• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

statuscompliance / status-backend / 14569873147

21 Apr 2025 08:01AM UTC coverage: 39.601% (+1.0%) from 38.557%
14569873147

Pull #116

github

web-flow
Merge 601c268d7 into 084f625db
Pull Request #116: tests(script): added controller

234 of 710 branches covered (32.96%)

Branch coverage included in aggregate %.

680 of 1598 relevant lines covered (42.55%)

4.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/controllers/grafana.controller.js
1
import { methods } from '../config/grafana.js';
2
import createPanelTemplate from '../utils/panelStructures.js';
3
import { createSQLQuery, parseSQLQuery } from '../utils/sqlQueryBuilder.js';
4

5
export async function createServiceAccount(req, res) {
6
  try {
×
7
    const { name, role } = req.body;
×
8
    const serviceAccountData = {
×
9
      isDisabled: false,
10
      name: name,
11
      role: role,
12
    };
13

14
    const response = await methods.serviceAccount.createServiceAccount(
×
15
      serviceAccountData
16
    );
17

18
    return res.status(201).json(response.data);
×
19
  } catch (error) {
20
    if (error.response) {
×
21
      const { status } = error.response;
×
22
      return res.status(status).json(error);
×
23
    } else {
24
      return res.status(500).json({
×
25
        message:
26
                    'Failed to create service account in Grafana due to server error',
27
        error: error.message,
28
      });
29
    }
30
  }
31
}
32

33
export async function getServiceAccountById(req, res) {
34
  try {
×
35
    const response = await methods.serviceAccount.retrieveServiceAccount(
×
36
      req.params.id
37
    );
38
    return res.status(200).json(response.data);
×
39
  } catch (error) {
40
    if (error.response) {
×
41
      const { status } = error.response;
×
42
      return res.status(status).json(error);
×
43
    } else {
44
      return res.status(500).json({
×
45
        message:
46
                    'Failed to retrieve service account in Grafana due to server error',
47
        error: error.message,
48
      });
49
    }
50
  }
51
}
52

53
export async function createServiceAccountToken(req, res) {
54
  try {
×
55
    const tokenData = {
×
56
      name: req.body.name,
57
      secondsToLive: req.body.secondsToLive,
58
    };
59
    const response = await methods.serviceAccount.createToken(
×
60
      req.params.id,
61
      tokenData
62
    );
63
    return res.status(201).json(response.data);
×
64
  } catch (error) {
65
    if (error.response) {
×
66
      const { status } = error.response;
×
67
      const errorData = error.response.data ? error.response.data : error;
×
68
      return res.status(status).json(errorData);
×
69
    } else {
70
      return res.status(500).json({
×
71
        message:
72
                    'Failed to create service account token in Grafana due to server error',
73
        error: error.message,
74
      });
75
    }
76
  }
77
}
78

79
export async function getFolders(req, res) {
80
  try {
×
81
    const response = await methods.folder.getFolders();
×
82
    return res.status(200).json(response.data);
×
83
  } catch (error) {
84
    if (error.response) {
×
85
      const { status } = error.response;
×
86
      return res.status(status).json(error);
×
87
    } else {
88
      return res.status(500).json({
×
89
        message:
90
                    'Failed to retrieve folders in Grafana due to server error',
91
        error: error.message,
92
      });
93
    }
94
  }
95
}
96

97
export async function getFolderDashboardsByUID(req, res) {
98
  try {
×
99
    const folderUid = req.params.uid === '{uid}' ? '' : req.params.uid;
×
100
    const response = await methods.search.search(
×
101
      undefined,
102
      undefined,
103
      'dash-db',
104
      undefined,
105
      undefined,
106
      undefined,
107
      folderUid,
108
      undefined,
109
      undefined
110
    );
111
    const dashboards = response.data.filter((dashboard) =>
×
112
      folderUid === '' ? !dashboard.folderUid : true
×
113
    );
114
    return res.status(200).json(dashboards);
×
115
  } catch (error) {
116
    if (error.response) {
×
117
      const { status } = error.response;
×
118
      return res.status(status).json(error);
×
119
    } else {
120
      return res.status(500).json({
×
121
        message:
122
                    'Failed to retrieve dashboards in Grafana due to server error',
123
        error: error.message,
124
      });
125
    }
126
  }
127
}
128

129
export async function createFolder(req, res) {
130
  try {
×
131
    const newUID = crypto.randomUUID();
×
132
    const {title, parentUid , description } = req.body;
×
133
    const response = await methods.folder.createFolder({
×
134
      newUID,
135
      title,
136
      parentUid,
137
      description
138
    });
139
    return res.status(201).json(response.data);
×
140
  } catch (error) {
141
    if (error.response) {
×
142
      const { status, data } = error.response;
×
143
      return res.status(status).json(data);
×
144
    } else {
145
      return res.status(500).json({
×
146
        message:
147
                    'Failed to create folder in Grafana due to server error',
148
        error: error.message,
149
      });
150
    }
151
  }
152
}
153

154
export async function deleteFolder(req, res) {
155
  try {
×
156
    const response = await methods.folder.deleteFolder(req.params.uid);
×
157
    return res.status(200).json(response.data);
×
158
  } catch (error) {
159
    if (error.response) {
×
160
      const { status, data } = error.response;
×
161
      return res.status(status).json(data);
×
162
    } else {
163
      return res.status(500).json({
×
164
        message: 'Failed to delete folder in Grafana due to server error',
165
        error: error.message,
166
      });
167
    }
168
  }
169
}
170

171
export async function getFolderByUID(req, res) {
172
  try {
×
173
    const response = await methods.folder.getFolderByUID(req.params.uid);
×
174
    return res.status(200).json(response.data);
×
175
  } catch (error) {
176
    if (error.response) {
×
177
      const { status } = error.response;
×
178
      return res.status(status).json(error);
×
179
    } else {
180
      return res.status(500).json({
×
181
        message:
182
                    'Failed to retrieve folder in Grafana due to server error',
183
        error: error.message,
184
      });
185
    }
186
  }
187
}
188

189
export async function createDashboard(req, res) {
190
  try {
×
191
    const response = await methods.dashboard.postDashboard({
×
192
      dashboard: {
193
        annotations: req.body.dashboard.annotations || {
×
194
          list: [],
195
        },
196
        editable: req.body.dashboard.editable || true,
×
197
        fiscalYearStartMonth:
198
                    req.body.dashboard.fiscalYearStartMonth || 0,
×
199
        graphTooltip: req.body.dashboard.graphTooltip || 0,
×
200
        id: null,
201
        links: [],
202
        panels: req.body.dashboard.panels,
203
        schemaVersion: req.body.dashboard.schemaVersion || 16,
×
204
        tags: req.body.dashboard.tags || [],
×
205
        templating: req.body.dashboard.templating || {
×
206
          list: [],
207
        },
208
        time: req.body.dashboard.time || {
×
209
          from: 'now-6h',
210
          to: 'now',
211
        },
212
        timepicker: req.body.dashboard.timepicker || {},
×
213
        timezone: req.body.dashboard.timezone || 'browser',
×
214
        title: req.body.dashboard.title,
215
        version: req.body.dashboard.version || 0,
×
216
        weekStart: req.body.dashboard.weekStart || '',
×
217
      },
218
      overwrite: req.body.overwrite || true,
×
219
      inputs: req.body.inputs || [],
×
220
      folderUid: req.body.folderUid,
221
      message: 'Dashboard created successfully',
222
    });
223
    return res.status(201).json(response.data);
×
224
  } catch (error) {
225
    if (error.response) {
×
226
      const { status } = error.response;
×
227
      return res.status(status).json(error);
×
228
    } else {
229
      return res.status(500).json({
×
230
        message:
231
                    'Failed to create dashboard in Grafana due to server error',
232
        error: error.message,
233
      });
234
    }
235
  }
236
}
237

238
export async function importDashboard(req, res) {
239
  try {
×
240
    const response = await methods.dashboard.importDashboard({
×
241
      dashboard: {
242
        annotations: req.body.dashboard.annotations || {
×
243
          list: [],
244
        },
245
        editable: req.body.dashboard.editable || true,
×
246
        fiscalYearStartMonth:
247
                    req.body.dashboard.fiscalYearStartMonth || 0,
×
248
        graphTooltip: req.body.dashboard.graphTooltip || 0,
×
249
        id: null,
250
        links: [],
251
        panels: req.body.dashboard.panels,
252
        schemaVersion: req.body.dashboard.schemaVersion || 16,
×
253
        tags: req.body.dashboard.tags || [],
×
254
        templating: req.body.dashboard.templating || {
×
255
          list: [],
256
        },
257
        time: req.body.dashboard.time || {
×
258
          from: 'now-6h',
259
          to: 'now',
260
        },
261
        timepicker: req.body.dashboard.timepicker || {},
×
262
        timezone: req.body.dashboard.timezone || 'browser',
×
263
        title: req.body.dashboard.title,
264
        version: req.body.dashboard.version || 0,
×
265
        weekStart: req.body.dashboard.weekStart || '',
×
266
      },
267
      overwrite: req.body.overwrite || true,
×
268
      inputs: req.body.inputs || [],
×
269
      folderUid: req.body.folderUid,
270
    });
271
    return res.status(201).json(response.data);
×
272
  } catch (error) {
273
    if (error.response) {
×
274
      const { status } = error.response;
×
275
      return res.status(status).json(error);
×
276
    } else {
277
      return res.status(500).json({
×
278
        message:
279
                    'Failed to import dashboard in Grafana due to server error',
280
        error: error.message,
281
      });
282
    }
283
  }
284
}
285

286
export async function createQuery(req, res) {
287
  try {
×
288
    const response = createSQLQuery(req.body);
×
289
    return res.status(200).json({
×
290
      message: 'SQL query created successfully',
291
      query: response,
292
    });
293
  } catch (error) {
294
    return res.status(500).json({
×
295
      message: 'Failed to create SQL query',
296
      error: error.message,
297
    });
298
  }
299
}
300

301
export async function parseQuery(req, res) {
302
  try {
×
303
    const response = parseSQLQuery(req.body.rawSql);
×
304
    return res.status(200).json({
×
305
      message: 'SQL query parsed successfully',
306
      sql: response,
307
    });
308
  } catch (error) {
309
    return res.status(500).json({
×
310
      message: 'Failed to parse SQL query',
311
      error: error.message,
312
    });
313
  }
314
}
315

316
export async function addDashboardPanel(req, res) {
317
  try {
×
318
    const {
319
      title,
320
      type,
321
      sqlQuery,
322
      table = 'Computations',
×
323
      displayName,
324
      gridPos = { x: 0, y: 0, w: 12, h: 8 },
×
325
    } = req.body;
×
326

327
    const dashboardResponse = await methods.dashboard.getDashboardByUID(
×
328
      req.params.uid
329
    );
330

331
    const dashboardMetadata = dashboardResponse.data.meta;
×
332
    const actualDashboard = dashboardResponse.data.dashboard;
×
333
    let newPanelId = 0;
×
334
    if (actualDashboard.panels && actualDashboard.panels.length > 0) {
×
335
      newPanelId =
×
336
                Math.max(...actualDashboard.panels.map((panel) => panel.id)) +
×
337
                1;
338
      actualDashboard.panels.forEach((panel) => (panel.gridPos.y += 8));
×
339
    }
340
    const newPanel = createPanelTemplate(type);
×
341
    if (!newPanel) {
×
342
      return res.status(400).json({
×
343
        message: `Unsupported panel type: ${type}`,
344
      });
345
    }
346

347
    newPanel.id = newPanelId;
×
348
    newPanel.title = title;
×
349
    newPanel.fieldConfig.defaults.displayName = displayName;
×
350
    newPanel.gridPos = gridPos;
×
351
    if (newPanel.targets && newPanel.targets.length > 0) {
×
352
      newPanel.targets[0].rawSql = createSQLQuery(sqlQuery);
×
353
      newPanel.targets[0].table = table;
×
354
    }
355

356
    actualDashboard.panels.push(newPanel);
×
357

358
    actualDashboard.version += 1;
×
359
    const response = await methods.dashboard.postDashboard({
×
360
      dashboard: actualDashboard,
361
      message: 'Panel added successfully',
362
      folderUid: dashboardMetadata.folderUid,
363
      overwrite: true,
364
    });
365

366
    return res.status(201).json({
×
367
      panelId: newPanelId,
368
      title: newPanel.title,
369
      type: newPanel.type,
370
      rawSql: newPanel.targets[0].rawSql,
371
      displayName: newPanel.fieldConfig.defaults.displayName,
372
      gridPos: newPanel.gridPos,
373
      ...response.data,
374
    });
375
  } catch (error) {
376
    if (error.response) {
×
377
      const { status } = error.response;
×
378
      return res.status(status).json(error);
×
379
    } else {
380
      return res.status(500).json({
×
381
        message:
382
                    'Failed to import dashboard in Grafana due to server error',
383
        error: error.message,
384
      });
385
    }
386
  }
387
}
388

389
export async function searchItems(req, res) {
390
  try {
×
391
    const {
392
      query = '',
×
393
      tag,
394
      type,
395
      dashboardUIDs,
396
      folderUIDs,
397
      starred,
398
      limit = 1000,
×
399
      page = 1,
×
400
    } = req.query;
×
401

402
    // Utility to parse comma-separated values into an array, or return undefined for empty values.
403
    const parseList = (val) =>
×
404
      val ? (Array.isArray(val) ? val : val.split(',')) : undefined;
×
405

406
    const tags = parseList(tag);
×
407
    const dashUIDs = parseList(dashboardUIDs);
×
408
    const folderUIDsParsed = parseList(folderUIDs);
×
409

410
    const starredFlag = starred === 'true' ? true : starred === 'false' ? false : undefined;
×
411

412
    const limitNum = Math.min(Number(limit), 5000) || 1000;
×
413
    const pageNum = Number(page) || 1;
×
414

415
    const response = await methods.search.search(
×
416
      query || undefined,
×
417
      tags,
418
      type || undefined,
×
419
      undefined,            // dashboardIds (deprecated)
420
      dashUIDs,
421
      undefined,            // folderIds (deprecated)
422
      folderUIDsParsed,
423
      starredFlag,
424
      limitNum,
425
      pageNum
426
    );
427

428
    return res.status(200).json(response.data);
×
429
  } catch (error) {
430
    if (error.response) {
×
431
      const { status, data } = error.response;
×
432
      return res.status(status).json(data);
×
433
    }
434
    return res.status(500).json({
×
435
      message: 'Failed to search in Grafana due to server error',
436
      error: error.message,
437
    });
438
  }
439
}
440

441

442
export async function getDashboardByUID(req, res) {
443
  try {
×
444
    const response = await methods.dashboard.getDashboardByUID(
×
445
      req.params.uid
446
    );
447
    return res.status(200).json(response.data);
×
448
  } catch (error) {
449
    if (error.response) {
×
450
      const { status } = error.response;
×
451
      return res.status(status).json(error);
×
452
    } else {
453
      return res.status(500).json({
×
454
        message:
455
                    'Failed to retrieve dashboard in Grafana due to server error',
456
        error: error.message,
457
      });
458
    }
459
  }
460
}
461

462
export async function getDashboardPanelQueriesByUID(req, res) {
463
  try {
×
464
    const response = await methods.dashboard.getDashboardByUID(
×
465
      req.params.uid
466
    );
467
    if (response.data.dashboard.panels.length > 0) {
×
468
      const panelQueries = response.data.dashboard.panels.map((panel) => {
×
469
        return {
×
470
          id: panel.id,
471
          title: panel.title,
472
          displayName: panel.fieldConfig.defaults.displayName,
473
          rawSql: panel.targets[0].rawSql,
474
          type: panel.type,
475
        };
476
      });
477
      return res.status(200).json(panelQueries);
×
478
    }
479
    return res.status(404).json({
×
480
      message: 'No panels found in dashboard',
481
    });
482
  } catch (error) {
483
    if (error.response) {
×
484
      const { status } = error.response;
×
485
      return res.status(status).json(error);
×
486
    } else {
487
      return res.status(500).json({
×
488
        message:
489
                    'Failed to retrieve dashboard in Grafana due to server error',
490
        error: error.message,
491
      });
492
    }
493
  }
494
}
495

496
export async function getPanelQueryByID(req, res) {
497
  try {
×
498
    const response = await methods.dashboard.getDashboardByUID(
×
499
      req.params.uid
500
    );
501
    if (response.data.dashboard.panels.length > 0) {
×
502
      const panel = response.data.dashboard.panels.find(
×
503
        (panel) => panel.id === parseInt(req.params.id, 10)
×
504
      );
505
      return res.status(200).json({
×
506
        id: panel.id,
507
        title: panel.title,
508
        type: panel.type,
509
        rawSql: panel.targets[0].rawSql,
510
        displayName: panel.fieldConfig.defaults.displayName,
511
        gridPos: panel.gridPos,
512
      });
513
    }
514
    return res.status(404).json({
×
515
      message: 'Panel not found in dashboard',
516
    });
517
  } catch (error) {
518
    if (error.response) {
×
519
      const { status } = error.response;
×
520
      return res.status(status).json(error);
×
521
    } else {
522
      return res.status(500).json({
×
523
        message:
524
                    'Failed to retrieve dashboard in Grafana due to server error',
525
        error: error.message,
526
      });
527
    }
528
  }
529
}
530

531
export async function getDatasources(req, res) {
532
  try {
×
533
    const response = await methods.datasource.getDataSources();
×
534
    return res.status(200).json(response.data);
×
535
  } catch (error) {
536
    if (error.response) {
×
537
      const { status } = error.response;
×
538
      return res.status(status).json(error);
×
539
    } else {
540
      return res.status(500).json({
×
541
        message:
542
                    'Failed to retrieve datasources in Grafana due to server error',
543
        error: error.message,
544
      });
545
    }
546
  }
547
}
548

549
export async function addDatasource(req, res) {
550
  try {
×
551
    const response = await methods.datasource.addDataSource({
×
552
      access: req.body.access,
553
      basicAuth: req.body.basicAuth,
554
      basicAuthUser: process.env.GRAFANA_USER,
555
      database: req.body.database,
556
      isDefault: req.body.isDefault,
557
      jsonData: req.body.jsonData,
558
      name: req.body.datasourceName,
559
      type: req.body.type,
560
      uid: crypto.randomUUID(),
561
      url: req.body.url,
562
      user: req.body.user,
563
      withCredentials: true,
564
    });
565
    return res.status(201).json(response.data);
×
566
  } catch (error) {
567
    if (error.response) {
×
568
      const { status, statusText, data } = error.response;
×
569
      return res.status(status).json({
×
570
        message: `Failed to create datasource in Grafana: ${statusText}`,
571
        error: data.message || error.message,
×
572
      });
573
    } else {
574
      return res.status(500).json({
×
575
        message:
576
                    'Failed to create datasource in Grafana due to server error',
577
        error: error.message,
578
      });
579
    }
580
  }
581
}
582

583
export async function getPanelsByDashboardUID(req, res) {
584
  try {
×
585
    const response = await methods.dashboard.getDashboardByUID(
×
586
      req.params.uid
587
    );
588
    if (response.data.dashboard.panels.length > 0) {
×
589
      const panels = response.data.dashboard.panels.map((panel) => {
×
590
        return {
×
591
          id: panel.id,
592
          title: panel.title,
593
          type: panel.type,
594
          rawSql: panel.targets[0].rawSql,
595
          displayName: panel.fieldConfig.defaults.displayName,
596
          gridPos: panel.gridPos,
597
        };
598
      });
599
      return res.status(200).json(panels);
×
600
    }
601
    return res.status(404).json({
×
602
      message: 'No panels found in dashboard',
603
    });
604
  } catch (error) {
605
    if (error.response) {
×
606
      const { status } = error.response;
×
607
      return res.status(status).json(error);
×
608
    } else {
609
      return res.status(500).json({
×
610
        message:
611
                    'Failed to retrieve dashboard in Grafana due to server error',
612
        error: error.message,
613
      });
614
    }
615
  }
616
}
617

618
export async function deleteDashboardByUID(req, res) {
619
  try {
×
620
    const response = await methods.dashboard.deleteDashboardByUID(
×
621
      req.params.uid
622
    );
623
    return res.status(200).json(response.data);
×
624
  } catch (error) {
625
    if (error.response) {
×
626
      const { status, statusText, data } = error.response;
×
627
      return res.status(status).json({
×
628
        message: `Failed to delete dashboard in Grafana: ${statusText}`,
629
        error: data.message || error.message,
×
630
      });
631
    } else {
632
      return res.status(500).json({
×
633
        message:
634
                    'Failed to delete dashboard in Grafana due to server error',
635
        error: error.message,
636
      });
637
    }
638
  }
639
}
640

641
export async function deletePanelByID(req, res) {
642
  try {
×
643
    const response = await methods.dashboard.getDashboardByUID(
×
644
      req.params.uid
645
    );
646
    if (response.data.dashboard.panels.length > 0) {
×
647
      const panelIndex = response.data.dashboard.panels.findIndex(
×
648
        (panel) => panel.id === parseInt(req.params.id, 10)
×
649
      );
650
      if (panelIndex >= 0) {
×
651
        response.data.dashboard.panels.splice(panelIndex, 1);
×
652
        response.data.dashboard.version += 1;
×
653
        const deleteResponse = await methods.dashboard.postDashboard({
×
654
          dashboard: response.data.dashboard,
655
          folderUid: response.data.meta.folderUid,
656
          overwrite: true,
657
        });
658
        return res.status(200).json(deleteResponse.data);
×
659
      }
660
      return res.status(404).json({
×
661
        message: 'Panel not found in dashboard',
662
      });
663
    }
664
    return res.status(404).json({
×
665
      message: 'No panels found in dashboard',
666
    });
667
  } catch (error) {
668
    if (error.response) {
×
669
      const { status, statusText, data } = error.response;
×
670
      return res.status(status).json({
×
671
        message: `Failed to delete panel in Grafana: ${statusText}`,
672
        error: data.message || error.message,
×
673
      });
674
    } else {
675
      return res.status(500).json({
×
676
        message:
677
                    'Failed to delete panel in Grafana due to server error',
678
        error: error.message,
679
      });
680
    }
681
  }
682
}
683

684
export async function updatePanelByID(req, res) {
685
  try {
×
686
    const response = await methods.dashboard.getDashboardByUID(
×
687
      req.params.uid
688
    );
689
    const {
690
      title,
691
      type,
692
      sqlQuery,
693
      table,
694
      displayName,
695
      gridPos = { x: 0, y: 0, w: 12, h: 8 },
×
696
    } = req.body;
×
697

698
    if (response.data.dashboard.panels.length > 0) {
×
699
      const panelIndex = response.data.dashboard.panels.findIndex(
×
700
        (panel) => panel.id === parseInt(req.params.id, 10)
×
701
      );
702
      if (panelIndex >= 0) {
×
703
        const panel = response.data.dashboard.panels[panelIndex];
×
704
        const updatedPanel =
705
                    type === undefined
×
706
                      ? createPanelTemplate(panel.type)
707
                      : createPanelTemplate(type);
708
        updatedPanel.id = parseInt(req.params.id, 10);
×
709
        updatedPanel.title = title === undefined ? panel.title : title;
×
710
        updatedPanel.fieldConfig.defaults.displayName =
×
711
                    displayName === undefined
×
712
                      ? panel.fieldConfig.defaults.displayName
713
                      : displayName;
714
        updatedPanel.gridPos =
×
715
                    gridPos === undefined ? panel.gridPos : gridPos;
×
716
        if (updatedPanel.targets && updatedPanel.targets.length > 0) {
×
717
          updatedPanel.targets[0].rawSql =
×
718
                        sqlQuery === undefined
×
719
                          ? panel.targets[0].rawSql
720
                          : createSQLQuery(sqlQuery);
721
          updatedPanel.targets[0].table =
×
722
                        table === undefined ? panel.targets[0].table : table;
×
723
        }
724
        response.data.dashboard.panels[panelIndex] = updatedPanel;
×
725
        response.data.dashboard.version += 1;
×
726
        const updateResponse = await methods.dashboard.postDashboard({
×
727
          dashboard: response.data.dashboard,
728
          folderUid: response.data.meta.folderUid,
729
          overwrite: true,
730
        });
731
        return res.status(200).json(updateResponse.data);
×
732
      }
733
      return res.status(404).json({
×
734
        message: 'Panel not found in dashboard',
735
      });
736
    }
737
    return res.status(404).json({
×
738
      message: 'No panels found in dashboard',
739
    });
740
  } catch (error) {
741
    if (error.response) {
×
742
      const { status, statusText, data } = error.response;
×
743
      return res.status(status).json({
×
744
        message: `Failed to update panel in Grafana: ${statusText}`,
745
        error: data.message || error.message,
×
746
      });
747
    } else {
748
      return res.status(500).json({
×
749
        message:
750
                    'Failed to update panel in Grafana due to server error',
751
        error: error.message,
752
      });
753
    }
754
  }
755
}
756

757
export async function createDashboardTemplate(req, res) {
758
  try {
×
759
    const { name, folderId, startDate, endDate } = req.body;
×
760

761
    // Set time range based on startDate and endDate parameters
762
    let timeRange = {
×
763
      from: 'now-6h',
764
      to: 'now'
765
    };
766

767
    if (startDate) {
×
768
      const startDateObj = new Date(startDate);
×
769
      timeRange.from = startDateObj.toISOString();
×
770
    }
771

772
    if (endDate) {
×
773
      const endDateObj = new Date(endDate);
×
774
      timeRange.to = endDateObj.toISOString();
×
775
    }
776

777
    const dashboardTemplate = {
×
778
      dashboard: {
779
        annotations: {
780
          list: []
781
        },
782
        editable: true,
783
        fiscalYearStartMonth: 0,
784
        graphTooltip: 0,
785
        panels: [],
786
        schemaVersion: 27,
787
        tags: [],
788
        templating: {
789
          list: []
790
        },
791
        time: timeRange,
792
        timepicker: null,
793
        timezone: 'browser',
794
        title: name || 'New Dashboard Template',
×
795
        version: 0,
796
        weekStart: ''
797
      },
798
      overwrite: false,
799
      inputs: [{}],
800
      folderUid: folderId || null
×
801
    };
802

803
    const response = await methods.dashboard.postDashboard(dashboardTemplate);
×
804
    return res.status(201).json({
×
805
      message: 'Dashboard template created successfully',
806
      dashboard: response.data
807
    });
808
  } catch (error) {
809
    if (error.response) {
×
810
      const { status, data } = error.response;
×
811
      return res.status(status).json(data);
×
812
    } else {
813
      return res.status(500).json({
×
814
        message: 'Failed to create dashboard template in Grafana due to server error',
815
        error: error.message
816
      });
817
    }
818
  }
819
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc