Skip to content

Commit

Permalink
feat(chartGraph): convert graph data, add error/loading states (#40)
Browse files Browse the repository at this point in the history
* parse the Redux date and sockets inputs and generate chart data and
tooltips
* add error state and zeroed array
* loading skeletor
* graphHelpers, rhelGraphCard replace translate refs
* rhelGraphCard, consolidate logic
* update integration snapshots
* graphHelpers, minor UTC correction, snapshot corrections
* dateHelpers, initial date defaults, prep for additional date functions
* helpers, index layout
* rhelGraphCard, replace default startDate, endDate props with helper
  • Loading branch information
priley86 committed Jul 19, 2019
1 parent 66f34ef commit d4ad093
Show file tree
Hide file tree
Showing 14 changed files with 571 additions and 153 deletions.
4 changes: 3 additions & 1 deletion public/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"curiosity-graph": {
"heading": "Daily CPU socket usage",
"dropdownDefault": "Last 30 Days"
"dropdownDefault": "Last 30 Days",
"socketsOn": "sockets on",
"fromPrevious": "from previous day"
}
}
10 changes: 10 additions & 0 deletions src/common/__tests__/__snapshots__/dateHelpers.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DateHelpers should have specific functions: dateHelpers 1`] = `
Object {
"defaultDateTime": Object {
"end": null,
"start": null,
},
}
`;
76 changes: 75 additions & 1 deletion src/common/__tests__/__snapshots__/graphHelpers.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,11 +1,85 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`GraphHelpers should have specific functions: helpers 1`] = `
exports[`GraphHelpers should convert graph data and generate tooltips when usage is populated: usage populated 1`] = `
Array [
Object {
"label": "56 sockets on Jun 1",
"x": "Jun 1",
"y": 56,
},
Object {
"label": "30 sockets on Jun 2
-26 from previous day",
"x": "Jun 2",
"y": 30,
},
Object {
"label": "40 sockets on Jun 3
+10 from previous day",
"x": "Jun 3",
"y": 40,
},
]
`;

exports[`GraphHelpers should convert graph data and return zeroed usage array if usage is empty: zeroed array 1`] = `
Array [
Object {
"x": "Jun 1",
"y": "0",
},
Object {
"x": "Jun 2",
"y": "0",
},
Object {
"x": "Jun 3",
"y": "0",
},
Object {
"x": "Jun 4",
"y": "0",
},
Object {
"x": "Jun 5",
"y": "0",
},
]
`;

exports[`GraphHelpers should convert graph data and returned zeroed array when usage throws error: throws error 1`] = `
Array [
Object {
"x": "Jun 1",
"y": "0",
},
Object {
"x": "Jun 2",
"y": "0",
},
Object {
"x": "Jun 3",
"y": "0",
},
Object {
"x": "Jun 4",
"y": "0",
},
Object {
"x": "Jun 5",
"y": "0",
},
]
`;

exports[`GraphHelpers should have specific functions: graphHelpers 1`] = `
Object {
"chartDateFormat": "MMM D",
"convertGraphData": [Function],
"getGraphHeight": [Function],
"getTooltipDimensions": [Function],
"getTooltipFontSize": [Function],
"zeroedUsageData": [Function],
}
`;

Expand Down
7 changes: 7 additions & 0 deletions src/common/__tests__/dateHelpers.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { dateHelpers } from '../dateHelpers';

describe('DateHelpers', () => {
it('should have specific functions', () => {
expect(dateHelpers).toMatchSnapshot('dateHelpers');
});
});
48 changes: 46 additions & 2 deletions src/common/__tests__/graphHelpers.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,55 @@
import { graphHelpers, getGraphHeight, getTooltipDimensions, getTooltipFontSize } from '../graphHelpers';
import {
graphHelpers,
convertGraphData,
getGraphHeight,
getTooltipDimensions,
getTooltipFontSize
} from '../graphHelpers';
import { helpers } from '../helpers';

describe('GraphHelpers', () => {
const { breakpoints } = helpers;
const startDate = new Date('2019-06-01T00:00:00Z');
const endDate = new Date('2019-06-05T00:00:00Z');
const socketLabel = 'sockets on';
const previousLabel = 'from previous day';

it('should have specific functions', () => {
expect(graphHelpers).toMatchSnapshot('helpers');
expect(graphHelpers).toMatchSnapshot('graphHelpers');
});

it('should convert graph data and return zeroed usage array if usage is empty', () => {
expect(convertGraphData({ usage: [], startDate, endDate, socketLabel, previousLabel })).toMatchSnapshot(
'zeroed array'
);
});

it('should convert graph data and generate tooltips when usage is populated', () => {
expect(
convertGraphData({
usage: [
{ cores: 56, date: '2019-06-01T00:00:00Z', instance_count: 28 },
{ cores: 30, date: '2019-06-02T00:00:00Z', instance_count: 28 },
{ cores: 40, date: '2019-06-03T00:00:00Z', instance_count: 28 }
],
startDate,
endDate,
socketLabel,
previousLabel
})
).toMatchSnapshot('usage populated');
});

it('should convert graph data and returned zeroed array when usage throws error', () => {
expect(
convertGraphData({
usage: [null], // unexpected usage, will throw exception
startDate,
endDate,
socketLabel,
previousLabel
})
).toMatchSnapshot('throws error');
});

it('should match graph heights at all breakpoints', () => {
Expand Down
21 changes: 21 additions & 0 deletions src/common/dateHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import moment from 'moment/moment';
import { helpers } from './helpers';

const defaultDateTime = (helpers.TEST_MODE && {
start: null,
end: null
}) || {
start: moment()
.utc()
.startOf('day')
.subtract(30, 'days'),
end: moment()
.utc()
.endOf('day')
};

const dateHelpers = {
defaultDateTime
};

export { dateHelpers as default, dateHelpers, defaultDateTime };
143 changes: 105 additions & 38 deletions src/common/graphHelpers.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,97 @@
const convertGraphData = () => {
// todo: convert passed params to consumable chart data

return [
{ x: 'May 25', y: 30, label: '30 Sockets on May 25' },
{ x: 'May 26', y: 60, label: '60 Sockets on May 26 \r\n +30 from previous day' },
{ x: 'May 27', y: 1 },
{ x: 'May 28', y: 1 },
{ x: 'May 29', y: 2 },
{ x: 'May 30', y: 2 },
{ x: 'May 31', y: 2 },
{ x: 'Jun 1', y: 2 },
{ x: 'Jun 2', y: 2 },
{ x: 'Jun 3', y: 2 },
{ x: 'Jun 4', y: 2 },
{ x: 'Jun 5', y: 2 },
{ x: 'Jun 6', y: 3 },
{ x: 'Jun 7', y: 3 },
{ x: 'Jun 8', y: 3 },
{ x: 'Jun 9', y: 3 },
{ x: 'Jun 10', y: 4 },
{ x: 'Jun 11', y: 4 },
{ x: 'Jun 12', y: 4 },
{ x: 'Jun 13', y: 4 },
{ x: 'Jun 14', y: 4 },
{ x: 'Jun 15', y: 4 },
{ x: 'Jun 16', y: 4 },
{ x: 'Jun 17', y: 3 },
{ x: 'Jun 18', y: 3 },
{ x: 'Jun 19', y: 1 },
{ x: 'Jun 20', y: 2 },
{ x: 'Jun 21', y: 5 },
{ x: 'Jun 22', y: 3 },
{ x: 'Jun 23', y: 1 },
{ x: 'Jun 24', y: 1 }
];
import moment from 'moment';
import { rhelApiTypes } from '../types/rhelApiTypes';
import { helpers } from './helpers';

const chartDateFormat = 'MMM D';

/**
* Generate a fallback graph with zeroed data
*
* @param startDate {string}
* @param endDate {string}
* @returns {Array}
*/
const zeroedUsageData = (startDate, endDate) => {
const zeroedArray = [];
const endDateStartDateDiff = moment(endDate).diff(startDate, 'days');

// todo: convert "y" back towards a number if/when we handle "chartDomain.y = [0, 100]" within helpers
for (let i = 0; i <= endDateStartDateDiff; i++) {
const clonedStartDate = moment.utc(startDate);
zeroedArray.push({
x: clonedStartDate.add(i, 'days').format(chartDateFormat),
y: '0'
});
}

return zeroedArray;
};

/**
* Apply label formatting
*
* @param cores {number}
* @param previousCores {number}
* @param formattedDate {string}
* @param socketLabel {string}
* @param previousLabel {string}
* @returns {string}
*/
const getLabel = ({ cores, previousCores, formattedDate, socketLabel, previousLabel }) => {
const prev = cores - previousCores;
const label = `${cores} ${socketLabel} ${formattedDate}`;

if (previousCores === null) {
return label;
}

return `${label}\n ${prev > -1 ? '+' : ''}${prev} ${previousLabel}`;
};

/**
* Convert graph data to usable format
* convert json usage report from this format:
* {cores: 56, date: "2019-06-01T00:00:00Z", instance_count: 28}
* to this format:
* { x: 'Jun 1', y: 56, label: '56 Sockets on Jun 1 \r\n +5 from previous day' }
*
* @param usage {Array}
* @param startDate {string}
* @param endDate {string}
* @param socketLabel {string}
* @param previousLabel {string}
* @returns {Array}
*/
const convertGraphData = ({ usage, startDate, endDate, socketLabel, previousLabel }) => {
let chartData = [];

try {
for (let i = 0; i < usage.length; i++) {
const formattedDate = moment
.utc(usage[i][rhelApiTypes.RHSM_API_RESPONSE_PRODUCTS_DATA_DATE])
.format(chartDateFormat);

const label = getLabel({
cores: usage[i][rhelApiTypes.RHSM_API_RESPONSE_PRODUCTS_DATA_CORES],
previousCores: i > 0 ? usage[i - 1][rhelApiTypes.RHSM_API_RESPONSE_PRODUCTS_DATA_CORES] : null,
formattedDate,
socketLabel,
previousLabel
});

chartData.push({ x: formattedDate, y: usage[i][rhelApiTypes.RHSM_API_RESPONSE_PRODUCTS_DATA_CORES], label });
}
} catch (e) {
if (!helpers.TEST_MODE) {
console.warn(`Malformed API response ${e.message}`);
}
}

if (!chartData.length) {
chartData = zeroedUsageData(startDate, endDate);
}

return chartData;
};

const getGraphHeight = (breakpoints, currentBreakpoint) =>
Expand Down Expand Up @@ -68,13 +126,22 @@ const getTooltipFontSize = (breakpoints, currentBreakpoint) => {
return 14;
};

const graphHelpers = { convertGraphData, getGraphHeight, getTooltipDimensions, getTooltipFontSize };
const graphHelpers = {
chartDateFormat,
convertGraphData,
getGraphHeight,
getTooltipDimensions,
getTooltipFontSize,
zeroedUsageData
};

export {
graphHelpers as default,
graphHelpers,
chartDateFormat,
convertGraphData,
getGraphHeight,
getTooltipDimensions,
getTooltipFontSize
getTooltipFontSize,
zeroedUsageData
};
5 changes: 5 additions & 0 deletions src/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { helpers } from './helpers';
import { dateHelpers } from './dateHelpers';
import { graphHelpers } from './graphHelpers';

export { helpers as default, helpers, dateHelpers, graphHelpers };
Loading

0 comments on commit d4ad093

Please sign in to comment.