Skip to content

Commit

Permalink
Merged in r2-2074-insights-api-send-all-columns (pull request #5913)
Browse files Browse the repository at this point in the history
R2-2074 - Insights API sends back information on all columns and rows, even if all zeros

Approved-by: Pavel Nabutovsky
Approved-by: Joshua Toliver
  • Loading branch information
aespinoza-quoin authored and jtoliver-quoin committed Apr 26, 2022
2 parents 474e4c6 + d41a3f7 commit 8eb86ac
Show file tree
Hide file tree
Showing 82 changed files with 991 additions and 940 deletions.
15 changes: 13 additions & 2 deletions app/javascript/components/charts/table-values/component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@ import { Paper, Table, TableBody, TableHead } from "@material-ui/core";
import isEmpty from "lodash/isEmpty";

import EmptyState from "../../loading-indicator/components/empty-state";
import InsightsTableHeader from "../../insights-sub-report/components/insights-table-header";

import { TableHeader, TableRows } from "./components";
import css from "./styles.css";

const TableValues = ({ columns, values, showPlaceholder = false, name = "", emptyMessage = "" }) => {
const TableValues = ({
columns,
values,
showPlaceholder = false,
name = "",
emptyMessage = "",
useInsightsHeader = false
}) => {
const Header = useInsightsHeader ? InsightsTableHeader : TableHeader;

return (
<Paper className={css.root}>
{showPlaceholder && isEmpty(values) ? (
<EmptyState type={name} emptyMessage={emptyMessage} />
) : (
<Table className={css.table}>
<TableHead className={css.tableHeader}>
<TableHeader columns={columns} />
<Header columns={columns} />
</TableHead>
<TableBody>
<TableRows values={values} />
Expand All @@ -33,6 +43,7 @@ TableValues.propTypes = {
emptyMessage: PropTypes.string,
name: PropTypes.string,
showPlaceholder: PropTypes.bool,
useInsightsHeader: PropTypes.bool,
values: PropTypes.array
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as InsightsTableHeader } from "../../../insights-sub-report/components/insights-table-header";
export { default as TableHeader } from "./table-header";
export { default as TableRows } from "./table-rows";
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import PropTypes from "prop-types";

import { ExportReportGraphIcon, ExportReportDataIcon } from "../../../images/primero-icons";
import ActionButton from "../../action-button";
import { ACTION_BUTTON_TYPES } from "../../action-button/constants";
import { ExportReportGraphIcon, ExportReportDataIcon } from "../../../../images/primero-icons";
import ActionButton from "../../../action-button";
import { ACTION_BUTTON_TYPES } from "../../../action-button/constants";

import css from "./styles.css";
import { downloadFile, tableToCsv } from "./utils";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { setupMountedComponent } from "../../../test";
import ActionButton from "../../action-button";
import { setupMountedComponent } from "../../../../test";
import ActionButton from "../../../action-button";

import Exporter from "./exporter";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./exporter";
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as exporter } from "./exporter";
export { default as InsightsTableHeader } from "./insights-table-header";
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import PropTypes from "prop-types";
import { TableCell, TableRow } from "@material-ui/core";
import isNil from "lodash/isNil";

import css from "./styles.css";
import { NAME } from "./constants";

const InsightsTableHeader = ({ addEmptyCell = true, columns }) => {
const groupedSubcolumns = columns.reduce((acc, column) => ({ ...acc, [column.label]: column.items }), {});
const subcolumnsNumber = Object.values(groupedSubcolumns)
.flat()
.some(subcolumn => !isNil(subcolumn));

return (
<>
<TableRow className={css.tableRowHeader}>
{addEmptyCell && <TableCell />}
{columns.map(column => (
<TableCell key={column.label} colSpan={column.colspan || column.items?.length}>
{column.label}
</TableCell>
))}
</TableRow>
{subcolumnsNumber && (
<TableRow className={css.tableRowSubHeader}>
{addEmptyCell && <TableCell />}
{Object.entries(groupedSubcolumns).flatMap(([parent, subcolumns]) =>
subcolumns.map(subcolumn => <TableCell key={`${parent}-${subcolumn}`}>{subcolumn}</TableCell>)
)}
</TableRow>
)}
</>
);
};

InsightsTableHeader.displayName = NAME;

InsightsTableHeader.propTypes = {
addEmptyCell: PropTypes.bool,
columns: PropTypes.array
};

export default InsightsTableHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* eslint-disable import/prefer-default-export */
export const NAME = "InsightsTableHeader";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./component";
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.tableRowSubHeader {
& th {
border-right: 1px solid var(--c-light-grey-2);
}
}

.tableRowHeader {
& th:not(:first-child) {
background-color: var(--c-light-grey);
font-weight: bold;
border-left: 1px solid var(--c-light-grey-2);
}

& th:last-of-type {
border-right: none;
}
}
15 changes: 12 additions & 3 deletions app/javascript/components/insights-sub-report/container.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from "./utils";
import { getInsight, getInsightFilter, getIsGroupedInsight } from "./selectors";
import namespace from "./namespace";
import { NAME, COMBINED_INDICATORS, GROUPED_BY_FILTER } from "./constants";
import { COMBINED_INDICATORS, GROUPED_BY_FILTER, NAME } from "./constants";
import css from "./styles.css";
import { setSubReport } from "./action-creators";

Expand Down Expand Up @@ -92,11 +92,13 @@ const Component = () => {
<>
<h3 className={css.sectionTitle}>{subReportTitle("combined")}</h3>
<TableValues
useInsightsHeader
columns={buildInsightColumns({
value: singleInsightsTableData,
isGrouped,
groupedBy,
localizeDate: i18n.localizeDate
localizeDate: i18n.localizeDate,
totalText
})}
values={buildInsightValues({
getLookupValue: lookupValue,
Expand Down Expand Up @@ -131,7 +133,14 @@ const Component = () => {
hideLegend
/>
<TableValues
columns={buildInsightColumns({ value, isGrouped, groupedBy, localizeDate: i18n.localizeDate })}
useInsightsHeader
columns={buildInsightColumns({
value,
isGrouped,
groupedBy,
localizeDate: i18n.localizeDate,
totalText
})}
values={buildInsightValues({
getLookupValue: lookupValue,
data: value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,25 @@ import getDataGroups from "./get-data-groups";
import translateGroups from "./translate-groups";

const buildGroupedColumns = (value, groupedBy, localizeDate) => {
const { years, groups } = getDataGroups(value, groupedBy);
const groups = getDataGroups(value, groupedBy);
const groupComparator = getGroupComparator(groupedBy);
const yearComparator = getGroupComparator(YEAR);

if (groupedBy === YEAR) {
return [{ items: years.sort(yearComparator), colspan: 1 }];
return groups.sort(yearComparator).map(year => ({ label: year, colspan: 1 }));
}

const translatedGroups = translateGroups(groups.sort(groupComparator), groupedBy, localizeDate);

return [
{ items: years.sort(yearComparator), colspan: groups.length },
{ items: translatedGroups, addEmptyCell: false }
];
return Object.keys(groups).map(year => ({
label: year,
items: translateGroups(groups[year].sort(groupComparator), groupedBy, localizeDate),
colspan: groups[year].length
}));
};

export default ({ value, isGrouped, groupedBy, localizeDate }) => {
export default ({ value, isGrouped, groupedBy, localizeDate, totalText }) => {
if (isGrouped && groupedBy) {
return buildGroupedColumns(value, groupedBy, localizeDate);
}

return [];
return [{ label: totalText }];
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ describe("<InsightsSubReport />/utils/buildInsightColumns", () => {
value: fromJS([
{ id: "option_1", total: 5 },
{ id: "option_2", total: 10 }
])
]),
totalText: "Total"
});

expect(columns).to.deep.equals([]);
expect(columns).to.deep.equals([{ label: "Total" }]);
});
});

Expand Down Expand Up @@ -48,7 +49,11 @@ describe("<InsightsSubReport />/utils/buildInsightColumns", () => {
])
});

expect(columns).to.deep.equal([{ items: ["2022", "2023", "2024"], colspan: 1 }]);
expect(columns).to.deep.equal([
{ label: "2022", colspan: 1 },
{ label: "2023", colspan: 1 },
{ label: "2024", colspan: 1 }
]);
});
});

Expand All @@ -60,21 +65,21 @@ describe("<InsightsSubReport />/utils/buildInsightColumns", () => {
localizeDate: format,
value: fromJS([
{
group_id: "january-2022",
group_id: "2022-01",
data: [
{ id: "option_1", total: 1 },
{ id: "option_2", total: 2 }
]
},
{
group_id: "february-2023",
group_id: "2023-02",
data: [
{ id: "option_1", total: 3 },
{ id: "option_2", total: 1 }
]
},
{
group_id: "january-2024",
group_id: "2024-01",
data: [
{ id: "option_2", total: 2 },
{ id: "option_3", total: 8 }
Expand All @@ -84,8 +89,9 @@ describe("<InsightsSubReport />/utils/buildInsightColumns", () => {
});

expect(columns).to.deep.equal([
{ items: ["2022", "2023", "2024"], colspan: 2 },
{ items: ["Jan", "Feb"], addEmptyCell: false }
{ label: "2022", items: ["Jan"], colspan: 1 },
{ label: "2023", items: ["Feb"], colspan: 1 },
{ label: "2024", items: ["Jan"], colspan: 1 }
]);
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { fromJS } from "immutable";
import first from "lodash/first";
import isNil from "lodash/isNil";
import sortBy from "lodash/sortBy";

import { YEAR } from "../../insights/constants";
Expand All @@ -13,21 +12,11 @@ import sortByAgeRange from "./sort-rows-by-age-range";
const buildRows = ({ tuples, rows, columnIndex, columnsNumber }) => {
tuples.forEach(tuple => {
const [lookupValue, value] = tuple;

const existing = rows.find(elem => first(elem) === lookupValue);

if (existing) {
if (!isNil(existing[columnIndex])) {
existing[columnIndex] = value;
} else {
// eslint-disable-next-line no-plusplus
for (let i = columnIndex; i < columnsNumber; i++) {
if (i === columnIndex) {
existing.push(value);
} else if (isNil(existing[i])) {
existing.push(0);
}
}
}
existing[columnIndex] = value;
} else {
rows.push(
[lookupValue]
Expand All @@ -39,47 +28,48 @@ const buildRows = ({ tuples, rows, columnIndex, columnsNumber }) => {
};

const buildGroupedRows = ({ getLookupValue, data, key, groupedBy }) => {
const { years, groups } = getDataGroups(data, groupedBy);
const groups = getDataGroups(data, groupedBy);

const groupedData = data.groupBy(value => value.get("group_id").toString());

if (groupedBy === YEAR) {
return years
return groups
.sort(yearComparator)
.reduce((acc, year, index) => {
const tuples = groupedData
.get(year, fromJS([]))
.flatMap(value => value.get("data").map(dataElem => [getLookupValue(key, dataElem), dataElem.get("total")]))
.toArray();

buildRows({ tuples, rows: acc, columnIndex: index + 1, columnsNumber: years.length });
buildRows({ tuples, rows: acc, columnsNumber: groups.length, columnIndex: index + 1 });

return acc;
}, [])
.map(value => ({ colspan: 0, row: value }));
}

const columnsNumber = groups.length * years.length;

const groupComparator = getGroupComparator(groupedBy);

const dataRows = years.sort(yearComparator).reduce((acc1, group1, groupIndex) => {
// index + 1 because the first value is the title of the row
const columnInitialIndex = groupIndex * groups.length + 1;
const columnsNumber = data.size;

groups.sort(groupComparator).forEach((group2, index) => {
const tuples = groupedData
.get(`${group2}-${group1}`, fromJS([]))
.flatMap(value => value.get("data").map(dataElem => [getLookupValue(key, dataElem), dataElem.get("total")]))
.toArray();
return Object.keys(groups)
.sort(yearComparator)
.reduce((acc1, year, yearIndex) => {
// index + 1 because the first value is the title of the row
const columnInitialIndex = yearIndex + 1;

buildRows({ tuples, rows: acc1, columnIndex: columnInitialIndex + index, columnsNumber });
});
groups[year].sort(groupComparator).forEach((group, index) => {
const tuples = groupedData
.get(`${year}-${group}`, fromJS([]))
.flatMap(value => value.get("data").map(dataElem => [getLookupValue(key, dataElem), dataElem.get("total")]))
.toArray();

return acc1;
}, []);
buildRows({ tuples, rows: acc1, columnIndex: columnInitialIndex + index, columnsNumber });
});

return dataRows.map(value => ({ colspan: 0, row: value }));
return acc1;
}, [])
.map(value => ({ colspan: 0, row: value }));
};

const buildSingleRows = ({ data, getLookupValue, key }) =>
Expand Down
Loading

0 comments on commit 8eb86ac

Please sign in to comment.