Skip to content

Commit

Permalink
Merge pull request #279 from EyeSeeTea/development
Browse files Browse the repository at this point in the history
Release 3.19.0
  • Loading branch information
ifoche authored Oct 12, 2022
2 parents 27f8027 + 50b6d3a commit 2a3a036
Show file tree
Hide file tree
Showing 17 changed files with 272 additions and 33 deletions.
9 changes: 6 additions & 3 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: 2022-04-29T09:28:31.324Z\n"
"PO-Revision-Date: 2022-04-29T09:28:31.324Z\n"
"POT-Creation-Date: 2022-09-08T10:43:07.553Z\n"
"PO-Revision-Date: 2022-09-08T10:43:07.553Z\n"

msgid "Data values - Create/update"
msgstr ""
Expand Down Expand Up @@ -790,6 +790,9 @@ msgstr ""
msgid "Create theme"
msgstr ""

msgid "Access to Themes"
msgstr ""

msgid "Error deleting data values"
msgstr ""

Expand Down Expand Up @@ -996,7 +999,7 @@ msgstr ""
msgid "data values"
msgstr ""

msgid "Select import Organisation Unit"
msgid "Override import Organisation Unit"
msgstr ""

msgid "No capture org unit match element org units"
Expand Down
8 changes: 6 additions & 2 deletions i18n/es.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Bulk Load\n"
"POT-Creation-Date: 2022-04-29T09:28:31.324Z\n"
"POT-Creation-Date: 2022-09-08T10:43:07.553Z\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -817,6 +817,10 @@ msgstr "Subtítulo"
msgid "Create theme"
msgstr "Crear tema"

#, fuzzy
msgid "Access to Themes"
msgstr "Acceso a plantillas"

msgid "Error deleting data values"
msgstr "Se ha producido un error borrando valores de datos"

Expand Down Expand Up @@ -1039,7 +1043,7 @@ msgstr "Actualizar"
msgid "data values"
msgstr "valores de datos"

msgid "Select import Organisation Unit"
msgid "Override import Organisation Unit"
msgstr "Seleccione una unidad organizativa en la que importar los datos"

msgid "No capture org unit match element org units"
Expand Down
8 changes: 6 additions & 2 deletions i18n/fr.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Bulk Load App\n"
"POT-Creation-Date: 2022-04-29T09:28:31.324Z\n"
"POT-Creation-Date: 2022-09-08T10:43:07.553Z\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -839,6 +839,10 @@ msgstr "Sous-titre"
msgid "Create theme"
msgstr "Créer un thème"

#, fuzzy
msgid "Access to Themes"
msgstr "Accès à la génération de modèles"

msgid "Error deleting data values"
msgstr "Erreur lors de la suppression des valeurs de données"

Expand Down Expand Up @@ -1062,7 +1066,7 @@ msgstr "Mettre à jour"
msgid "data values"
msgstr "valeurs de données"

msgid "Select import Organisation Unit"
msgid "Override import Organisation Unit"
msgstr "Sélectionnez l'unité d'organisation d'importation"

msgid "No capture org unit match element org units"
Expand Down
8 changes: 6 additions & 2 deletions i18n/pt.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Bulk Load\n"
"POT-Creation-Date: 2022-04-29T09:28:31.324Z\n"
"POT-Creation-Date: 2022-09-08T10:43:07.553Z\n"
"Language: pt\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -872,6 +872,10 @@ msgstr "Legenda"
msgid "Create theme"
msgstr "Criar tema"

#, fuzzy
msgid "Access to Themes"
msgstr "Acesso à geração de planilhas"

msgid "Error deleting data values"
msgstr "Erro ao excluir valores de dados"

Expand Down Expand Up @@ -1096,7 +1100,7 @@ msgstr "Atualizar"
msgid "data values"
msgstr "valores de dados"

msgid "Select import Organisation Unit"
msgid "Override import Organisation Unit"
msgstr "Selecione a unidade organizacional para importar os dados"

msgid "No capture org unit match element org units"
Expand Down
8 changes: 6 additions & 2 deletions i18n/ru.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Bulk Load\n"
"POT-Creation-Date: 2022-04-29T09:28:31.324Z\n"
"POT-Creation-Date: 2022-09-08T10:43:07.553Z\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
Expand Down Expand Up @@ -876,6 +876,10 @@ msgstr "Субтитр"
msgid "Create theme"
msgstr "Создать тему"

#, fuzzy
msgid "Access to Themes"
msgstr "Доступ к генерации шаблонов"

msgid "Error deleting data values"
msgstr "Ошибка при удалении значений данных"

Expand Down Expand Up @@ -1100,7 +1104,7 @@ msgstr "Обновление"
msgid "data values"
msgstr "значения данных"

msgid "Select import Organisation Unit"
msgid "Override import Organisation Unit"
msgstr "Выберите импортируемое организационное подразделение"

msgid "No capture org unit match element org units"
Expand Down
2 changes: 2 additions & 0 deletions src/CompositionRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { SaveThemeUseCase } from "./domain/usecases/SaveThemeUseCase";
import { SearchUsersUseCase } from "./domain/usecases/SearchUsersUseCase";
import { WriteSettingsUseCase } from "./domain/usecases/WriteSettingsUseCase";
import { D2Api } from "./types/d2-api";
import { GetFilteredThemesUseCase } from "./domain/usecases/GetFilteredThemesUseCase";

export interface CompositionRootOptions {
appConfig: JsonConfig;
Expand Down Expand Up @@ -85,6 +86,7 @@ export function getCompositionRoot({ appConfig, dhisInstance, mockApi }: Composi
list: new ListThemesUseCase(templateManager),
save: new SaveThemeUseCase(templateManager),
delete: new DeleteThemeUseCase(templateManager),
getFilteredThemes: new GetFilteredThemesUseCase(usersRepository),
}),
settings: getExecute({
getDefault: new GetDefaultSettingsUseCase(config),
Expand Down
4 changes: 3 additions & 1 deletion src/data/Dhis2RelationshipTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,9 @@ async function getConstraintForTypeTei(
fields: "trackedEntityInstance",
} as const;

const results = await promiseMap(_.chunk(query.ou, 250), async ouChunk => {
const orgUnitsChunks = query.ou ? _.chunk(query.ou, 250) : [[]];

const results = await promiseMap(orgUnitsChunks, async ouChunk => {
const filterQuery =
query.ouMode === "SELECTED" || query.ouMode === "CHILDREN" || query.ouMode === "DESCENDANTS"
? { ...query, ou: ouChunk }
Expand Down
37 changes: 27 additions & 10 deletions src/data/Dhis2TrackedEntityInstances.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
PaginatedTeiGetResponse,
TeiGetRequest,
TrackedEntityInstance as TrackedEntityInstanceApi,
TrackedEntityInstanceGeometryAttributes,
TrackedEntityInstanceToPost,
Expand Down Expand Up @@ -175,7 +176,7 @@ async function runSequentialPromisesOnSuccess(

// Private

/* A TEI cannot be posted if it includes relationships to other TEIs which are not created
/* A TEI cannot be posted if it includes relationships to other TEIs which are not created
yet (creation of TEIS is sequential). So let's split pre/post TEI's so they can be
posted separatedly.
*/
Expand Down Expand Up @@ -394,18 +395,34 @@ async function getExistingTeis(api: D2Api): Promise<Ref[]> {
fields: "trackedEntityInstance",
} as const;

const { trackedEntityInstances: firstPage, pager } = await api.trackedEntityInstances.get(query).getData();
const pages = _.range(2, pager.pageCount + 1);
// DHIS 2.37 added a new requirement: "Either Program or Tracked entity type should be specified"
// Requests to /api/trackedEntityInstances for these two params are singled-value, so we must
// perform multiple requests. Use Tracked Entity Types as tipically there will be more programs.

const otherPages = await promiseMap(pages, async page => {
const { trackedEntityInstances } = await api.trackedEntityInstances.get({ ...query, page }).getData();
return trackedEntityInstances;
const metadata = await api.metadata.get({ trackedEntityTypes: { fields: { id: true } } }).getData();

const teisGroups = await promiseMap(metadata.trackedEntityTypes, async entityType => {
const queryWithEntityType: TeiGetRequest = { ...query, trackedEntityType: entityType.id };

const { trackedEntityInstances: firstPage, pager } = await api.trackedEntityInstances
.get(queryWithEntityType)
.getData();
const pages = _.range(2, pager.pageCount + 1);

const otherPages = await promiseMap(pages, async page => {
const { trackedEntityInstances } = await api.trackedEntityInstances
.get({ ...queryWithEntityType, page })
.getData();
return trackedEntityInstances;
});

return [...firstPage, ..._.flatten(otherPages)].map(({ trackedEntityInstance, ...rest }) => ({
...rest,
id: trackedEntityInstance,
}));
});

return [...firstPage, ..._.flatten(otherPages)].map(({ trackedEntityInstance, ...rest }) => ({
...rest,
id: trackedEntityInstance,
}));
return _.flatten(teisGroups);
}

type TeiKey = KeysOfUnion<TrackedEntityInstanceApi>;
Expand Down
3 changes: 2 additions & 1 deletion src/data/ExcelPopulateRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,8 @@ function getFormulaWithValidation(workbook: XLSX.Workbook, sheet: SheetWithValid
}

function _getFormulaWithValidation(workbook: XLSX.Workbook, sheet: SheetWithValidations, cell: XLSX.Cell) {
const defaultValue = cell.formula();
// Formulas some times return the = prefix, which the called does not expect. Force the removal.
const defaultValue = cell.formula()?.replace(/^=/, "");
const value = getValue(cell);
if (defaultValue || !value) return defaultValue;

Expand Down
22 changes: 22 additions & 0 deletions src/domain/entities/Theme.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SharingRule } from "@eyeseetea/d2-ui-components";
import { generateUid } from "d2/uid";
import _ from "lodash";
import { defaultColorScale } from "../../webapp/utils/colors";
Expand All @@ -9,6 +10,13 @@ export type Color = string;
export type ThemeableSections = "title" | "subtitle";
export type ImageSections = "logo";

export type Sharing = {
external: boolean;
public: string;
userGroups: SharingRule[];
users: SharingRule[];
};

export interface ThemeStyle {
text?: string;
bold?: boolean;
Expand All @@ -32,6 +40,13 @@ export interface CellImage {
src: string;
}

const defaultSharing: Sharing = {
external: false,
public: "r-------",
userGroups: [],
users: [],
};

export class Theme {
public readonly id: Id;
public readonly name: string;
Expand All @@ -43,6 +58,7 @@ export class Theme {
public readonly pictures?: {
[key in ImageSections]?: CellImage;
};
public readonly sharing: Sharing;

constructor({
id = generateUid(),
Expand All @@ -51,13 +67,15 @@ export class Theme {
palette = defaultColorScale,
sections = {},
pictures = {},
sharing = defaultSharing,
}: Partial<Theme> = {}) {
this.id = id;
this.name = name;
this.templates = templates;
this.palette = palette;
this.sections = sections;
this.pictures = pictures;
this.sharing = sharing;
}

private update(partialUpdate: Partial<Theme>): Theme {
Expand Down Expand Up @@ -86,6 +104,10 @@ export class Theme {
return this.update({ palette });
}

public updateSharing(sharing: Theme["sharing"]): Theme {
return this.update({ sharing });
}

public validate(): Validation {
return _.pickBy({
name: _.compact([
Expand Down
4 changes: 4 additions & 0 deletions src/domain/helpers/ExcelReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export class ExcelReader {

const values = await promiseMap(cells, async cell => {
const value = cell ? await this.readCellValue(template, cell) : undefined;
const optionId = await this.excelRepository.readCell(template.id, cell, { formula: true });
if (!isDefined(value)) return undefined;

const orgUnit = await this.readCellValue(template, dataSource.orgUnit, cell);
Expand Down Expand Up @@ -152,6 +153,7 @@ export class ExcelReader {
dataElement: this.formatValue(dataElement),
category: category ? this.formatValue(category) : undefined,
value: this.formatValue(value),
optionId: optionId ? removeCharacters(optionId) : undefined,
},
],
};
Expand All @@ -163,6 +165,7 @@ export class ExcelReader {
private async readByCell(template: Template, dataSource: CellDataSource): Promise<DataPackageData[]> {
const cell = await this.excelRepository.findRelativeCell(template.id, dataSource.ref);
const value = cell ? await this.readCellValue(template, cell) : undefined;
const optionId = await this.excelRepository.readCell(template.id, cell, { formula: true });
if (!isDefined(value)) return [];

const orgUnit = await this.readCellValue(template, dataSource.orgUnit);
Expand Down Expand Up @@ -193,6 +196,7 @@ export class ExcelReader {
dataElement: String(dataElement),
category: category ? String(category) : undefined,
value: this.formatValue(value),
optionId: optionId ? removeCharacters(optionId) : undefined,
},
],
},
Expand Down
24 changes: 24 additions & 0 deletions src/domain/usecases/GetFilteredThemesUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { UseCase } from "../../CompositionRoot";
import { Theme } from "../entities/Theme";
import { UsersRepository } from "../repositories/UsersRepository";

export class GetFilteredThemesUseCase implements UseCase {
constructor(private usersRepository: UsersRepository) {}

public async execute(themes: Theme[]): Promise<Theme[]> {
const currentUser = await this.usersRepository.getCurrentUser();
const { userGroups } = currentUser;

const filteredThemes = themes.filter(theme => {
return (
userGroups.some(uG => theme.sharing.userGroups.some(userGroup => userGroup.id === uG.id)) ||
theme.sharing.users.some(user => user.id === currentUser.id) ||
theme.sharing.public !== "--------" ||
theme.sharing.external ||
theme.sharing === undefined
);
});

return filteredThemes;
}
}
Loading

0 comments on commit 2a3a036

Please sign in to comment.