Skip to content

Commit

Permalink
Merge pull request #16 from EyeSeeTea/feat/org-unit-selector
Browse files Browse the repository at this point in the history
feat: Add Org Units filter
  • Loading branch information
eperedo authored Jan 7, 2025
2 parents eacd33f + d1ab56f commit 8082b48
Show file tree
Hide file tree
Showing 25 changed files with 739 additions and 927 deletions.
20 changes: 19 additions & 1 deletion i18n/ar.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: i18next-conv\n"
"POT-Creation-Date: 2024-12-16T17:57:18.316Z\n"
"POT-Creation-Date: 2024-12-30T12:25:50.318Z\n"
"PO-Revision-Date: 2018-10-25T09:02:35.143Z\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -41,6 +41,24 @@ msgstr ""
msgid "Close"
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Error"
msgstr ""

msgid "Select Organization Units"
msgstr ""

msgid "Cancel"
msgstr ""

msgid "Select"
msgstr ""

msgid "Clear"
msgstr ""

msgid "Back"
msgstr ""

Expand Down
22 changes: 20 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-12-16T17:57:18.316Z\n"
"PO-Revision-Date: 2024-12-16T17:57:18.316Z\n"
"POT-Creation-Date: 2024-12-30T12:25:50.318Z\n"
"PO-Revision-Date: 2024-12-30T12:25:50.318Z\n"

msgid "Select Dashboard"
msgstr ""
Expand Down Expand Up @@ -41,6 +41,24 @@ msgstr ""
msgid "Close"
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Error"
msgstr ""

msgid "Select Organization Units"
msgstr ""

msgid "Cancel"
msgstr ""

msgid "Select"
msgstr ""

msgid "Clear"
msgstr ""

msgid "Back"
msgstr ""

Expand Down
20 changes: 19 additions & 1 deletion i18n/es.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: i18next-conv\n"
"POT-Creation-Date: 2024-12-16T17:57:18.316Z\n"
"POT-Creation-Date: 2024-12-30T12:25:50.318Z\n"
"PO-Revision-Date: 2018-10-25T09:02:35.143Z\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -41,6 +41,24 @@ msgstr ""
msgid "Close"
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Error"
msgstr ""

msgid "Select Organization Units"
msgstr ""

msgid "Cancel"
msgstr ""

msgid "Select"
msgstr ""

msgid "Clear"
msgstr ""

msgid "Back"
msgstr "Volver"

Expand Down
20 changes: 19 additions & 1 deletion i18n/fr.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: i18next-conv\n"
"POT-Creation-Date: 2024-12-16T17:57:18.316Z\n"
"POT-Creation-Date: 2024-12-30T12:25:50.318Z\n"
"PO-Revision-Date: 2018-10-25T09:02:35.143Z\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -41,6 +41,24 @@ msgstr ""
msgid "Close"
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Error"
msgstr ""

msgid "Select Organization Units"
msgstr ""

msgid "Cancel"
msgstr ""

msgid "Select"
msgstr ""

msgid "Clear"
msgstr ""

msgid "Back"
msgstr ""

Expand Down
20 changes: 19 additions & 1 deletion i18n/pt.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: i18next-conv\n"
"POT-Creation-Date: 2024-12-16T17:57:18.316Z\n"
"POT-Creation-Date: 2024-12-30T12:25:50.318Z\n"
"PO-Revision-Date: 2018-10-25T09:02:35.143Z\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -41,6 +41,24 @@ msgstr ""
msgid "Close"
msgstr ""

msgid "Loading..."
msgstr ""

msgid "Error"
msgstr ""

msgid "Select Organization Units"
msgstr ""

msgid "Cancel"
msgstr ""

msgid "Select"
msgstr ""

msgid "Clear"
msgstr ""

msgid "Back"
msgstr ""

Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
"url": "git+https://github.com/eyeseetea/dashboard-reports.git"
},
"dependencies": {
"@dhis2/app-runtime": "2.8.0",
"@dhis2/app-runtime": "3.10.4",
"@dhis2/d2-i18n": "1.1.0",
"@dhis2/d2-i18n-extract": "1.0.8",
"@dhis2/d2-i18n-generate": "1.2.0",
"@dhis2/ui": "6.12.0",
"@eyeseetea/d2-api": "1.13.1",
"@eyeseetea/d2-ui-components": "2.6.11",
"@dhis2/ui": "6.15.2",
"@eyeseetea/d2-api": "1.16.1",
"@eyeseetea/d2-ui-components": "2.9.0",
"@eyeseetea/feedback-component": "0.0.3",
"@krakenjs/post-robot": "^11.0.0",
"@material-ui/core": "4.12.4",
Expand Down
8 changes: 8 additions & 0 deletions src/CompositionRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import { StorageName } from "./domain/entities/Settings";
import { DataStoreD2Repository } from "./data/repositories/DataStoreD2Repository";
import { PluginVisualizationD2Repository } from "./data/repositories/PluginVisualizationD2Repository";
import { GetPluginVisualizationUseCase } from "./domain/usecases/GetPluginVisualizationUseCase";
import { GetRootOrgUnitsUseCase } from "./domain/usecases/GetRootOrgUnitsUseCase";
import { OrgUnitD2Repository } from "./data/repositories/OrgUnitD2Repository";
import { GetOrgUnitsByIdsUseCase } from "./domain/usecases/GetOrgUnitsByIdsUseCase";

export function getCompositionRoot(api: D2Api, instance: Instance, storageName: StorageName) {
const instanceRepository = new InstanceDefaultRepository(instance);
Expand All @@ -24,6 +27,7 @@ export function getCompositionRoot(api: D2Api, instance: Instance, storageName:
storageName === "datastore" ? new DataStoreD2Repository(api) : new SettingsD2ConstantRepository(api);
const exportDocxRepository = new DashboardExportDocxRepository();
const pluginVisualizationsRepository = new PluginVisualizationD2Repository(api);
const orgUnitsRepository = new OrgUnitD2Repository(api);

return {
instance: {
Expand All @@ -45,6 +49,10 @@ export function getCompositionRoot(api: D2Api, instance: Instance, storageName:
export: {
save: new SaveRawReportUseCase(exportDocxRepository),
},
orgUnits: {
getRoots: new GetRootOrgUnitsUseCase(orgUnitsRepository),
getByIds: new GetOrgUnitsByIdsUseCase(orgUnitsRepository),
},
};
}

Expand Down
48 changes: 48 additions & 0 deletions src/data/repositories/OrgUnitD2Repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import _ from "lodash";
import { FutureData } from "../../domain/entities/Future";
import { OrgUnit } from "../../domain/entities/OrgUnit";
import { Id } from "../../domain/entities/Ref";
import { OrgUnitRepository } from "../../domain/repositories/OrgUnitRepository";
import { D2Api, MetadataPick } from "../../types/d2-api";
import { apiToFuture } from "../../utils/futures";

const orgUnitFields = { id: true, displayName: true, path: true, level: true } as const;

type D2OrgUnit = MetadataPick<{
organisationUnits: { fields: typeof orgUnitFields };
}>["organisationUnits"][number];

export class OrgUnitD2Repository implements OrgUnitRepository {
constructor(private api: D2Api) {}

public getOrgUnitRoots(): FutureData<OrgUnit[]> {
return apiToFuture(
this.api.models.organisationUnits.get({
paging: false,
filter: { level: { eq: "1" } },
fields: orgUnitFields,
})
).map(orgUnits => {
return orgUnits.objects.map(d2OrgUnit => this.convertToOrgUnit(d2OrgUnit));
});
}

public getOrgUnitsByIds(ids: Id[]): FutureData<OrgUnit[]> {
return apiToFuture(
this.api.models.organisationUnits.get({
paging: false,
fields: orgUnitFields,
filter: { id: { in: ids } },
})
).map(orgUnits => {
return orgUnits.objects.map(d2OrgUnit => this.convertToOrgUnit(d2OrgUnit));
});
}

private convertToOrgUnit(orgUnitResponse: D2OrgUnit): OrgUnit {
return {
..._.omit(orgUnitResponse, ["displayName"]),
name: orgUnitResponse.displayName,
};
}
}
54 changes: 31 additions & 23 deletions src/data/repositories/PluginVisualizationD2Repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { D2Api, MetadataPick } from "../../types/d2-api";
import { FutureData } from "../../domain/entities/Future";
import { apiToFuture } from "../../utils/futures";
import { DashboardItem } from "../../domain/entities/Dashboard";
import { generatePeriods, PeriodItem, ReportPeriod } from "../../domain/entities/DateMonth";
import { generatePeriods, ReportPeriod } from "../../domain/entities/DateMonth";
import { Maybe } from "../../types/utils";

export class PluginVisualizationD2Repository implements PluginVisualizationRepository {
constructor(private api: D2Api) {}

get(options: {
dashboardItem: DashboardItem;
orgUnitId: Maybe<Id>;
orgUnitIds: Maybe<Id[]>;
period: ReportPeriod;
}): FutureData<PluginVisualization> {
const params = processFieldsFilterParams({ fields: visualizationFields, filter: {} });
Expand All @@ -24,7 +24,7 @@ export class PluginVisualizationD2Repository implements PluginVisualizationRepos
);
return res$
.map(res => this.applyPeriodFilters(res, options.period))
.map(res => (options.orgUnitId ? this.applyOrgUnitFilters(res, options.orgUnitId) : res))
.map(res => this.applyOrgUnitFilters(res, options.orgUnitIds))
.map(res => (isD2Map(res) ? { ...res, type: "MAP" } : res));
}

Expand All @@ -36,41 +36,49 @@ export class PluginVisualizationD2Repository implements PluginVisualizationRepos
const itemsPeriod = generatePeriods(reportPeriod);
if (itemsPeriod.length === 0) {
return item;
} else if (isD2Map(item)) {
} else {
return this.applyFilters(item, dimension => ({
...dimension,
items: dimension.dimension === "pe" ? itemsPeriod : dimension.items,
}));
}
}

private applyOrgUnitFilters(item: D2PluginVisualization, orgUnitIds: Maybe<Id[]>) {
if (!orgUnitIds || orgUnitIds.length === 0) {
return item;
}
const newItems = orgUnitIds.map(id => ({ id, dimensionItemType: "ORGANISATION_UNIT" }));
return this.applyFilters(item, dimension => ({
...dimension,
items: dimension.dimension === "ou" ? newItems : dimension.items,
}));
}

private applyFilters(item: D2PluginVisualization, mapper: (dimension: D2Dimension) => D2Dimension) {
if (isD2Map(item)) {
return {
...item,
mapViews: item.mapViews.map((mapView: MapView) => ({
...mapView,
...this.applyPeriodToDimensionAttrs(mapView as WithDimensionAttributes, itemsPeriod),
...this.applyFilterToDimensionAttrs(mapView as WithDimensionAttributes, mapper),
})),
} as D2MapVisualization;
} else {
return {
...item,
...this.applyPeriodToDimensionAttrs(item as WithDimensionAttributes, itemsPeriod),
...this.applyFilterToDimensionAttrs(item as WithDimensionAttributes, mapper),
};
}
}

private applyOrgUnitFilters(item: D2PluginVisualization, _orgUnit: string) {
// TODO: filter by org unit
return item;
}

private applyPeriodToDimensionAttrs(obj: WithDimensionAttributes, period: PeriodItem[]) {
private applyFilterToDimensionAttrs(obj: WithDimensionAttributes, mapper: (dimension: D2Dimension) => D2Dimension) {
return {
rows: this.applyPeriodToDimensions(obj.rows, period),
columns: this.applyPeriodToDimensions(obj.columns, period),
filters: this.applyPeriodToDimensions(obj.filters, period),
rows: obj.rows.map(mapper),
columns: obj.columns.map(mapper),
filters: obj.filters.map(mapper),
};
}

private applyPeriodToDimensions(dimensions: D2Dimension[], period: PeriodItem[]) {
return dimensions.map(dimension => ({
...dimension,
items: dimension.dimension === "pe" ? period : dimension.items,
}));
}
}

function isD2Map(visualization: D2PluginVisualization): visualization is D2MapVisualization {
Expand Down Expand Up @@ -127,7 +135,7 @@ type DimensionType = "ou" | "pe" | (string & {});
interface D2DimensionItem {
dimensionItemType?: string;
id: string;
name: string;
name?: string;
}

interface D2Dimension {
Expand Down
21 changes: 21 additions & 0 deletions src/domain/entities/OrgUnit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import _ from "lodash";
import { Id } from "./Ref";

export type OrgUnitPath = string;

export interface OrgUnit {
id: Id;
path: OrgUnitPath;
name: string;
level: number;
}

const pathSeparator = "/";

export function getIdFromPath(path: OrgUnitPath): Id {
return _.last(path.split(pathSeparator)) as Id;
}

export function getOrgUnitParentPath(path: OrgUnitPath) {
return _(path).split(pathSeparator).initial().join(pathSeparator);
}
Loading

0 comments on commit 8082b48

Please sign in to comment.