Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/data/common/Dhis2DataFormRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ export class Dhis2DataFormRepository implements DataFormRepository {
const base2 = getSectionBaseWithToggle(config, base, dataElements);

switch (config.viewType) {
case "grid-with-cat-option-combos":
case "grid-with-periods":
return { viewType: config.viewType, periods: config.periods, ...base2 };
case "table":
Expand Down
47 changes: 33 additions & 14 deletions src/data/common/Dhis2DataStoreDataForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ interface BaseSectionConfig {
}

interface BasicSectionConfig extends BaseSectionConfig {
viewType: "grid-with-combos" | "grid-with-cat-option-combos" | "matrix-grid" | "grid-disaggregated-cocs";
viewType: "grid-with-combos" | "matrix-grid" | "grid-disaggregated-cocs";
}

interface GridSectionConfig extends BaseSectionConfig {
Expand All @@ -70,7 +70,7 @@ interface GridSectionConfig extends BaseSectionConfig {
}

interface GridWithPeriodsSectionConfig extends BaseSectionConfig {
viewType: "grid-with-periods";
viewType: "grid-with-cat-option-combos" | "grid-with-periods";
periods: string[];
}

Expand Down Expand Up @@ -412,19 +412,37 @@ type DataFormStoreConfigFromCodec = GetType<typeof DataStoreConfigCodec>;

type PeriodInterval = { type: "relative-interval"; startOffset: number; endOffset: number };

function getPeriods(dataSetPeriod: string, interval: Maybe<PeriodInterval>): string[] {
function getPeriodsByViewType(
viewType: SectionConfig["viewType"],
dataSetPeriod: string,
interval: Maybe<PeriodInterval>
): string[] {
const dataSetYear = parseInt(dataSetPeriod);

const interval2: PeriodInterval = interval || {
type: "relative-interval",
startOffset: -2,
endOffset: 0,
};
switch (viewType) {
case "grid-indicators-calculated":
case "grid-with-periods": {
const interval2: PeriodInterval = interval || {
type: "relative-interval",
startOffset: -2,
endOffset: 0,
};

return _(dataSetYear + interval2.startOffset)
.range(dataSetYear + interval2.endOffset + 1)
.map(year => year.toString())
.value();
return _(dataSetYear + interval2.startOffset)
.range(dataSetYear + interval2.endOffset + 1)
.map(year => year.toString())
.value();
}
case "grid-with-cat-option-combos":
if (!interval) return [];

return _(dataSetYear + interval.startOffset)
.range(dataSetYear + interval.endOffset + 1)
.map(year => year.toString())
.value();
default:
throw new Error(`Unsupported viewType ${viewType} for periods calculation`);
}
}

interface DataFormStoreConfig {
Expand Down Expand Up @@ -744,11 +762,12 @@ export class Dhis2DataStoreDataForm {
const baseConfig = { ...base, viewType };

switch (viewType) {
case "grid-with-cat-option-combos":
case "grid-with-periods": {
const config = {
...baseConfig,
viewType,
periods: getPeriods(period, sectionConfig.periods),
periods: getPeriodsByViewType(viewType, period, sectionConfig.periods),
};
return [section.id, config] as [typeof section.id, typeof config];
}
Expand All @@ -774,7 +793,7 @@ export class Dhis2DataStoreDataForm {
case "grid-indicators-calculated": {
const config = {
...baseConfig,
periods: getPeriods(period, sectionConfig.periods),
periods: getPeriodsByViewType(viewType, period, sectionConfig.periods),
rows: sectionConfig.rows ?? [],
virtualColumns: sectionConfig.virtualColumns ?? [],
virtualRows: sectionConfig.virtualRows ?? [],
Expand Down
4 changes: 2 additions & 2 deletions src/domain/common/entities/DataForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,11 @@ export interface SectionBase {
}

export interface SectionSimple extends SectionBase {
viewType: "grid-with-combos" | "grid-with-cat-option-combos" | "matrix-grid" | "grid-disaggregated-cocs";
viewType: "grid-with-combos" | "matrix-grid" | "grid-disaggregated-cocs";
}

export interface SectionWithPeriods extends SectionBase {
viewType: "grid-with-periods";
viewType: "grid-with-periods" | "grid-with-cat-option-combos";
periods: string[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a getReferencedPeriods method in this class:

static getReferencedPeriods(dataForm: DataForm, basePeriod: Period): Period[] {
        return _(dataForm.sections)
            .flatMap(section => {
                switch (section.viewType) {
                    case "grid-with-periods":
                        return section.periods;
                    case "grid-indicators-calculated":
                        return section.periods;
                    default:
                        return [];
                }
            })
            .uniq()
            .concat([basePeriod])
            .sortBy()
            .value();
    }

This is being used to fetch dataValues including all the periods, can we check if we need to include the "grid-with-cat-option-combos", here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, we would need to add "grid-with-cat-option-combos" here 👍

}

Expand Down
4 changes: 4 additions & 0 deletions src/webapp/reports/autogenerated-forms/DataElementItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface DataElementItemProps {
columnDataElements?: DataElement[];
rows?: Row[];
rowName?: string;
lockException?: boolean; // If true, the input will not be disabled if expired
}

export const DataElementItem: React.FC<DataElementItemProps> = React.memo(props => {
Expand All @@ -37,6 +38,7 @@ export const DataElementItem: React.FC<DataElementItemProps> = React.memo(props
columnDataElements,
rows,
rowName,
lockException,
} = props;

const classes = useStyles();
Expand Down Expand Up @@ -97,6 +99,7 @@ export const DataElementItem: React.FC<DataElementItemProps> = React.memo(props
columnDataElements={columnDataElements}
cocId={dataElementCocId}
rows={rows}
lockException={lockException}
/>
</div>
<CommentIcon
Expand Down Expand Up @@ -124,6 +127,7 @@ export const DataElementItem: React.FC<DataElementItemProps> = React.memo(props
columnTotal={columnTotal}
columnDataElements={columnDataElements}
cocId={dataElementCocId}
lockException={lockException}
/>
</div>
</div>
Expand Down
10 changes: 7 additions & 3 deletions src/webapp/reports/autogenerated-forms/DataEntryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ export interface DataEntryItemProps {
columnDataElements?: DataElement[];
cocId: string;
rows?: Row[];
lockException?: boolean; // If true, the input will not be disabled if expired
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if I'm missing something but if the period is expired and we force an input to be enabled user can't enter data due to an exception from the API, right?

Not wrong, just to be sure I understand how this works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that is the usual behaviour. I think it would be better I rewrite the comment to explain the behaviour of lockException here. In the TUB dataset, the previous periods are not locked by the API so this will work.

I think a better comment would be:
// If true, the input will be not disabled when the period is not the same as the data form period

how about that @eperedo?

}

function isInputExpired(
period: string | undefined,
dataFormPeriod: string,
dataInputPeriods: dataInputPeriodsType,
expiryDays: number
expiryDays: number,
lockException: boolean
) {
if (lockException) return false;
const periodToCheck = period ?? dataFormPeriod;

const dataInputPeriod = dataInputPeriods?.find(p => p.period.id === periodToCheck);
Expand Down Expand Up @@ -234,7 +237,7 @@ export function checkDisabledRule(options: UseApplyRulesProps): boolean {
}

const DataEntryItem: React.FC<DataEntryItemProps> = props => {
const { dataElement, dataFormInfo, manualyDisabled: handDisabled, rows } = props;
const { dataElement, dataFormInfo, manualyDisabled: handDisabled, rows, lockException } = props;
const [dataValue, state, notifyChange] = useUpdatableDataValueWithFeedback(props);

const { type } = dataValue;
Expand All @@ -244,7 +247,8 @@ const DataEntryItem: React.FC<DataEntryItemProps> = props => {
props.period,
dataFormInfo.period,
dataFormInfo.metadata.dataForm.dataInputPeriods,
dataFormInfo.metadata.dataForm.expiryDays
dataFormInfo.metadata.dataForm.expiryDays,
lockException ?? false
)
: handDisabled;
const config = dataFormInfo.metadata.dataForm.options.dataElements[dataElement.id];
Expand Down
22 changes: 20 additions & 2 deletions src/webapp/reports/autogenerated-forms/GridWithCatOptionCombos.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { SectionSimple } from "../../../domain/common/entities/DataForm";
import { SectionWithPeriods } from "../../../domain/common/entities/DataForm";
import { DataFormInfo } from "./AutogeneratedForm";
import { makeStyles } from "@material-ui/core";
import { GridWithCatOptionCombosViewModel } from "./GridWithCatOptionCombosViewModel";
Expand All @@ -19,10 +19,11 @@ import { DataTableCellSummary } from "./datatables/DataTableCellSummary";
import { DataTableCellRowName } from "./datatables/DataTableCellRowName";
import { Html } from "./Html";
import { RowIndicatorItem } from "../../components/IndicatorItem/IndicatorItem";
import i18n from "../../../locales";

export interface GridWithCatOptionCombosProps {
dataFormInfo: DataFormInfo;
section: SectionSimple;
section: SectionWithPeriods;
}

/*
Expand Down Expand Up @@ -67,6 +68,15 @@ const GridWithCatOptionCombos: React.FC<GridWithCatOptionCombosProps> = props =>
colSpan="2"
></CustomDataTableColumnHeader>

{grid.periods.length > 0 && (
<CustomDataTableColumnHeader
backgroundColor={props.section.styles.columns.backgroundColor}
width="50px"
>
{i18n.t("Period")}
</CustomDataTableColumnHeader>
)}

{grid.columns.map(column => (
<CustomDataTableColumnHeader
backgroundColor={props.section.styles.columns.backgroundColor}
Expand Down Expand Up @@ -125,6 +135,12 @@ const GridWithCatOptionCombos: React.FC<GridWithCatOptionCombosProps> = props =>
</CustomDataTableCell>
)}

{row.period && (
<CustomDataTableCell backgroundColor={props.section.styles.rows.backgroundColor}>
<span>{row.period}</span>
</CustomDataTableCell>
)}

{grid.columns.map(column => {
const dataElement = column.dataElements.find(de => de.name === row.name);
return dataElement ? (
Expand All @@ -136,6 +152,8 @@ const GridWithCatOptionCombos: React.FC<GridWithCatOptionCombosProps> = props =>
dataElement={dataElement}
dataFormInfo={dataFormInfo}
noComment={dataElement.disabledComments}
period={row.period || dataFormInfo.period}
lockException={row.period ? true : false}
/>
</CustomDataTableCell>
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from "lodash";
import { Section, Texts } from "../../../domain/common/entities/DataForm";
import { Section, SectionWithPeriods, Texts } from "../../../domain/common/entities/DataForm";
import { DataElement } from "../../../domain/common/entities/DataElement";
import { CategoryOptionCombo } from "../../../domain/common/entities/CategoryOptionCombo";
import { Maybe } from "../../../utils/ts-utils";
Expand All @@ -11,9 +11,10 @@ export interface Grid {
id: string;
name: string;
columns: Column[];
periods: string[];
rows: Row[];
toggle: Section["toggle"];
toggleMultiple: Section["toggleMultiple"];
toggle: SectionWithPeriods["toggle"];
toggleMultiple: SectionWithPeriods["toggleMultiple"];
texts: Texts;
summary: Summary[];
indicators: Indicator[];
Expand All @@ -38,6 +39,7 @@ interface Row {
dataElement: DataElement;
deName: string;
name: string;
period?: string;
}[];
}

Expand All @@ -62,7 +64,7 @@ export function getFormulaByColumnName(section: Section, columnName: string): Ma
}

export class GridWithCatOptionCombosViewModel {
static get(section: Section, dataFormInfo: DataFormInfo): Grid {
static get(section: SectionWithPeriods, dataFormInfo: DataFormInfo): Grid {
const subsections = _(section.dataElements)
.flatMap(dataElement => {
const categoryOptionCombos = dataElement.categoryCombos.categoryOptionCombos;
Expand Down Expand Up @@ -97,7 +99,30 @@ export class GridWithCatOptionCombosViewModel {
})
.value();

const rows = _(subsections)
const rows = GridWithCatOptionCombosViewModel.getRows(subsections, section, dataFormInfo);
const columns = GridWithCatOptionCombosViewModel.getColumns(subsections, section, dataFormInfo, rows);
const summary = GridWithCatOptionCombosViewModel.getSummary(section, columns, dataFormInfo);

return {
id: section.id,
indicators: section.indicators,
name: section.name,
columns: columns,
periods: section.periods,
rows: rows,
toggle: section.toggle,
toggleMultiple: section.toggleMultiple,
texts: section.texts,
summary: section.totals ? summary : [],
};
}

private static getRows(
subsections: SubSectionGrid[],
section: SectionWithPeriods,
dataFormInfo: DataFormInfo
): Row[] {
return _(subsections)
.flatMap(subsection => subsection.dataElements)
.uniqBy(de => de.name)
.groupBy(de => _(de.name.split(separator)).initial().join(" - "))
Expand All @@ -108,34 +133,40 @@ export class GridWithCatOptionCombosViewModel {
return {
groupName: groupName,
groupDescription: groupDescription,
rows: group.map(de => {
return { dataElement: de, deName: _.last(de.name.split(separator)) ?? "", name: de.name };
rows: group.flatMap(de => {
const row = { dataElement: de, deName: _.last(de.name.split(separator)) ?? "", name: de.name };

return section.periods.length > 0 ? section.periods.map(period => ({ ...row, period })) : [row];
}),
};
})
.value();
}

const columns: Column[] = _.orderBy(
subsections.map(subsection => {
const columnDescription = getDescription(
section.columnsDescriptions,
dataFormInfo,
subsection.code || ""
);
const columnDataElements = rows.flatMap(row => {
return subsection.dataElements.filter(de => row.rows.map(r => r.name).includes(de.name));
});
private static getColumns(
subsections: SubSectionGrid[],
section: SectionWithPeriods,
dataFormInfo: DataFormInfo,
rows: Row[]
): Column[] {
const subsectionColumns = subsections.map(subsection => {
const columnDescription = getDescription(section.columnsDescriptions, dataFormInfo, subsection.code || "");
const columnDataElements = rows.flatMap(row => {
return subsection.dataElements.filter(de => row.rows.map(r => r.name).includes(de.name));
});

return {
name: subsection.name,
dataElements: columnDataElements,
description: columnDescription,
};
});

return {
name: subsection.name,
dataElements: columnDataElements,
description: columnDescription,
};
}),
[section.sortRowsBy ? section.sortRowsBy : ""]
);
return _.orderBy(subsectionColumns, [section.sortRowsBy ? section.sortRowsBy : ""]);
}

const summary = _(section.totals)
private static getSummary(section: SectionWithPeriods, columns: Column[], dataFormInfo: DataFormInfo): Summary[] {
return _(section.totals)
.map((sectionTotal, key) => {
const cellTotals = columns.map(column => {
const allDataElements = dataFormInfo.metadata.dataForm.dataElements;
Expand All @@ -162,18 +193,6 @@ export class GridWithCatOptionCombosViewModel {
})
.filter(summaryRow => summaryRow.cells.every(cell => cell.items.length > 0))
.value();

return {
id: section.id,
indicators: section.indicators,
name: section.name,
columns: columns,
rows: rows,
toggle: section.toggle,
toggleMultiple: section.toggleMultiple,
texts: section.texts,
summary: section.totals ? summary : [],
};
}

private static getColumnWithDataElements(selectedDataElements: DataElement[], column: Column): TotalItem[] {
Expand Down
2 changes: 1 addition & 1 deletion src/webapp/reports/autogenerated-forms/SectionsTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function TypeSwitch(props: TypeSwitchProps) {
<GridWithCatOptionCombos
key={`${section.id}+tab`}
dataFormInfo={dataFormInfo}
section={section as SectionSimple}
section={section as SectionWithPeriods}
/>
);
case "grid-disaggregated-cocs":
Expand Down
Loading