Skip to content

Commit 135e28e

Browse files
authored
Merge pull request #1 from oslabs-beta/justin/code-review
Multiple traces on single Plotly graph; save to desktop enabled
2 parents de74ee3 + 5eca54d commit 135e28e

File tree

6 files changed

+161
-106
lines changed

6 files changed

+161
-106
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export DISPLAY="`sed -n 's/nameserver //p' /etc/resolv.conf`:0"
8585
### Running the Chronos Desktop App in Development Mode
8686

8787
1. From the root directory, run `npm install`
88-
2. Run 'npm run build'
88+
2. Run `npm run build`
8989
3. Open a new terminal and run `npm run dev:app` to start the Webpack development server
9090
4. Open a new terminal and run `npm run dev:electron` to start the Electron UI in development mode
9191

app/charts/HealthChart.tsx

Lines changed: 93 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import moment from 'moment';
22
import React, { useState } from 'react';
33
import Plot from 'react-plotly.js';
44
import { all, solo as soloStyle } from './sizeSwitch';
5+
import { getTime } from '../context/helpers';
56

67
interface HealthChartProps {
78
key: string;
8-
renderService: string;
9-
metric: string;
10-
timeList: any;
11-
valueList: any;
9+
serviceName: string;
10+
// metric: string;
11+
categoryName: string;
12+
metrics: any[];
13+
timeList: any[];
14+
// valueList: any;
1215
sizing: string;
1316
colourGenerator: Function;
1417
}
@@ -18,83 +21,106 @@ interface SoloStyles {
1821
width: number;
1922
}
2023

24+
type plotlyData = {
25+
name: string;
26+
x: string[];
27+
y: string[];
28+
type: string;
29+
mode: string;
30+
marker: { colors: string[] };
31+
};
32+
2133
const HealthChart: React.FC<HealthChartProps> = React.memo(props => {
22-
const { renderService, metric, timeList, valueList, sizing, colourGenerator } = props;
34+
// 'metrics' is an array of the user-specified metrics as objects
35+
const { serviceName, categoryName, metrics, timeList, sizing, colourGenerator } = props;
2336
const [solo, setSolo] = useState<SoloStyles | null>(null);
37+
const timeArr = timeList.map((el: any) => moment(el).format('kk:mm:ss'));
38+
const reverseTimeArr = timeArr.reverse();
39+
const re = /_/g;
40+
const plotlyDataObjectArray: plotlyData[] = [];
41+
42+
// generates an array plotly data objects to add to be passed into our plotly chart's data prop
43+
const generatePlotlyDataObjects = (metricsArray, timeArray) => {
44+
console.log('metricsArray: ', metricsArray);
45+
console.log('timeArray: ', timeArray);
46+
// initalize an array of objects for output
47+
// iterate through the metricsArray
48+
// each element is an array of num data (y-axis)
49+
metricsArray.forEach(el => {
50+
const originalMetricName = Object.keys(el)[0];
51+
const prettyMetricName = originalMetricName.replace(re, ' ');
52+
const newColor = colourGenerator(serviceName);
53+
console.log('prettyMetricName ', prettyMetricName);
54+
// plotly's data prop takes an array of objects that each have x, y, type, mode, marker
55+
const dataObject: plotlyData = {
56+
name: prettyMetricName,
57+
x: timeArray,
58+
y: el[originalMetricName],
59+
type: 'scattergl',
60+
mode: 'lines',
61+
marker: {
62+
colors: ['#fc4039', '#4b54ea', '#32b44f', '#3788fc', '#9c27b0', '#febc2c'],
63+
},
64+
};
65+
plotlyDataObjectArray.push(dataObject);
66+
});
67+
console.log('plotlydataObjectarray: ', plotlyDataObjectArray);
68+
};
69+
2470
setInterval(() => {
2571
if (solo !== soloStyle) {
2672
setSolo(soloStyle);
2773
}
2874
}, 20);
2975

3076
const createChart = () => {
31-
const timeArr = timeList.map((el: any) => moment(el).format('kk:mm:ss'));
32-
const reverseTimeArr = timeArr.reverse()
33-
const hashedColour = colourGenerator(renderService);
34-
const re = /_/g;
35-
let plotlyData: {
36-
name: any;
37-
x: any;
38-
y: any;
39-
type: any;
40-
mode: any;
41-
marker: { color: string };
42-
};
43-
plotlyData = {
44-
name: metric.replace(re, " "),
45-
x: reverseTimeArr, //reversed for better UX
46-
y: valueList,
47-
type: 'scattergl',
48-
mode: 'lines',
49-
marker: { color: hashedColour },
50-
};
51-
const sizeSwitch = sizing === 'all' ? all : solo;
77+
generatePlotlyDataObjects(metrics, reverseTimeArr);
78+
const sizeSwitch = sizing === 'all' ? all : solo;
5279

53-
return (
54-
<Plot
55-
data={[plotlyData]}
56-
config={{ displayModeBar: false }}
57-
layout={{
58-
title: `${renderService} | ${metric}`,
59-
...sizeSwitch,
60-
font: {
61-
color: '#444d56',
62-
size: 11.5,
63-
family: 'Roboto',
64-
},
65-
paper_bgcolor: 'white',
66-
plot_bgcolor: 'white',
67-
showlegend: true,
68-
legend: {
69-
orientation: 'h',
70-
xanchor: 'center',
71-
x: 0.5,
72-
y: 5,
73-
},
74-
xaxis: {
75-
title: 'Time',
76-
tickmode: 'auto',
77-
tick0: 0,
78-
dtick: 10,
79-
rangemode: 'nonnegative',
80-
mirror: false,
81-
ticks: 'outside',
82-
showline: true,
83-
},
84-
yaxis: {
85-
rangemode: 'nonnegative',
86-
title: metric,
87-
},
88-
}}
89-
/>
90-
);
80+
return (
81+
<Plot
82+
data={plotlyDataObjectArray}
83+
config={{ displayModeBar: true }}
84+
layout={{
85+
title: `${serviceName} | ${categoryName}`,
86+
...sizeSwitch,
87+
font: {
88+
color: '#444d56',
89+
size: 11.5,
90+
family: 'Roboto',
91+
},
92+
paper_bgcolor: 'white',
93+
plot_bgcolor: 'white',
94+
showlegend: true,
95+
legend: {
96+
orientation: 'h',
97+
xanchor: 'center',
98+
x: 0.5,
99+
y: 5,
100+
},
101+
xaxis: {
102+
title: 'Time',
103+
tickmode: 'auto',
104+
tick0: 0,
105+
dtick: 10,
106+
rangemode: 'nonnegative',
107+
mirror: false,
108+
ticks: 'outside',
109+
showline: true,
110+
},
111+
yaxis: {
112+
rangemode: 'nonnegative',
113+
//! change this later :^)
114+
title: 'Value',
115+
},
116+
}}
117+
/>
118+
);
91119
};
92120

93121
return (
94122
<div className="chart" data-testid="Health Chart">
95-
{
96-
createChart()
97-
}
123+
{createChart()}
98124
</div>
99125
);
100126
});

app/components/TransferColumns.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ const TransferColumns = React.memo(() => {
173173
const row = {};
174174
row['id'] = index;
175175
row['tag'] = el.tag;
176-
row['title'] = el.title.split(' | ')[1].replace("kubernetes-cadvisor/docker-desktop/", ""); // gets rid of the full path
176+
row['title'] = el.title.split(' | ')[1].replace('kubernetes-cadvisor/docker-desktop/', ''); // gets rid of the full path
177177
rows.push(row);
178178
});
179179

@@ -185,6 +185,8 @@ const TransferColumns = React.memo(() => {
185185
);
186186
});
187187

188+
//! BZ: creates metrics query page in Chronos
189+
188190
return (
189191
<>
190192
<div id="getChartsContainer">

app/containers/GraphsContainer.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,9 @@ const GraphsContainer: React.FC = React.memo(props => {
156156
};
157157

158158
const HealthAndEventButtons: JSX.Element[] = getHealthAndEventComponents();
159-
console.log({GraphsContainer: selectedMetrics})
160-
console.log({GraphsContainer: chart});
159+
console.log('selected metrics: ', {GraphsContainer: selectedMetrics})
160+
console.log('chart: ', { GraphsContainer: chart });
161+
161162
return (
162163
<>
163164
<nav id="navigationBar">

app/containers/HealthContainer.tsx

Lines changed: 61 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,50 +26,79 @@ const HealthContainer: React.FC<HealthContainerProps> = React.memo(props => {
2626
useEffect(() => {
2727
const temp: JSX.Element[] = [];
2828
let counter: number = 0;
29-
const datalist: any[] = healthData.healthDataList;
30-
const timelist: any[] = healthData.healthTimeList;
31-
console.log('datalist in healthcontainer is:', datalist); //array of healthDataList
32-
console.log('timelist in healthcontainer is:', timelist);
29+
const dataList: any[] = healthData.healthDataList;
30+
const timeList: any[] = healthData.healthTimeList;
31+
// dataList and timeList are structured the same, but time holds timestamps. An array of 4 objects. [Memory, CPU, Processes, Latency]
32+
// Each element has all its metrics.
33+
// console.log('healthData object in state: ', healthData);
34+
// console.log('dataList in healthcontainer is:', dataList);
35+
// console.log('timelist in healthcontainer is:', timeList);
3336

34-
if (healthData && datalist && timelist && datalist.length > 0 && timelist.length > 0) {
37+
if (healthData && dataList && timeList && dataList.length > 0 && timeList.length > 0) {
3538
let selectedMetricsList: string[] = [];
3639
selectedMetrics.forEach(element => {
3740
if (Object.keys(element)[0] === category) {
3841
selectedMetricsList = element[category];
3942
}
4043
});
44+
// ***ALERT*** temporary solution to getting the list of times for our single chart
45+
const times: string[] = timeList[0].Memory[0].books[0].activememory_in_bytes;
4146

42-
datalist.forEach((element: {}) => {
47+
dataList.forEach((element: {}) => {
4348
const categoryName: string = Object.keys(element)[0];
49+
/*
50+
'element' is the category found in the dataList response from the server query for metrics data.
51+
The above forEach method loops through the different categories.
52+
The 'category' variable is the specific category passed in to HealthContainer via prop drilling.
53+
The 'category' is the string Memory, CPU, or others that are in the Category column of the Query Selector interface.
54+
The 'categoryName' is the string that is Memory/CPU/other inside the metrics data response ('dataList' or 'timelist').
55+
When the 'element'/'categoryName' matches the 'category' selected in the Query Selection interface...
56+
... it will dive into that Category object to pull out a chart for each metric selected in the selection interface.
57+
selectedMetricsList is derived from the selectedMetrics that were in the QueryContext.
58+
selectedMetricsList is how we know which metrics should be made into a chart.
59+
selectedMetricsList is the way we can give one chart the multiple metrics being requested.
60+
*/
4461
if (category === categoryName) {
4562
const categoryObj: [] = element[categoryName];
63+
const filteredMetrics: any[] = [];
4664
for (const metricObj of categoryObj) {
47-
const serviceName: string = Object.keys(metricObj)[0];
48-
const serviceValArr: any[] = Object.values(metricObj);
49-
const serviceVals: any[] = serviceValArr[0];
50-
for (const serviceMetric of serviceVals) {
51-
const metric: string = Object.keys(serviceMetric)[0];
52-
const valueList = Object.values(serviceMetric)[0];
53-
const newTimeList: any = getTime(timelist, serviceName, metric, categoryName);
54-
// console.log('valueList is', valueList); //-> 50 values in an array
55-
// console.log('newTimeList array is:', newTimeList); //-> 50 values in an array
56-
if (selectedMetricsList.includes(metric)) {
57-
const re = /_/g;
58-
const newHealthChart = (
59-
<HealthChart
60-
key={`Chart${counter}`}
61-
renderService={serviceName}
62-
metric={metric.replace(re, " ")}
63-
timeList={newTimeList}
64-
valueList={valueList}
65-
sizing={props.sizing}
66-
colourGenerator={props.colourGenerator}
67-
/>
68-
);
69-
counter++;
70-
temp.push(newHealthChart);
71-
}
72-
}
65+
// serviceName = category (ex. books)
66+
const serviceName: string = Object.keys(metricObj)[0];
67+
console.log('metricObj: ', metricObj)
68+
const serviceMetricsArr: any[] = Object.values(metricObj).flat();
69+
console.log('serviceMetricsArr: ', serviceMetricsArr); // -> array of arrays containing numerical data.
70+
/* serviceMetricsArr = array of all metric objects
71+
[0: {
72+
total-availle-memory-in-bytes: [numbers, more numbers, nums, woo]
73+
}]
74+
*/
75+
76+
// filters through the desired metrics and pass them down to HealthChart
77+
selectedMetricsList.forEach(selected => {
78+
serviceMetricsArr.forEach(metric => {
79+
if (metric[selected]) filteredMetrics.push(metric);
80+
});
81+
});
82+
console.log('filteredMetrics: ', filteredMetrics);
83+
84+
const re = /_/g;
85+
const newHealthChart = (
86+
<HealthChart
87+
key={`Chart${counter}`}
88+
categoryName={categoryName}
89+
serviceName={serviceName}
90+
// metric={metric.replace(re, " ")}
91+
metrics={filteredMetrics}
92+
timeList={times}
93+
// valueList={valueList}
94+
sizing={props.sizing}
95+
colourGenerator={props.colourGenerator}
96+
/>
97+
);
98+
counter++;
99+
temp.push(newHealthChart);
100+
// }
101+
// }
73102
}
74103
}
75104
});

package-lock.json

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)