Please make sure the name for the server is not 'new'
166 | ) : null}
167 | {errMsgIP ? (
168 |
Please make sure your IP is in the correct format
169 | ) : null}
170 | {errMsgPort ?
Please make sure the port is valid
: null}
171 |
172 | );
173 | };
174 |
175 | export default AddEditCard;
176 |
--------------------------------------------------------------------------------
/server/controllers/dashboardController.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-unused-vars */
2 | /* eslint-disable no-shadow */
3 | const { ChartSetting, Data } = require('../models/webModel');
4 | const { Display } = require('../models/webModel');
5 |
6 | const dashboardController = {};
7 |
8 | /*
9 | gets chart settings for a particular chart name
10 | */
11 | dashboardController.getChartSetting = (req, res, next) => {
12 | ChartSetting.findOne({ name: req.params.name }, (err, data) => {
13 | if (err) {
14 | return next({ status: 500, log: 'There was an error', message: err.message });
15 | }
16 | res.locals.chartSetting = data;
17 | return next();
18 | });
19 | };
20 |
21 | /*
22 | confirms whether or not chart name already exists
23 | */
24 | dashboardController.findAndComfirm = (req, res, next) => {
25 | if (res.locals.data === null) {
26 | res.locals.chartExists = { found: false };
27 | } else res.locals.chartExists = { found: true };
28 | return next();
29 | };
30 |
31 | /*
32 | gets display for a particular Prometheus instance
33 | */
34 | dashboardController.getAllDisplay = (req, res, next) => {
35 | Display.find({ instance: req.params.instance }, (err, data) => {
36 | if (err) {
37 | return next({ status: 500, log: 'There was an error', message: err.message });
38 | }
39 | res.locals.data = data;
40 | return next();
41 | });
42 | };
43 |
44 | /*
45 | updates display for a particular Prometheus instance if one exists
46 | if not, creates a new document for the Prometheus instance
47 | */
48 | dashboardController.updateAllDisplay = async (req, res, next) => {
49 | if (req.body.display && Array.isArray(req.body.display)) {
50 | await Display.findOneAndUpdate(
51 | { instance: req.params.instance },
52 | { display: req.body.display },
53 | (err, display) => {
54 | if (!display) {
55 | Display.create(
56 | { instance: req.params.instance, display: req.body.display },
57 | (err, result) => {
58 | if (err) {
59 | return res.status(500).send({ success: false });
60 | }
61 | return next();
62 | },
63 | );
64 | } else if (err) {
65 | return res.status(500).send({ success: false });
66 | } else {
67 | return next();
68 | }
69 | },
70 | );
71 | } else {
72 | return res.status(500).send({ success: false });
73 | }
74 | };
75 |
76 | /*
77 | creates a new document for chart setting for a new chart
78 | */
79 | dashboardController.createChartSetting = (req, res, next) => {
80 | console.log(req.body);
81 | ChartSetting.create(
82 | {
83 | name: req.params.name,
84 | columns: req.body.columns,
85 | filters: req.body.filters,
86 | },
87 | (err, result) => {
88 | if (err) {
89 | console.log(`There was an error: ${err}`);
90 | res.status(500).send({ success: false });
91 | return;
92 | }
93 | console.log(`Created: ${result}`);
94 | return next();
95 | },
96 | );
97 | };
98 |
99 | /*
100 | checks whether or not a previous query in a previous middleware
101 | had results
102 | */
103 | dashboardController.checkIfChartExists = (req, res, next) => {
104 | if (res.locals.chartSetting !== null) {
105 | res.locals.chartExists = { found: true };
106 | } else {
107 | res.locals.chartExists = { found: false };
108 | }
109 | return next();
110 | };
111 |
112 | /*
113 | deletes chart setting for a particular chart name
114 | */
115 | dashboardController.deleteChartSetting = (req, res, next) => {
116 | ChartSetting.findOneAndDelete({ name: req.params.name }, (err, data) => {
117 | if (err) {
118 | return next({ status: 500, log: 'There was an error', message: err.message });
119 | }
120 | return next();
121 | });
122 | };
123 |
124 | /*
125 | deletes single display element from a document for a particular
126 | Prometheus instance
127 | */
128 | dashboardController.deleteSingleDisplay = (req, res, next) => {
129 | const allDisplay = res.locals.data[0].display;
130 | const updatedDisplays = allDisplay.slice();
131 | for (let index = 0; index < allDisplay.length; index += 1) {
132 | const currentDisplay = allDisplay[index];
133 | if (currentDisplay[0].props.id === req.params.name) {
134 | updatedDisplays.splice(index, 1);
135 | break;
136 | }
137 | }
138 | res.locals.data = updatedDisplays;
139 | Display.findOneAndUpdate(
140 | { instance: req.params.instance },
141 | { display: updatedDisplays },
142 | (err, result) => {
143 | if (err) {
144 | return next({ status: 500, log: 'There was an error', message: err.message });
145 | }
146 | return next();
147 | },
148 | );
149 | };
150 |
151 | /*
152 | updates chart setting for a particular chart name
153 | */
154 | dashboardController.updateChartSetting = (req, res, next) => {
155 | ChartSetting.findOneAndUpdate(
156 | { name: req.params.name },
157 | { columns: req.body.columns, name: req.body.name, filters: req.body.filters },
158 | (err, result) => {
159 | if (err) {
160 | return next({ status: 500, log: 'There was an error', message: err.message });
161 | }
162 | return next();
163 | },
164 | );
165 | };
166 |
167 | /*
168 | updates single display element from a document for a particular
169 | Prometheus instance
170 | */
171 | dashboardController.updateSingleDisplay = (req, res, next) => {
172 | const updatedDisplays = [];
173 | Display.find({ instance: req.body.instance }, (err, result) => {
174 | if (err) {
175 | return next({ status: 500, log: 'There was an error', message: err.message });
176 | }
177 | result[0].display.forEach((chart) => {
178 | updatedDisplays.push(chart);
179 | });
180 | for (let index = 0; index < updatedDisplays.length; index += 1) {
181 | const currentDisplay = updatedDisplays[index];
182 | if (currentDisplay[0].props.id === req.params.name) {
183 | updatedDisplays.splice(index, 1, req.body.updatedChart);
184 | break;
185 | }
186 | }
187 | Display.findOneAndUpdate(
188 | { instance: req.body.instance },
189 | { display: updatedDisplays },
190 | (err, result) => {
191 | if (err) {
192 | return next({ status: 500, log: 'There was an error', message: err.message });
193 | }
194 | return next();
195 | },
196 | );
197 | });
198 | };
199 |
200 | /*
201 | gets info for all Prometheus instances
202 | */
203 | dashboardController.getAllPrometheusInstances = (req, res, next) => {
204 | Data.find({}, (err, result) => {
205 | if (err) {
206 | return next({ status: 500, log: 'There was an error', message: err.message });
207 | }
208 | res.locals.allPrometheusInstances = result;
209 | return next();
210 | });
211 | };
212 |
213 | /*
214 | gets info for a particular Prometheus instance name
215 | */
216 | dashboardController.getPrometheusInstance = (req, res, next) => {
217 | Data.findOne({ name: req.params.name }, (err, result) => {
218 | if (err) {
219 | return next({ status: 500, log: 'There was an error', message: err.message });
220 | }
221 | console.log('main app prom instance', result);
222 | res.locals.prometheusInstance = result;
223 | return next();
224 | });
225 | };
226 |
227 | module.exports = dashboardController;
228 |
--------------------------------------------------------------------------------
/client/components/dashboard/ChartSetup.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { DragDropContext } from 'react-beautiful-dnd';
3 | import OptionsOrSelectedColumn from './OptionsOrSelectedColumn';
4 | import TimeSeriesChart from './TimeSeriesChart';
5 | import DonutChart from './DonutChart';
6 | import SingleNumberDisplay from './SingleNumberDisplay';
7 | import DataFilters from './DataFilters';
8 | import history from './dashboardHistory';
9 |
10 | const ChartSetup = ({
11 | id,
12 | allCharts,
13 | setAllCharts,
14 | columns,
15 | setColumns,
16 | chartName,
17 | setChartName,
18 | chart,
19 | setChart,
20 | filters,
21 | setFilters,
22 | prometheusInstance,
23 | setPrometheusInstance,
24 | }) => {
25 | /*
26 | initializes state of notification for if a chart name already exists and old chart name
27 | */
28 | const [alreadyExistsNotification, setNotification] = useState(() => '');
29 | // eslint-disable-next-line no-unused-vars
30 | const [oldChartName, setOldChartName] = useState(() => chartName);
31 |
32 | /*
33 | handles after an item has been dragged and dropped:
34 | updates data selector columns in order to display correctly reflecting where
35 | items have been dragged and dropped
36 | */
37 | const onDragEnd = ({ source, destination }) => {
38 | setNotification('');
39 | if (destination === undefined || destination === null) return;
40 |
41 | if (source.droppableId === destination.droppableId && destination.index === source.index) {
42 | return;
43 | }
44 | const start = columns[source.droppableId];
45 | const end = columns[destination.droppableId];
46 |
47 | if (start === end) {
48 | const updatedList = start.list.filter((item, index) => index !== source.index);
49 | updatedList.splice(destination.index, 0, start.list[source.index]);
50 | const updatedColumn = {
51 | ...start,
52 | list: updatedList,
53 | };
54 | const updatedState = {
55 | ...columns,
56 | [updatedColumn.name]: updatedColumn,
57 | };
58 | setColumns(updatedState);
59 | } else {
60 | const updatedStartList = start.list.filter((item, index) => index !== source.index);
61 | const updatedStartColumn = {
62 | ...start,
63 | list: updatedStartList,
64 | };
65 | const updatedEndList = end.list;
66 | updatedEndList.splice(destination.index, 0, start.list[source.index]);
67 | const updatedEndColumn = {
68 | ...end,
69 | list: updatedEndList,
70 | };
71 | const updatedState = {
72 | ...columns,
73 | [updatedStartColumn.name]: updatedStartColumn,
74 | [updatedEndColumn.name]: updatedEndColumn,
75 | };
76 | setColumns(updatedState);
77 | }
78 | };
79 |
80 | /*
81 | handles changes to chart name input:
82 | updates chart name and resets notification for if a chart name already exists
83 | */
84 | const changeChartName = (event) => {
85 | setChartName(event.target.value);
86 | setNotification('');
87 | };
88 |
89 | /*
90 | copy of current state of filters to alter
91 | */
92 | const updatedFilters = { ...filters };
93 | /*
94 | handles change on filter drop downs:
95 | updates particular property in updated filters object with
96 | new selection, sets filters to updated filters
97 | */
98 | const changeFilter = (event) => {
99 | updatedFilters[event.target.id] = event.target.value;
100 | setFilters(updatedFilters);
101 | };
102 |
103 | /*
104 | handles click on save chart setup button:
105 | if new chart, checks if chart name already exists in database and notifies if so
106 | and if not, adds chart name, data selector columns, and filters to database, adds new chart
107 | to display on chart setup page and main dashboard page
108 |
109 | if edit chart, update chart name, data selector columns, and filters in database, updates chart
110 | to display on chart setup page and main dashboard page
111 |
112 | chart type displayed dependent upon aggregation selected, data selected, and time selected
113 | have notifications set up if aggregation selected, data selected, and/or time selected is not
114 | currently being handled by application
115 | */
116 | const saveChartSetup = async () => {
117 | if (id === 'new-chart') {
118 | if (columns.metricsSelected.list.length !== 0 && chartName !== '') {
119 | let chartAlreadyExists;
120 | await fetch(`/dashboard/chart/${chartName}`)
121 | .then((response) => response.json())
122 | .then((response) => {
123 | chartAlreadyExists = response.found;
124 | });
125 |
126 | if (!chartAlreadyExists) {
127 | let newChart;
128 | const aggregation = columns.aggregationSelected.list;
129 | const metric = columns.metricsSelected.list;
130 | const time = columns.timeRangeSelected.list;
131 | if (
132 | time.length !== 0
133 | && !aggregation.includes('Divide')
134 | && !aggregation.includes('Multiply')
135 | ) {
136 | newChart = [
137 | ,
146 | ];
147 | } else if (
148 | time.length === 0
149 | && aggregation.length === 1
150 | && aggregation[0] === 'Divide'
151 | && metric.length === 2
152 | ) {
153 | newChart = [
154 | ,
163 | ];
164 | } else if (
165 | time.length === 0
166 | && aggregation.length >= 0
167 | && metric.length === 1
168 | ) {
169 | newChart = [
170 | ,
179 | ];
180 | } else {
181 | newChart = [
182 |
183 | Data visualization and PromQL translation not yet available, but are currently
184 | in development. Apologies for the inconvenience. Please try something else.
185 | Thank you for your patience.
186 |