From eeeb7a520d9430d8938f95aea475fa4e2ad2eecd Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 28 Sep 2020 11:36:15 +0200 Subject: [PATCH 01/27] Filter by orgUnit if there are few org units --- src/data/events/EventsD2ApiRepository.ts | 97 +++++++++++++++++++++--- 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/src/data/events/EventsD2ApiRepository.ts b/src/data/events/EventsD2ApiRepository.ts index 28001ea2a..06b26a509 100644 --- a/src/data/events/EventsD2ApiRepository.ts +++ b/src/data/events/EventsD2ApiRepository.ts @@ -11,6 +11,7 @@ import { import { cleanObjectDefault, cleanOrgUnitPaths } from "../../domain/synchronization/utils"; import { DataImportParams } from "../../types/d2"; import { D2Api, Pager } from "../../types/d2-api"; +import { promiseMap } from "../../utils/common"; export class EventsD2ApiRepository implements EventsRepository { private api: D2Api; @@ -24,8 +25,15 @@ export class EventsD2ApiRepository implements EventsRepository { programs: string[] = [], defaults: string[] = [] ): Promise { - if (params.allEvents) return this.getAllEvents(params, programs, defaults); - else return this.getSpecificEvents(params, programs, defaults); + const { allEvents = false, orgUnitPaths = [] } = params; + + if (!allEvents) { + return this.getSpecificEvents(params, programs, defaults); + } else if (allEvents && orgUnitPaths.length < 25) { + return this.getEventsByOrgUnit(params, programs, defaults); + } else { + return this.getAllEvents(params, programs, defaults); + } } /** @@ -51,7 +59,6 @@ export class EventsD2ApiRepository implements EventsRepository { const [startDate, endDate] = buildPeriodFromParams(params); const orgUnits = cleanOrgUnitPaths(orgUnitPaths); - const result = []; const fetchApi = async (program: string, page: number) => { return this.api @@ -66,23 +73,90 @@ export class EventsD2ApiRepository implements EventsRepository { .getData(); }; - for (const program of programs) { + const result = await promiseMap(programs, async program => { const { events, pager } = await fetchApi(program, 1); - result.push(...events); - for (let page = 2; page <= pager.pageCount; page += 1) { - const { events } = await fetchApi(program, page); - result.push(...events); - } - } + const paginatedEvents = await promiseMap( + _.range(2, pager.pageCount + 1), + async page => { + const { events } = await fetchApi(program, page); + return events; + } + ); + + return [...events, ..._.flatten(paginatedEvents)]; + }); return _(result) + .flatten() .filter(({ orgUnit }) => orgUnits.includes(orgUnit)) .map(object => ({ ...object, id: object.event })) .map(object => cleanObjectDefault(object, defaults)) .value(); } + private async getEventsByOrgUnit( + params: DataSynchronizationParams, + programs: string[] = [], + defaults: string[] = [] + ): Promise { + if (programs.length === 0) return []; + + const { period, orgUnitPaths = [] } = params; + const [startDate, endDate] = buildPeriodFromParams(params); + + const orgUnits = cleanOrgUnitPaths(orgUnitPaths); + + const fetchApi = async (program: string, orgUnit: string, page: number) => { + return this.api + .get("/events", { + pageSize: 250, + totalPages: true, + page, + program, + orgUnit, + startDate: period !== "ALL" ? startDate.format("YYYY-MM-DD") : undefined, + endDate: period !== "ALL" ? endDate.format("YYYY-MM-DD") : undefined, + }) + .getData(); + }; + + const result = await promiseMap(programs, async program => { + const filteredEvents = await promiseMap(orgUnits, async orgUnit => { + const { events, pager } = await fetchApi(program, orgUnit, 1); + + const paginatedEvents = await promiseMap( + _.range(2, pager.pageCount + 1), + async page => { + const { events } = await this.api + .get("/events", { + pageSize: 250, + totalPages: true, + page, + program, + startDate: + period !== "ALL" ? startDate.format("YYYY-MM-DD") : undefined, + endDate: + period !== "ALL" ? endDate.format("YYYY-MM-DD") : undefined, + }) + .getData(); + return events; + } + ); + + return [...events, ..._.flatten(paginatedEvents)]; + }); + + return _.flatten(filteredEvents); + }); + + return _(result) + .flatten() + .map(object => ({ ...object, id: object.event })) + .map(object => cleanObjectDefault(object, defaults)) + .value(); + } + private async getSpecificEvents( params: DataSynchronizationParams, programs: string[] = [], @@ -186,7 +260,8 @@ interface EventsPostResponse { }; } +type EventExportType = ProgramEvent & { event: string }; interface EventExportResult { - events: Array; + events: EventExportType[]; pager: Pager; } From 0a4957d34462e57aceb3505cc157abd444eef9c3 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Wed, 30 Sep 2020 08:10:21 +0200 Subject: [PATCH 02/27] Do not remove options from optionset --- src/models/dhis/metadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/dhis/metadata.ts b/src/models/dhis/metadata.ts index dde6fc3c8..ab2a096a2 100644 --- a/src/models/dhis/metadata.ts +++ b/src/models/dhis/metadata.ts @@ -363,7 +363,7 @@ export class OptionModel extends D2Model { protected static metadataType = "option"; protected static collectionName = "options" as const; - protected static excludeRules = ["optionSets.options"]; + protected static excludeRules = []; protected static includeRules = ["attributes", "optionSets", "optionSets.attributes"]; } From 018f5aa29247ad9a387d6d20c340deb81d6467fc Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Wed, 30 Sep 2020 08:32:48 +0200 Subject: [PATCH 03/27] Fix manual pull sync --- .../webapp/pages/manual-sync/ManualSyncPage.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/presentation/webapp/pages/manual-sync/ManualSyncPage.tsx b/src/presentation/webapp/pages/manual-sync/ManualSyncPage.tsx index 596b0b988..0a3b28a20 100644 --- a/src/presentation/webapp/pages/manual-sync/ManualSyncPage.tsx +++ b/src/presentation/webapp/pages/manual-sync/ManualSyncPage.tsx @@ -117,11 +117,13 @@ const ManualSyncPage: React.FC = () => { const updateSelection = useCallback( (selection: string[], exclusion: string[]) => { - const syncRule = SyncRule.createOnDemand(type) - .updateMetadataIds(selection) - .updateExcludedIds(exclusion); - - updateSyncRule(syncRule); + updateSyncRule(({ originInstance, targetInstances }) => + SyncRule.createOnDemand(type) + .updateBuilder({ originInstance }) + .updateTargetInstances(targetInstances) + .updateMetadataIds(selection) + .updateExcludedIds(exclusion) + ); }, [type] ); From f38289b42a4bc04c25007b1472ec0742a5a155dc Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Wed, 30 Sep 2020 08:40:28 +0200 Subject: [PATCH 04/27] Fix sync rule syncing --- .../react/components/sync-wizard/common/GeneralInfoStep.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presentation/react/components/sync-wizard/common/GeneralInfoStep.tsx b/src/presentation/react/components/sync-wizard/common/GeneralInfoStep.tsx index c240bf6ed..da4b6e5d4 100644 --- a/src/presentation/react/components/sync-wizard/common/GeneralInfoStep.tsx +++ b/src/presentation/react/components/sync-wizard/common/GeneralInfoStep.tsx @@ -32,7 +32,7 @@ export const GeneralInfoStep = ({ syncRule, onChange }: SyncWizardStepProps) => const onChangeInstance = useCallback( (_type: InstanceSelectionOption, instance?: Instance) => { const originInstance = instance?.id ?? "LOCAL"; - const targetInstances = originInstance === "LOCAL" ? ["LOCAL"] : []; + const targetInstances = originInstance === "LOCAL" ? [] : ["LOCAL"]; onChange( syncRule From 881db850c8595822f20519838356e261c8cbce74 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Wed, 30 Sep 2020 12:55:54 +0200 Subject: [PATCH 05/27] Add includeParents check --- .../react/components/metadata-table/MetadataTable.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/presentation/react/components/metadata-table/MetadataTable.tsx b/src/presentation/react/components/metadata-table/MetadataTable.tsx index 4a00eece1..973dbfd67 100644 --- a/src/presentation/react/components/metadata-table/MetadataTable.tsx +++ b/src/presentation/react/components/metadata-table/MetadataTable.tsx @@ -406,10 +406,11 @@ const MetadataTable: React.FC = ({ useEffect(() => { if (model.getCollectionName() === "organisationUnits" && !filters.parents) return; const fields = model.getFields(); + const includeParents = model.getCollectionName() === "organisationUnits"; setLoading(true); compositionRoot.metadata - .list({ ...filters, filterRows, fields, includeParents: true }, remoteInstance) + .list({ ...filters, filterRows, fields, includeParents }, remoteInstance) .then(({ objects, pager }) => { const rows = model.getApiModelTransform()((objects as unknown) as MetadataType[]); notifyRowsChange(rows); From ccee085d5f68bec5a85756d0bee6b4fad0e51861 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Wed, 30 Sep 2020 13:19:39 +0200 Subject: [PATCH 06/27] Add property to include/exclude org units from metadata sync --- src/domain/modules/entities/MetadataModule.ts | 5 +++++ src/models/syncRule.ts | 2 ++ .../metadata/AdvancedMetadataOptionsStep.tsx | 11 +++++++++++ .../sync-params-selector/SyncParamsSelector.tsx | 14 ++++++++++++++ src/types/synchronization.ts | 1 + 5 files changed, 33 insertions(+) diff --git a/src/domain/modules/entities/MetadataModule.ts b/src/domain/modules/entities/MetadataModule.ts index 1515bf426..f9f32da6c 100644 --- a/src/domain/modules/entities/MetadataModule.ts +++ b/src/domain/modules/entities/MetadataModule.ts @@ -17,6 +17,7 @@ interface BaseMetadataModule extends BaseModule { metadataIds: string[]; excludedIds: string[]; includeUserInformation: boolean; + removeOrgUnitReferences: boolean; useDefaultIncludeExclude: boolean; metadataIncludeExcludeRules?: MetadataIncludeExcludeRules; } @@ -25,6 +26,7 @@ export class MetadataModule extends GenericModule implements BaseMetadataModule public readonly metadataIds: string[]; public readonly excludedIds: string[]; public readonly includeUserInformation: boolean; + public readonly removeOrgUnitReferences: boolean; public readonly useDefaultIncludeExclude: boolean; public readonly metadataIncludeExcludeRules: MetadataIncludeExcludeRules; public readonly type = "metadata"; @@ -34,6 +36,7 @@ export class MetadataModule extends GenericModule implements BaseMetadataModule this.metadataIds = data.metadataIds; this.excludedIds = data.excludedIds; this.includeUserInformation = data.includeUserInformation; + this.removeOrgUnitReferences = data.removeOrgUnitReferences; this.useDefaultIncludeExclude = data.useDefaultIncludeExclude; this.metadataIncludeExcludeRules = data.metadataIncludeExcludeRules; } @@ -53,6 +56,7 @@ export class MetadataModule extends GenericModule implements BaseMetadataModule excludedIds: this.excludedIds, syncParams: { enableMapping: true, + removeOrgUnitReferences: this.removeOrgUnitReferences, includeSharingSettings: this.includeUserInformation, useDefaultIncludeExclude: this.useDefaultIncludeExclude, metadataIncludeExcludeRules: this.metadataIncludeExcludeRules, @@ -150,6 +154,7 @@ export class MetadataModule extends GenericModule implements BaseMetadataModule ...GenericModule.buildDefaultValues(), metadataIds: [], excludedIds: [], + removeOrgUnitReferences: false, includeUserInformation: false, useDefaultIncludeExclude: true, metadataIncludeExcludeRules: {}, diff --git a/src/models/syncRule.ts b/src/models/syncRule.ts index 8f7b2605e..481a7e466 100644 --- a/src/models/syncRule.ts +++ b/src/models/syncRule.ts @@ -55,6 +55,7 @@ const defaultSynchronizationBuilder: SynchronizationBuilder = { importStrategy: "CREATE_AND_UPDATE", enableMapping: false, includeSharingSettings: true, + removeOrgUnitReferences: false, useDefaultIncludeExclude: true, atomicMode: "ALL", mergeMode: "MERGE", @@ -244,6 +245,7 @@ export default class SyncRule { return { enableMapping: false, includeSharingSettings: true, + removeOrgUnitReferences: false, useDefaultIncludeExclude: true, ...params, }; diff --git a/src/presentation/react/components/module-wizard/metadata/AdvancedMetadataOptionsStep.tsx b/src/presentation/react/components/module-wizard/metadata/AdvancedMetadataOptionsStep.tsx index 57d72d8bf..6227c9c79 100644 --- a/src/presentation/react/components/module-wizard/metadata/AdvancedMetadataOptionsStep.tsx +++ b/src/presentation/react/components/module-wizard/metadata/AdvancedMetadataOptionsStep.tsx @@ -12,6 +12,10 @@ export const AdvancedMetadataOptionsStep: React.FC { + onChange(module.update({ removeOrgUnitReferences })); + }; + return (
@@ -21,6 +25,13 @@ export const AdvancedMetadataOptionsStep: React.FC
+
+ +
); }; diff --git a/src/presentation/react/components/sync-params-selector/SyncParamsSelector.tsx b/src/presentation/react/components/sync-params-selector/SyncParamsSelector.tsx index 877731bb2..b6649d0ab 100644 --- a/src/presentation/react/components/sync-params-selector/SyncParamsSelector.tsx +++ b/src/presentation/react/components/sync-params-selector/SyncParamsSelector.tsx @@ -35,6 +35,10 @@ const SyncParamsSelector: React.FC = ({ ); }; + const changeOrgUnitReferences = (removeOrgUnitReferences: boolean) => { + onChange(syncRule.updateSyncParams({ ...syncParams, removeOrgUnitReferences })); + }; + const changeAtomic = (value: boolean) => { onChange( syncRule.updateSyncParams({ @@ -126,6 +130,16 @@ const SyncParamsSelector: React.FC = ({ )} + {syncRule.type === "metadata" && ( +
+ +
+ )} + {syncRule.type === "metadata" && (
Date: Fri, 2 Oct 2020 14:20:40 +0200 Subject: [PATCH 07/27] Use d2-api with fetch backend --- .../aggregated/AggregatedD2ApiRepository.ts | 3 ++- src/data/events/EventsD2ApiRepository.ts | 3 ++- src/data/instance/InstanceD2ApiRepository.ts | 3 ++- src/data/metadata/MetadataD2ApiRepository.ts | 3 ++- src/data/storage/StorageDataStoreRepository.ts | 3 ++- .../usecases/GenericSyncUseCase.ts | 3 ++- src/migrations/cli.ts | 2 -- .../components/metadata-table/MetadataTable.tsx | 4 ++-- src/presentation/react/contexts/UseD2ApiData.ts | 5 +++-- src/presentation/webapp/WebApp.jsx | 4 ---- src/presentation/widget/WidgetApp.jsx | 4 ---- src/scheduler/cli.ts | 2 -- src/utils/analytics.ts | 4 ++-- src/utils/common.ts | 7 +++++++ src/utils/d2-utils.ts | 17 +++++++++++++++++ 15 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/data/aggregated/AggregatedD2ApiRepository.ts b/src/data/aggregated/AggregatedD2ApiRepository.ts index e9fe481a8..60cbdde7f 100644 --- a/src/data/aggregated/AggregatedD2ApiRepository.ts +++ b/src/data/aggregated/AggregatedD2ApiRepository.ts @@ -13,12 +13,13 @@ import { cleanOrgUnitPaths } from "../../domain/synchronization/utils"; import { DataImportParams } from "../../types/d2"; import { D2Api, DataValueSetsPostResponse } from "../../types/d2-api"; import { promiseMap } from "../../utils/common"; +import { getD2APiFromInstance } from "../../utils/d2-utils"; export class AggregatedD2ApiRepository implements AggregatedRepository { private api: D2Api; constructor(private instance: Instance) { - this.api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + this.api = getD2APiFromInstance(instance); } public async getAggregated( diff --git a/src/data/events/EventsD2ApiRepository.ts b/src/data/events/EventsD2ApiRepository.ts index 28001ea2a..2702acb0d 100644 --- a/src/data/events/EventsD2ApiRepository.ts +++ b/src/data/events/EventsD2ApiRepository.ts @@ -11,12 +11,13 @@ import { import { cleanObjectDefault, cleanOrgUnitPaths } from "../../domain/synchronization/utils"; import { DataImportParams } from "../../types/d2"; import { D2Api, Pager } from "../../types/d2-api"; +import { getD2APiFromInstance } from "../../utils/d2-utils"; export class EventsD2ApiRepository implements EventsRepository { private api: D2Api; constructor(private instance: Instance) { - this.api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + this.api = getD2APiFromInstance(instance); } public async getEvents( diff --git a/src/data/instance/InstanceD2ApiRepository.ts b/src/data/instance/InstanceD2ApiRepository.ts index d2cf1094f..bc42c8847 100644 --- a/src/data/instance/InstanceD2ApiRepository.ts +++ b/src/data/instance/InstanceD2ApiRepository.ts @@ -10,12 +10,13 @@ import { } from "../../domain/metadata/entities/MetadataEntities"; import { D2Api } from "../../types/d2-api"; import { cache } from "../../utils/cache"; +import { getD2APiFromInstance } from "../../utils/d2-utils"; export class InstanceD2ApiRepository implements InstanceRepository { private api: D2Api; constructor(instance: Instance) { - this.api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + this.api = getD2APiFromInstance(instance); } public getApi(): D2Api { diff --git a/src/data/metadata/MetadataD2ApiRepository.ts b/src/data/metadata/MetadataD2ApiRepository.ts index ecce39abe..8c7e01903 100644 --- a/src/data/metadata/MetadataD2ApiRepository.ts +++ b/src/data/metadata/MetadataD2ApiRepository.ts @@ -34,6 +34,7 @@ import { } from "../../domain/metadata/entities/FilterRule"; import { modelFactory } from "../../models/dhis/factory"; import { buildPeriodFromParams } from "../../domain/aggregated/utils"; +import { getD2APiFromInstance } from "../../utils/d2-utils"; export class MetadataD2ApiRepository implements MetadataRepository { private api: D2Api; @@ -42,7 +43,7 @@ export class MetadataD2ApiRepository implements MetadataRepository { private instance: Instance, private transformationRepository: TransformationRepository ) { - this.api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + this.api = getD2APiFromInstance(instance); } /** diff --git a/src/data/storage/StorageDataStoreRepository.ts b/src/data/storage/StorageDataStoreRepository.ts index d310cdce3..68010613d 100644 --- a/src/data/storage/StorageDataStoreRepository.ts +++ b/src/data/storage/StorageDataStoreRepository.ts @@ -1,6 +1,7 @@ import { Instance } from "../../domain/instance/entities/Instance"; import { StorageRepository } from "../../domain/storage/repositories/StorageRepository"; import { D2Api, DataStore } from "../../types/d2-api"; +import { getD2APiFromInstance } from "../../utils/d2-utils"; const dataStoreNamespace = "metadata-synchronization"; @@ -10,7 +11,7 @@ export class StorageDataStoreRepository extends StorageRepository { constructor(instance: Instance) { super(); - this.api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + this.api = getD2APiFromInstance(instance); this.dataStore = this.api.dataStore(dataStoreNamespace); } diff --git a/src/domain/synchronization/usecases/GenericSyncUseCase.ts b/src/domain/synchronization/usecases/GenericSyncUseCase.ts index 50a246aba..f0e964cf6 100644 --- a/src/domain/synchronization/usecases/GenericSyncUseCase.ts +++ b/src/domain/synchronization/usecases/GenericSyncUseCase.ts @@ -35,6 +35,7 @@ import { } from "../entities/SynchronizationReport"; import { SynchronizationResult, SynchronizationStatus } from "../entities/SynchronizationResult"; import { SynchronizationType } from "../entities/SynchronizationType"; +import { getD2APiFromInstance } from "../../../utils/d2-utils"; export type SyncronizationClass = | typeof MetadataSyncUseCase @@ -54,7 +55,7 @@ export abstract class GenericSyncUseCase { protected readonly localInstance: Instance, protected readonly encryptionKey: string ) { - this.api = new D2Api({ baseUrl: localInstance.url, auth: localInstance.auth }); + this.api = getD2APiFromInstance(localInstance); } public abstract async buildPayload(): Promise; diff --git a/src/migrations/cli.ts b/src/migrations/cli.ts index 16441a286..b64d3dd09 100644 --- a/src/migrations/cli.ts +++ b/src/migrations/cli.ts @@ -1,4 +1,3 @@ -import axiosRetry from "axios-retry"; import { D2Api } from "../types/d2-api"; import { debug } from "../utils/debug"; import { MigrationsRunner } from "./index"; @@ -8,7 +7,6 @@ async function main() { const [baseUrl] = process.argv.slice(2); if (!baseUrl) throw new Error("Usage: index.ts DHIS2_URL"); const api = new D2Api({ baseUrl: baseUrl }); - axiosRetry(api.connection, { retries: 3 }); const runner = await MigrationsRunner.init({ api, debug, migrations: migrationTasks }); runner.execute(); } diff --git a/src/presentation/react/components/metadata-table/MetadataTable.tsx b/src/presentation/react/components/metadata-table/MetadataTable.tsx index 4a00eece1..b5eadda5b 100644 --- a/src/presentation/react/components/metadata-table/MetadataTable.tsx +++ b/src/presentation/react/components/metadata-table/MetadataTable.tsx @@ -1,6 +1,5 @@ import { Checkbox, FormControlLabel, Icon, makeStyles } from "@material-ui/core"; import DoneAllIcon from "@material-ui/icons/DoneAll"; -import axios from "axios"; import { DatePicker, ObjectsTable, @@ -30,6 +29,7 @@ import { useAppContext } from "../../contexts/AppContext"; import Dropdown from "../dropdown/Dropdown"; import { ResponsibleDialog } from "../responsible-dialog/ResponsibleDialog"; import { getFilterData, getOrgUnitSubtree } from "./utils"; +import { isCancel } from "../../../../utils/common"; interface MetadataTableProps extends Omit, "rows" | "columns"> { remoteInstance?: Instance; @@ -326,7 +326,7 @@ const MetadataTable: React.FC = ({ const handleError = useCallback( (error: Error) => { - if (!axios.isCancel(error)) { + if (!isCancel(error)) { snackbar.error(error.message); setRows([]); setPager({}); diff --git a/src/presentation/react/contexts/UseD2ApiData.ts b/src/presentation/react/contexts/UseD2ApiData.ts index 1a2415a52..bae8b4ac2 100644 --- a/src/presentation/react/contexts/UseD2ApiData.ts +++ b/src/presentation/react/contexts/UseD2ApiData.ts @@ -1,6 +1,7 @@ -import axios, { Canceler } from "axios"; +import { Canceler } from "axios"; import { useCallback, useEffect, useState } from "react"; import { D2ApiResponse } from "../../../types/d2-api"; +import { isCancel } from "../../../utils/common"; export type D2ApiDataHookQuery = Pick, "cancel" | "getData">; @@ -26,7 +27,7 @@ export const useD2ApiData = (apiQuery?: D2ApiDataHookQuery): D2ApiDataHook setState({ loading: false, data }); }) .catch(error => { - if (!axios.isCancel(error)) { + if (isCancel(error)) { setState({ loading: false, error }); console.error(error); } diff --git a/src/presentation/webapp/WebApp.jsx b/src/presentation/webapp/WebApp.jsx index 36ccbc3db..65d0e9434 100644 --- a/src/presentation/webapp/WebApp.jsx +++ b/src/presentation/webapp/WebApp.jsx @@ -2,7 +2,6 @@ import { useConfig } from "@dhis2/app-runtime"; import { HeaderBar } from "@dhis2/ui-widgets"; import { MuiThemeProvider } from "@material-ui/core/styles"; import { createGenerateClassName, StylesProvider } from "@material-ui/styles"; -import axiosRetry from "axios-retry"; import { init } from "d2"; import { LoadingProvider, SnackbarProvider } from "d2-ui-components"; import _ from "lodash"; @@ -23,8 +22,6 @@ import Share from "../react/components/share/Share"; import Root from "./pages/Root"; import "./WebApp.css"; -const axiosMaxRetries = 3; - const generateClassName = createGenerateClassName({ productionPrefix: "c", }); @@ -111,7 +108,6 @@ const App = () => { }; async function runMigrations(api) { - axiosRetry(api.connection, { retries: axiosMaxRetries }); const runner = await MigrationsRunner.init({ api, debug: debug }); if (runner.hasPendingMigrations()) { diff --git a/src/presentation/widget/WidgetApp.jsx b/src/presentation/widget/WidgetApp.jsx index cc0bbbb3b..4ad6b70dc 100644 --- a/src/presentation/widget/WidgetApp.jsx +++ b/src/presentation/widget/WidgetApp.jsx @@ -1,7 +1,6 @@ import { useConfig } from "@dhis2/app-runtime"; import { MuiThemeProvider } from "@material-ui/core/styles"; import { createGenerateClassName, StylesProvider } from "@material-ui/styles"; -import axiosRetry from "axios-retry"; import { init } from "d2"; import { LoadingProvider, SnackbarProvider } from "d2-ui-components"; import OldMuiThemeProvider from "material-ui/styles/MuiThemeProvider"; @@ -18,8 +17,6 @@ import { CompositionRoot } from "../CompositionRoot"; import Root from "./pages/Root"; import "./WidgetApp.css"; -const axiosMaxRetries = 3; - const generateClassName = createGenerateClassName({ productionPrefix: "c", }); @@ -79,7 +76,6 @@ const App = () => { }; async function runMigrations(api) { - axiosRetry(api.connection, { retries: axiosMaxRetries }); const runner = await MigrationsRunner.init({ api, debug: debug }); if (runner.hasPendingMigrations()) { diff --git a/src/scheduler/cli.ts b/src/scheduler/cli.ts index 811afb4aa..c43317ce5 100644 --- a/src/scheduler/cli.ts +++ b/src/scheduler/cli.ts @@ -1,4 +1,3 @@ -import axiosRetry from "axios-retry"; import "dotenv/config"; import fs from "fs"; import { configure, getLogger } from "log4js"; @@ -37,7 +36,6 @@ const { config } = yargs }).argv; const checkMigrations = async (api: D2Api) => { - axiosRetry(api.connection, { retries: 3 }); const debug = getLogger("migrations").debug; const runner = await MigrationsRunner.init({ api, debug, migrations: migrationTasks }); if (runner.hasPendingMigrations()) { diff --git a/src/utils/analytics.ts b/src/utils/analytics.ts index 1daf85072..a54527132 100644 --- a/src/utils/analytics.ts +++ b/src/utils/analytics.ts @@ -1,6 +1,6 @@ -import { D2Api } from "d2-api/2.30"; import { Instance } from "../domain/instance/entities/Instance"; import i18n from "../locales"; +import { getD2APiFromInstance } from "./d2-utils"; const timeout = (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)); @@ -8,7 +8,7 @@ const timeout = (ms: number) => { export async function* executeAnalytics(instance: Instance) { yield i18n.t("Running analytics for instance {{name}}", instance); - const api = new D2Api({ baseUrl: instance.url, auth: instance.auth }); + const api = getD2APiFromInstance(instance); const { response } = await api.analytics.run().getData(); diff --git a/src/utils/common.ts b/src/utils/common.ts index 9afc464f2..c72986522 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -1,3 +1,5 @@ +import Axios from "axios"; + /* Map sequentially over T[] with an asynchronous function and return array of mapped values */ export function promiseMap(inputValues: T[], mapper: (value: T) => Promise): Promise { const reducer = (acc$: Promise, inputValue: T): Promise => @@ -9,3 +11,8 @@ export function promiseMap(inputValues: T[], mapper: (value: T) => Promise ); return inputValues.reduce(reducer, Promise.resolve([])); } + +export function isCancel(error: any) { + // Support axios and fetch backends. Probably should be moved to api.isCancel. + return Axios.isCancel(error) || (error && error.name === "AbortError"); +} diff --git a/src/utils/d2-utils.ts b/src/utils/d2-utils.ts index 8d409790b..47bfeab31 100644 --- a/src/utils/d2-utils.ts +++ b/src/utils/d2-utils.ts @@ -1,7 +1,24 @@ import _ from "lodash"; +import { D2Api } from "../types/d2-api"; +import { Instance } from "../domain/instance/entities/Instance"; export function getMajorVersion(version: string): number { const apiVersion = _.get(version.split("."), 1); if (!apiVersion) throw new Error(`Invalid version: ${version}`); return Number(apiVersion); } + +export function getD2APiFromInstance(instance: Instance) { + /* + Problem: If we use Axios (XMLHttpRequest.withCredentials option), the session is lost when + connecting to an instance in the same domain (even with a different path prefix or port). + + Solution: Use fetch API (now supported by d2-api), so it sends credentials=omit when auth is passed. + + Documentation: + + https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials + https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials + */ + return new D2Api({ baseUrl: instance.url, auth: instance.auth, backend: "fetch" }); +} From c147191280edfa553a0b93ff7e5c14f357352e4b Mon Sep 17 00:00:00 2001 From: Arnau Sanchez Date: Fri, 2 Oct 2020 14:32:40 +0200 Subject: [PATCH 08/27] Update d2-api --- package.json | 3 +-- yarn.lock | 52 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index ead4127f5..98164dccc 100644 --- a/package.json +++ b/package.json @@ -24,12 +24,11 @@ "@material-ui/styles": "4.10.0", "@octokit/rest": "18.0.0", "axios": "0.19.2", - "axios-retry": "3.1.8", "btoa": "1.2.1", "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.1.0", + "d2-api": "1.2.0-beta.1", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/yarn.lock b/yarn.lock index 864ea5ea3..b094e4746 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,6 +2766,13 @@ abab@^2.0.0, abab@^2.0.3: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.4.tgz#6dfa57b417ca06d21b2478f0e638302f99c2405c" integrity sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -3331,21 +3338,14 @@ axios-debug-log@^0.6.2: "@types/debug" "^4.0.0" debug "^4.0.0" -axios-mock-adapter@^1.17.0: +axios-mock-adapter@1.18.2: version "1.18.2" - resolved "https://registry.yarnpkg.com/axios-mock-adapter/-/axios-mock-adapter-1.18.2.tgz#01fa9e88e692e8f1bbc1ad1200dde672486e03c7" + resolved "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.18.2.tgz#01fa9e88e692e8f1bbc1ad1200dde672486e03c7" integrity sha512-e5aTsPy2Viov22zNpFTlid76W1Scz82pXeEwwCXdtO85LROhHAF8pHF2qDhiyMONLxKyY3lQ+S4UCsKgrlx8Hw== dependencies: fast-deep-equal "^3.1.1" is-buffer "^2.0.3" -axios-retry@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.8.tgz#ffcfed757e1fab8cbf832f8505bb0e0af47c520c" - integrity sha512-yPw5Y4Bg6Dgmhm35KaJFtlh23s1TecW0HsUerK4/IS1UKl0gtN2aJqdEKtVomiOS/bDo5w4P3sqgki/M10eF8Q== - dependencies: - is-retry-allowed "^1.1.0" - axios@0.19.2: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" @@ -4843,6 +4843,13 @@ cronstrue@^1.81.0: resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-1.96.0.tgz#10379b50e9a638965ea03bb9c854e9dadeaa79e3" integrity sha512-kNuuN0AXqspm+jlpwiecFSFBrG5dYBaL5EaW5MEjGAh4IFT/jbKwKCNhzWb8N5NulKQUHEDN7w98GjoAm6PmMg== +cross-fetch@^3.0.6: + version "3.0.6" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" + integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + dependencies: + node-fetch "2.6.1" + cross-spawn@7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" @@ -5201,22 +5208,24 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.1.0.tgz#317d4b26a59b42b00199a8f6e2302c30c23cdfa7" - integrity sha512-KjYsL1U3i6vg8m4EmzepT5EjJRvoujqIkJ1OjdKF8FxMcpemCquY2Upps7zq995Y85t6kvuKYOUBoEULX+2znw== +d2-api@1.2.0-beta.1: + version "1.2.0-beta.1" + resolved "https://registry.npmjs.org/d2-api/-/d2-api-1.2.0-beta.1.tgz#080527a81693af2e026699ae4501af14c338de7b" + integrity sha512-8E6HKTSnYqv9WgkX4WEhH5R9aHi6t10A7b1SL4nL87aMDRDuw8PVCivbAovEK9MS3DQTp8AO6vAT2zI6tUQDzg== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5" "@types/argparse" "^1.0.36" "@types/prettier" "^1.18.3" "@types/qs" "^6.5.3" + abort-controller "^3.0.0" argparse "^1.0.10" axios "0.19.2" axios-debug-log "^0.6.2" - axios-mock-adapter "^1.17.0" + axios-mock-adapter "1.18.2" btoa "^1.2.1" cronstrue "^1.81.0" + cross-fetch "^3.0.6" cryptr "^4.0.2" d2 "^31.8.1" dotenv "^8.0.0" @@ -6421,6 +6430,11 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + eventemitter2@6.4.2: version "6.4.2" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.2.tgz#f31f8b99d45245f0edbc5b00797830ff3b388970" @@ -8427,11 +8441,6 @@ is-resolvable@^1.0.0: resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== -is-retry-allowed@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - is-root@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" @@ -10973,6 +10982,11 @@ no-case@^3.0.3: lower-case "^2.0.1" tslib "^1.10.0" +node-fetch@2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" From 95540b90f7ea28100662c7246e020aea8966645a Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 08:55:05 +0200 Subject: [PATCH 09/27] Updates about cancellable responses --- package.json | 2 +- .../metadata-table/MetadataTable.tsx | 5 +- .../data/CategoryOptionsSelectionStep.tsx | 2 +- .../react/contexts/UseD2ApiData.ts | 48 ------------------- src/utils/common.ts | 7 --- yarn.lock | 21 ++------ 6 files changed, 8 insertions(+), 77 deletions(-) delete mode 100644 src/presentation/react/contexts/UseD2ApiData.ts diff --git a/package.json b/package.json index 98164dccc..576f8776a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.2.0-beta.1", + "d2-api": "1.2.0-beta.4", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/src/presentation/react/components/metadata-table/MetadataTable.tsx b/src/presentation/react/components/metadata-table/MetadataTable.tsx index b5eadda5b..eeb111471 100644 --- a/src/presentation/react/components/metadata-table/MetadataTable.tsx +++ b/src/presentation/react/components/metadata-table/MetadataTable.tsx @@ -1,5 +1,6 @@ import { Checkbox, FormControlLabel, Icon, makeStyles } from "@material-ui/core"; import DoneAllIcon from "@material-ui/icons/DoneAll"; +import { isCancel } from "d2-api"; import { DatePicker, ObjectsTable, @@ -12,7 +13,7 @@ import { TablePagination, TableSelection, TableState, - useSnackbar, + useSnackbar } from "d2-ui-components"; import _ from "lodash"; import React, { ChangeEvent, ReactNode, useCallback, useEffect, useState } from "react"; @@ -29,8 +30,6 @@ import { useAppContext } from "../../contexts/AppContext"; import Dropdown from "../dropdown/Dropdown"; import { ResponsibleDialog } from "../responsible-dialog/ResponsibleDialog"; import { getFilterData, getOrgUnitSubtree } from "./utils"; -import { isCancel } from "../../../../utils/common"; - interface MetadataTableProps extends Omit, "rows" | "columns"> { remoteInstance?: Instance; filterRows?: string[]; diff --git a/src/presentation/react/components/sync-wizard/data/CategoryOptionsSelectionStep.tsx b/src/presentation/react/components/sync-wizard/data/CategoryOptionsSelectionStep.tsx index 7bd5a014b..89bc47963 100644 --- a/src/presentation/react/components/sync-wizard/data/CategoryOptionsSelectionStep.tsx +++ b/src/presentation/react/components/sync-wizard/data/CategoryOptionsSelectionStep.tsx @@ -1,9 +1,9 @@ +import { useD2ApiData } from "d2-api"; import { MultiSelector } from "d2-ui-components"; import _ from "lodash"; import React, { useMemo } from "react"; import i18n from "../../../../../locales"; import { useAppContext } from "../../../contexts/AppContext"; -import { useD2ApiData } from "../../../contexts/UseD2ApiData"; import { Toggle } from "../../toggle/Toggle"; import { SyncWizardStepProps } from "../Steps"; diff --git a/src/presentation/react/contexts/UseD2ApiData.ts b/src/presentation/react/contexts/UseD2ApiData.ts deleted file mode 100644 index bae8b4ac2..000000000 --- a/src/presentation/react/contexts/UseD2ApiData.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Canceler } from "axios"; -import { useCallback, useEffect, useState } from "react"; -import { D2ApiResponse } from "../../../types/d2-api"; -import { isCancel } from "../../../utils/common"; - -export type D2ApiDataHookQuery = Pick, "cancel" | "getData">; - -interface D2ApiDataHookState { - loading: boolean; - data?: Data; - error?: Error; -} - -interface D2ApiDataHookResponse extends D2ApiDataHookState { - refetch(query: D2ApiDataHookQuery): Canceler; -} - -export const useD2ApiData = (apiQuery?: D2ApiDataHookQuery): D2ApiDataHookResponse => { - const [query, setQuery] = useState | undefined>(apiQuery); - const [state, setState] = useState>({ loading: true }); - - useEffect(() => { - if (!query) return; - query - .getData() - .then(data => { - setState({ loading: false, data }); - }) - .catch(error => { - if (isCancel(error)) { - setState({ loading: false, error }); - console.error(error); - } - }); - return query.cancel; - }, [query, setState]); - - const refetch = useCallback( - (newQuery: D2ApiDataHookQuery) => { - setState((prevState: D2ApiDataHookState) => ({ ...prevState, loading: true })); - setQuery(newQuery); - return newQuery.cancel; - }, - [setState, setQuery] - ); - - return { ...state, refetch }; -}; diff --git a/src/utils/common.ts b/src/utils/common.ts index c72986522..9afc464f2 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -1,5 +1,3 @@ -import Axios from "axios"; - /* Map sequentially over T[] with an asynchronous function and return array of mapped values */ export function promiseMap(inputValues: T[], mapper: (value: T) => Promise): Promise { const reducer = (acc$: Promise, inputValue: T): Promise => @@ -11,8 +9,3 @@ export function promiseMap(inputValues: T[], mapper: (value: T) => Promise ); return inputValues.reduce(reducer, Promise.resolve([])); } - -export function isCancel(error: any) { - // Support axios and fetch backends. Probably should be moved to api.isCancel. - return Axios.isCancel(error) || (error && error.name === "AbortError"); -} diff --git a/yarn.lock b/yarn.lock index b094e4746..71cc74c03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4843,13 +4843,6 @@ cronstrue@^1.81.0: resolved "https://registry.yarnpkg.com/cronstrue/-/cronstrue-1.96.0.tgz#10379b50e9a638965ea03bb9c854e9dadeaa79e3" integrity sha512-kNuuN0AXqspm+jlpwiecFSFBrG5dYBaL5EaW5MEjGAh4IFT/jbKwKCNhzWb8N5NulKQUHEDN7w98GjoAm6PmMg== -cross-fetch@^3.0.6: - version "3.0.6" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" - integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== - dependencies: - node-fetch "2.6.1" - cross-spawn@7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" @@ -5208,10 +5201,10 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.2.0-beta.1: - version "1.2.0-beta.1" - resolved "https://registry.npmjs.org/d2-api/-/d2-api-1.2.0-beta.1.tgz#080527a81693af2e026699ae4501af14c338de7b" - integrity sha512-8E6HKTSnYqv9WgkX4WEhH5R9aHi6t10A7b1SL4nL87aMDRDuw8PVCivbAovEK9MS3DQTp8AO6vAT2zI6tUQDzg== +d2-api@1.2.0-beta.4: + version "1.2.0-beta.4" + resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.4.tgz#7c75b527e55c36c041aef24a79b71fa1e41264da" + integrity sha512-cvmmlVS1N07XrpPvA1+2URW88ojMuU15t1mHUz7WiWnM+uphzlKXF7/k/gxuodc5tNcG4hKTsTH2Xwp51QzIXA== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5" @@ -5225,7 +5218,6 @@ d2-api@1.2.0-beta.1: axios-mock-adapter "1.18.2" btoa "^1.2.1" cronstrue "^1.81.0" - cross-fetch "^3.0.6" cryptr "^4.0.2" d2 "^31.8.1" dotenv "^8.0.0" @@ -10982,11 +10974,6 @@ no-case@^3.0.3: lower-case "^2.0.1" tslib "^1.10.0" -node-fetch@2.6.1: - version "2.6.1" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" - integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== - node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" From 61cd95b33bd477b643c100b0bb1d6cad3dd191aa Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 08:57:13 +0200 Subject: [PATCH 10/27] Prettify code --- .../react/components/metadata-table/MetadataTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presentation/react/components/metadata-table/MetadataTable.tsx b/src/presentation/react/components/metadata-table/MetadataTable.tsx index eeb111471..51994bd45 100644 --- a/src/presentation/react/components/metadata-table/MetadataTable.tsx +++ b/src/presentation/react/components/metadata-table/MetadataTable.tsx @@ -13,7 +13,7 @@ import { TablePagination, TableSelection, TableState, - useSnackbar + useSnackbar, } from "d2-ui-components"; import _ from "lodash"; import React, { ChangeEvent, ReactNode, useCallback, useEffect, useState } from "react"; From 4e8d14c2f3ab1e3ead8bb1f63869836153893f0d Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 08:58:02 +0200 Subject: [PATCH 11/27] Re-add missing empty line --- .../react/components/metadata-table/MetadataTable.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/presentation/react/components/metadata-table/MetadataTable.tsx b/src/presentation/react/components/metadata-table/MetadataTable.tsx index 51994bd45..b341c6f1c 100644 --- a/src/presentation/react/components/metadata-table/MetadataTable.tsx +++ b/src/presentation/react/components/metadata-table/MetadataTable.tsx @@ -30,6 +30,7 @@ import { useAppContext } from "../../contexts/AppContext"; import Dropdown from "../dropdown/Dropdown"; import { ResponsibleDialog } from "../responsible-dialog/ResponsibleDialog"; import { getFilterData, getOrgUnitSubtree } from "./utils"; + interface MetadataTableProps extends Omit, "rows" | "columns"> { remoteInstance?: Instance; filterRows?: string[]; From ff71a4f592de8f7521eb80b04b3d1b18f7ba9299 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 09:03:09 +0200 Subject: [PATCH 12/27] Update all usages to fetch backend --- src/index.js | 2 +- src/migrations/cli.ts | 2 +- src/presentation/webapp/WebApp.jsx | 2 +- src/presentation/widget/WidgetApp.jsx | 2 +- src/scheduler/cli.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index ada0bc2d3..082be1ba8 100644 --- a/src/index.js +++ b/src/index.js @@ -43,7 +43,7 @@ async function main() { const baseUrl = await getBaseUrl(); try { - const api = new D2Api({ baseUrl }); + const api = new D2Api({ baseUrl, backend: "fetch" }); const userSettings = await api.get("/userSettings").getData(); if (typeof userSettings === "string") throw new Error("User needs to log in"); configI18n(userSettings); diff --git a/src/migrations/cli.ts b/src/migrations/cli.ts index b64d3dd09..08f28baaa 100644 --- a/src/migrations/cli.ts +++ b/src/migrations/cli.ts @@ -6,7 +6,7 @@ import { migrationTasks } from "./tasks"; async function main() { const [baseUrl] = process.argv.slice(2); if (!baseUrl) throw new Error("Usage: index.ts DHIS2_URL"); - const api = new D2Api({ baseUrl: baseUrl }); + const api = new D2Api({ baseUrl: baseUrl, backend: "fetch" }); const runner = await MigrationsRunner.init({ api, debug, migrations: migrationTasks }); runner.execute(); } diff --git a/src/presentation/webapp/WebApp.jsx b/src/presentation/webapp/WebApp.jsx index 65d0e9434..be5278001 100644 --- a/src/presentation/webapp/WebApp.jsx +++ b/src/presentation/webapp/WebApp.jsx @@ -55,7 +55,7 @@ const App = () => { if (!encryptionKey) throw new Error("You need to provide a valid encryption key"); const d2 = await init({ baseUrl: `${baseUrl}/api` }); - const api = new D2Api({ baseUrl }); + const api = new D2Api({ baseUrl, backend: "fetch" }); const version = await api.getVersion(); const instance = Instance.build({ name: "This instance", url: baseUrl, version }); diff --git a/src/presentation/widget/WidgetApp.jsx b/src/presentation/widget/WidgetApp.jsx index 4ad6b70dc..a39e4cf87 100644 --- a/src/presentation/widget/WidgetApp.jsx +++ b/src/presentation/widget/WidgetApp.jsx @@ -36,7 +36,7 @@ const App = () => { if (!encryptionKey) throw new Error("You need to provide a valid encryption key"); const d2 = await init({ baseUrl: `${baseUrl}/api` }); - const api = new D2Api({ baseUrl }); + const api = new D2Api({ baseUrl, backend: "fetch" }); const instance = Instance.build({ name: "This instance", url: baseUrl }); const compositionRoot = new CompositionRoot(instance, encryptionKey); diff --git a/src/scheduler/cli.ts b/src/scheduler/cli.ts index c43317ce5..d4a9b0e8a 100644 --- a/src/scheduler/cli.ts +++ b/src/scheduler/cli.ts @@ -51,7 +51,7 @@ const start = async (): Promise => { return; } - const api = new D2Api({ baseUrl, auth: { username, password } }); + const api = new D2Api({ baseUrl, auth: { username, password }, backend: "fetch" }); await checkMigrations(api); const welcomeMessage = `Script initialized on ${baseUrl} with user ${username}`; From 8051eaaf2060e350677500ac424033fb9544bd81 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 09:18:08 +0200 Subject: [PATCH 13/27] Prettify code --- src/data/events/EventsD2ApiRepository.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/events/EventsD2ApiRepository.ts b/src/data/events/EventsD2ApiRepository.ts index 4dfaf519b..1d605d6d2 100644 --- a/src/data/events/EventsD2ApiRepository.ts +++ b/src/data/events/EventsD2ApiRepository.ts @@ -6,7 +6,7 @@ import { EventsRepository } from "../../domain/events/repositories/EventsReposit import { Instance } from "../../domain/instance/entities/Instance"; import { SynchronizationResult, - SynchronizationStats + SynchronizationStats, } from "../../domain/synchronization/entities/SynchronizationResult"; import { cleanObjectDefault, cleanOrgUnitPaths } from "../../domain/synchronization/utils"; import { DataImportParams } from "../../types/d2"; From 7299dd8dcb9336d216cb24e8f6167e67f87bd539 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 09:22:26 +0200 Subject: [PATCH 14/27] Update pot files --- i18n/en.pot | 7 +++++-- i18n/es.po | 5 ++++- i18n/fr.po | 5 ++++- i18n/pt.po | 5 ++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index dbe80aaad..56cd0d2f2 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -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: 2020-09-18T10:25:12.901Z\n" -"PO-Revision-Date: 2020-09-18T10:25:12.901Z\n" +"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" +"PO-Revision-Date: 2020-10-05T07:22:06.919Z\n" msgid "Field {{field}} cannot be blank" msgstr "" @@ -514,6 +514,9 @@ msgstr "" msgid "Include user information and sharing settings" msgstr "" +msgid "Remove organisation unit references" +msgstr "" + msgid "Use default dependencies" msgstr "" diff --git a/i18n/es.po b/i18n/es.po index e0ea0b3cb..9a2e90005 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-09-17T07:32:35.965Z\n" +"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -515,6 +515,9 @@ msgstr "" msgid "Include user information and sharing settings" msgstr "" +msgid "Remove organisation unit references" +msgstr "" + msgid "Use default dependencies" msgstr "" diff --git a/i18n/fr.po b/i18n/fr.po index 4acfcd5c6..0d4b024e7 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-09-17T07:32:35.965Z\n" +"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -515,6 +515,9 @@ msgstr "" msgid "Include user information and sharing settings" msgstr "" +msgid "Remove organisation unit references" +msgstr "" + msgid "Use default dependencies" msgstr "" diff --git a/i18n/pt.po b/i18n/pt.po index 4acfcd5c6..0d4b024e7 100644 --- a/i18n/pt.po +++ b/i18n/pt.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-09-17T07:32:35.965Z\n" +"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -515,6 +515,9 @@ msgstr "" msgid "Include user information and sharing settings" msgstr "" +msgid "Remove organisation unit references" +msgstr "" + msgid "Use default dependencies" msgstr "" From 1f07b1b8669596e2cfbd665080984f8e1aec875b Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 09:55:25 +0200 Subject: [PATCH 15/27] Add logic to remove organisation units --- .../metadata/usecases/MetadataSyncUseCase.ts | 15 +++++++++++++-- src/domain/metadata/utils.ts | 7 +++++-- src/types/synchronization.ts | 1 + 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/domain/metadata/usecases/MetadataSyncUseCase.ts b/src/domain/metadata/usecases/MetadataSyncUseCase.ts index cd720ee18..ab1e50fae 100644 --- a/src/domain/metadata/usecases/MetadataSyncUseCase.ts +++ b/src/domain/metadata/usecases/MetadataSyncUseCase.ts @@ -35,7 +35,14 @@ export class MetadataSyncUseCase extends GenericSyncUseCase { public async exportMetadata(originalBuilder: ExportBuilder): Promise { const visitedIds: Set = new Set(); const recursiveExport = async (builder: ExportBuilder): Promise => { - const { type, ids, excludeRules, includeRules, includeSharingSettings } = builder; + const { + type, + ids, + excludeRules, + includeRules, + includeSharingSettings, + removeOrgUnitReferences, + } = builder; //TODO: when metadata entities schema exists on domain, move this factory to domain const collectionName = modelFactory(this.api, type).getCollectionName(); @@ -58,7 +65,8 @@ export class MetadataSyncUseCase extends GenericSyncUseCase { schema.name, element, excludeRules, - includeSharingSettings + includeSharingSettings, + removeOrgUnitReferences ); result[collectionName] = result[collectionName] || []; @@ -74,6 +82,7 @@ export class MetadataSyncUseCase extends GenericSyncUseCase { excludeRules: nestedExcludeRules[type], includeRules: nestedIncludeRules[type], includeSharingSettings, + removeOrgUnitReferences, })) .map(newBuilder => { newBuilder.ids.forEach(id => { @@ -95,6 +104,7 @@ export class MetadataSyncUseCase extends GenericSyncUseCase { const { metadataIds, syncParams, filterRules = [] } = this.builder; const { includeSharingSettings = true, + removeOrgUnitReferences = false, metadataIncludeExcludeRules = {}, useDefaultIncludeExclude = {}, } = syncParams ?? {}; @@ -119,6 +129,7 @@ export class MetadataSyncUseCase extends GenericSyncUseCase { ? myClass.getIncludeRules() : metadataIncludeExcludeRules[metadataType].includeRules.map(_.toPath), includeSharingSettings, + removeOrgUnitReferences, }); }); diff --git a/src/domain/metadata/utils.ts b/src/domain/metadata/utils.ts index 5cbe4a65a..8a02041b4 100644 --- a/src/domain/metadata/utils.ts +++ b/src/domain/metadata/utils.ts @@ -25,7 +25,8 @@ export function cleanObject( modelName: string, element: any, excludeRules: string[][] = [], - includeSharingSettings: boolean + includeSharingSettings: boolean, + removeOrgUnitReferences: boolean ): any { const leafRules: string[] = _(excludeRules) .filter(path => path.length === 1) @@ -41,7 +42,9 @@ export function cleanObject( [] ); - const propsToRemove = includeSharingSettings ? [] : userProperties; + const sharingSettingsFilter = includeSharingSettings ? [] : userProperties; + const organisationUnitFilter = removeOrgUnitReferences ? ["organisationUnits"] : []; + const propsToRemove = [...sharingSettingsFilter, ...organisationUnitFilter]; return _.pick( element, diff --git a/src/types/synchronization.ts b/src/types/synchronization.ts index 058da5fb1..8460b1c59 100644 --- a/src/types/synchronization.ts +++ b/src/types/synchronization.ts @@ -43,6 +43,7 @@ export interface ExportBuilder { excludeRules: string[][]; includeRules: string[][]; includeSharingSettings: boolean; + removeOrgUnitReferences: boolean; } export interface NestedRules { From 80271789b7a9aff568f24e82129f191ac195b55e Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 16:49:48 +0200 Subject: [PATCH 16/27] Bump d2-api --- package.json | 2 +- yarn.lock | 33 ++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 576f8776a..f4f013a99 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.2.0-beta.4", + "d2-api": "1.2.0-beta.6", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/yarn.lock b/yarn.lock index 71cc74c03..6f0c63bbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,9 +2766,9 @@ abab@^2.0.0, abab@^2.0.3: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.4.tgz#6dfa57b417ca06d21b2478f0e638302f99c2405c" integrity sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ== -abort-controller@^3.0.0: +abort-controller@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" @@ -5201,17 +5201,17 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.2.0-beta.4: - version "1.2.0-beta.4" - resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.4.tgz#7c75b527e55c36c041aef24a79b71fa1e41264da" - integrity sha512-cvmmlVS1N07XrpPvA1+2URW88ojMuU15t1mHUz7WiWnM+uphzlKXF7/k/gxuodc5tNcG4hKTsTH2Xwp51QzIXA== +d2-api@1.2.0-beta.6: + version "1.2.0-beta.6" + resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.6.tgz#f33d97fe09f0042c8a96b6e5c8852c3eb49d3025" + integrity sha512-4onD6X0gN4bDo9bo+MeQKMymCBk90XY3BxUswdVhUK1SwVbqTtq6Z6zSpDOmapCWKJdmOairsa/dqjdjt9WeXw== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5" "@types/argparse" "^1.0.36" "@types/prettier" "^1.18.3" "@types/qs" "^6.5.3" - abort-controller "^3.0.0" + abort-controller "3.0.0" argparse "^1.0.10" axios "0.19.2" axios-debug-log "^0.6.2" @@ -5222,6 +5222,7 @@ d2-api@1.2.0-beta.4: d2 "^31.8.1" dotenv "^8.0.0" express "^4.17.1" + isomorphic-fetch "3.0.0" lodash "^4.17.15" log4js "^4.5.1" node-schedule "^1.3.2" @@ -8548,6 +8549,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-fetch@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -10987,6 +10996,11 @@ node-fetch@^2.3.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -15700,6 +15714,11 @@ whatwg-fetch@^2.0.3: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== +whatwg-fetch@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" From 6e97436d593b20cf3a5e27a2831028e6cbfcbe1b Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 16:53:26 +0200 Subject: [PATCH 17/27] Bump d2-api --- package.json | 2 +- yarn.lock | 33 ++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 576f8776a..f4f013a99 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.2.0-beta.4", + "d2-api": "1.2.0-beta.6", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/yarn.lock b/yarn.lock index 71cc74c03..6f0c63bbe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2766,9 +2766,9 @@ abab@^2.0.0, abab@^2.0.3: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.4.tgz#6dfa57b417ca06d21b2478f0e638302f99c2405c" integrity sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ== -abort-controller@^3.0.0: +abort-controller@3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== dependencies: event-target-shim "^5.0.0" @@ -5201,17 +5201,17 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.2.0-beta.4: - version "1.2.0-beta.4" - resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.4.tgz#7c75b527e55c36c041aef24a79b71fa1e41264da" - integrity sha512-cvmmlVS1N07XrpPvA1+2URW88ojMuU15t1mHUz7WiWnM+uphzlKXF7/k/gxuodc5tNcG4hKTsTH2Xwp51QzIXA== +d2-api@1.2.0-beta.6: + version "1.2.0-beta.6" + resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.6.tgz#f33d97fe09f0042c8a96b6e5c8852c3eb49d3025" + integrity sha512-4onD6X0gN4bDo9bo+MeQKMymCBk90XY3BxUswdVhUK1SwVbqTtq6Z6zSpDOmapCWKJdmOairsa/dqjdjt9WeXw== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5" "@types/argparse" "^1.0.36" "@types/prettier" "^1.18.3" "@types/qs" "^6.5.3" - abort-controller "^3.0.0" + abort-controller "3.0.0" argparse "^1.0.10" axios "0.19.2" axios-debug-log "^0.6.2" @@ -5222,6 +5222,7 @@ d2-api@1.2.0-beta.4: d2 "^31.8.1" dotenv "^8.0.0" express "^4.17.1" + isomorphic-fetch "3.0.0" lodash "^4.17.15" log4js "^4.5.1" node-schedule "^1.3.2" @@ -8548,6 +8549,14 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-fetch@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz#0267b005049046d2421207215d45d6a262b8b8b4" + integrity sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA== + dependencies: + node-fetch "^2.6.1" + whatwg-fetch "^3.4.1" + isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -10987,6 +10996,11 @@ node-fetch@^2.3.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -15700,6 +15714,11 @@ whatwg-fetch@^2.0.3: resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== +whatwg-fetch@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" From 0ebad719571df93f3fddd7c4a0db83833fd84060 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 17:39:41 +0200 Subject: [PATCH 18/27] Update error messages --- .../aggregated/AggregatedD2ApiRepository.ts | 57 +++++++++++------ src/data/events/EventsD2ApiRepository.ts | 61 ++++++++++++------- src/data/metadata/MetadataD2ApiRepository.ts | 27 ++++++-- 3 files changed, 101 insertions(+), 44 deletions(-) diff --git a/src/data/aggregated/AggregatedD2ApiRepository.ts b/src/data/aggregated/AggregatedD2ApiRepository.ts index 60cbdde7f..d5de32425 100644 --- a/src/data/aggregated/AggregatedD2ApiRepository.ts +++ b/src/data/aggregated/AggregatedD2ApiRepository.ts @@ -183,24 +183,45 @@ export class AggregatedD2ApiRepository implements AggregatedRepository { data: object, additionalParams: DataImportParams | undefined ): Promise { - const { status, description, importCount, conflicts } = await this.api - .post( - "/dataValueSets", - { - idScheme: "UID", - dataElementIdScheme: "UID", - orgUnitIdScheme: "UID", - eventIdScheme: "UID", - preheatCache: false, - skipExistingCheck: false, - format: "json", - async: false, - dryRun: false, - ...additionalParams, - }, - data - ) - .getData(); + try { + const response = await this.api + .post( + "/dataValueSets", + { + idScheme: "UID", + dataElementIdScheme: "UID", + orgUnitIdScheme: "UID", + eventIdScheme: "UID", + preheatCache: false, + skipExistingCheck: false, + format: "json", + async: false, + dryRun: false, + ...additionalParams, + }, + data + ) + .getData(); + + return this.cleanAggregatedImportResponse(response); + } catch (error) { + if (error?.response?.data) { + return this.cleanAggregatedImportResponse(error.response.data); + } + + return { + status: "NETWORK ERROR", + instance: this.instance.toPublicObject(), + date: new Date(), + type: "aggregated", + }; + } + } + + private cleanAggregatedImportResponse( + importResult: DataValueSetsPostResponse + ): SynchronizationResult { + const { status, description, importCount, conflicts } = importResult; const errors = conflicts?.map(({ object, value }) => ({ diff --git a/src/data/events/EventsD2ApiRepository.ts b/src/data/events/EventsD2ApiRepository.ts index 1d605d6d2..1f4de85f7 100644 --- a/src/data/events/EventsD2ApiRepository.ts +++ b/src/data/events/EventsD2ApiRepository.ts @@ -193,32 +193,51 @@ export class EventsD2ApiRepository implements EventsRepository { data: object, additionalParams: DataImportParams | undefined ): Promise { - const { status, message, response } = await this.api - .post( - "/events", - { - idScheme: "UID", - dataElementIdScheme: "UID", - orgUnitIdScheme: "UID", - eventIdScheme: "UID", - preheatCache: false, - skipExistingCheck: false, - format: "json", - async: false, - dryRun: false, - ...additionalParams, - }, - data - ) - .getData(); + try { + const response = await this.api + .post( + "/events", + { + idScheme: "UID", + dataElementIdScheme: "UID", + orgUnitIdScheme: "UID", + eventIdScheme: "UID", + preheatCache: false, + skipExistingCheck: false, + format: "json", + async: false, + dryRun: false, + ...additionalParams, + }, + data + ) + .getData(); + + return this.cleanEventsImportResponse(response); + } catch (error) { + if (error?.response?.data) { + return this.cleanEventsImportResponse(error.response.data); + } + + return { + status: "NETWORK ERROR", + instance: this.instance.toPublicObject(), + date: new Date(), + type: "events", + }; + } + } + + private cleanEventsImportResponse(importResult: EventsPostResponse): SynchronizationResult { + const { status, message, response } = importResult; const errors = response.importSummaries?.flatMap( - ({ reference = "", description = "", conflicts = [] }) => - conflicts.map(({ object, value }) => ({ + ({ reference = "", description = "", conflicts }) => + conflicts?.map(({ object, value }) => ({ id: reference, message: _([description, object, value]).compact().join(" "), - })) + })) ?? [{ id: reference, message: description }] ) ?? []; const stats: SynchronizationStats = _.pick(response, [ diff --git a/src/data/metadata/MetadataD2ApiRepository.ts b/src/data/metadata/MetadataD2ApiRepository.ts index 8c7e01903..a9010789b 100644 --- a/src/data/metadata/MetadataD2ApiRepository.ts +++ b/src/data/metadata/MetadataD2ApiRepository.ts @@ -218,6 +218,10 @@ export class MetadataD2ApiRepository implements MetadataRepository { const response = await this.postMetadata(versionedPayloadPackage, additionalParams); return this.cleanMetadataImportResponse(response, "metadata"); } catch (error) { + if (error?.response?.data) { + return this.cleanMetadataImportResponse(error.response.data, "metadata"); + } + return { status: "NETWORK ERROR", instance: this.instance.toPublicObject(), @@ -231,12 +235,25 @@ export class MetadataD2ApiRepository implements MetadataRepository { metadata: MetadataPackage, additionalParams: MetadataImportParams ): Promise { - const response = await this.postMetadata(metadata, { - ...additionalParams, - importStrategy: "DELETE", - }); + try { + const response = await this.postMetadata(metadata, { + ...additionalParams, + importStrategy: "DELETE", + }); + + return this.cleanMetadataImportResponse(response, "deleted"); + } catch (error) { + if (error?.response?.data) { + return this.cleanMetadataImportResponse(error.response.data, "deleted"); + } - return this.cleanMetadataImportResponse(response, "deleted"); + return { + status: "NETWORK ERROR", + instance: this.instance.toPublicObject(), + date: new Date(), + type: "deleted", + }; + } } public async getByFilterRules(filterRules: FilterRule[]): Promise { From 28b7002bc9677f4857d37d46634b2357bd3ddb61 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 18:40:23 +0200 Subject: [PATCH 19/27] Update error message --- src/domain/instance/usecases/ValidateInstanceUseCase.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/domain/instance/usecases/ValidateInstanceUseCase.ts b/src/domain/instance/usecases/ValidateInstanceUseCase.ts index f467b0d98..463757605 100644 --- a/src/domain/instance/usecases/ValidateInstanceUseCase.ts +++ b/src/domain/instance/usecases/ValidateInstanceUseCase.ts @@ -44,9 +44,7 @@ export class ValidateInstanceUseCase implements UseCase { } } else if (error.request) { return Either.error( - i18n.t("Network error {{error}}, check if server is up and CORS is enabled", { - error: error.toString(), - }) + i18n.t("Network error, check if server is up and CORS is enabled") ); } else { debug({ error }); From ad9d05a3da06bac5cdf3c477b05cf7dbc90ff154 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Mon, 5 Oct 2020 18:44:56 +0200 Subject: [PATCH 20/27] Bump d2-api --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f4f013a99..61679748f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.2.0-beta.6", + "d2-api": "1.2.0-beta.8", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/yarn.lock b/yarn.lock index 6f0c63bbe..7613e10db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5201,10 +5201,10 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.2.0-beta.6: - version "1.2.0-beta.6" - resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.6.tgz#f33d97fe09f0042c8a96b6e5c8852c3eb49d3025" - integrity sha512-4onD6X0gN4bDo9bo+MeQKMymCBk90XY3BxUswdVhUK1SwVbqTtq6Z6zSpDOmapCWKJdmOairsa/dqjdjt9WeXw== +d2-api@1.2.0-beta.8: + version "1.2.0-beta.8" + resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.8.tgz#826ba5da3b4346be0caabf60bd5b08fd21763c78" + integrity sha512-54jFFTo1/7afnzMxGQl93bKTspKasugpfheN8CaC5nqrs989XD7HWOAY3bmp1I+Q9imzMUg3062DtT5P7CXbcA== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5" From 5ce7a535ec761831c19920bcbfafa3d52d311136 Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Tue, 6 Oct 2020 08:46:25 +0200 Subject: [PATCH 21/27] Fix problem parsing empty include/exclude rules --- src/models/syncRule.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/models/syncRule.ts b/src/models/syncRule.ts index 8f7b2605e..67af380c4 100644 --- a/src/models/syncRule.ts +++ b/src/models/syncRule.ts @@ -410,12 +410,18 @@ export default class SyncRule { } public markToNotUseDefaultIncludeExclude(models: Array): SyncRule { + const parseRules = (rule: string[][]) => + _(rule) + .map(array => (array.length > 0 ? array.join(".") : undefined)) + .compact() + .value(); + const rules: MetadataIncludeExcludeRules = models.reduce( (accumulator: any, model: typeof D2Model) => ({ ...accumulator, [model.getMetadataType()]: { - includeRules: model.getIncludeRules().map(array => array.join(".")), - excludeRules: model.getExcludeRules().map(array => array.join(".")), + includeRules: parseRules(model.getIncludeRules()), + excludeRules: parseRules(model.getExcludeRules()), }, }), {} From dae047bfbf3d244bdcd0d8d7f6d30b5487e7316f Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Tue, 6 Oct 2020 09:20:38 +0200 Subject: [PATCH 22/27] Fix issue with empty string --- src/models/dhis/metadata.ts | 2 +- src/models/syncRule.ts | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/models/dhis/metadata.ts b/src/models/dhis/metadata.ts index ab2a096a2..cb555a15b 100644 --- a/src/models/dhis/metadata.ts +++ b/src/models/dhis/metadata.ts @@ -355,7 +355,7 @@ export class OptionSetModel extends D2Model { protected static metadataType = "optionSet"; protected static collectionName = "optionSets" as const; - protected static excludeRules = [""]; + protected static excludeRules = []; protected static includeRules = ["attributes", "options", "options.attributes"]; } diff --git a/src/models/syncRule.ts b/src/models/syncRule.ts index 67af380c4..8f7b2605e 100644 --- a/src/models/syncRule.ts +++ b/src/models/syncRule.ts @@ -410,18 +410,12 @@ export default class SyncRule { } public markToNotUseDefaultIncludeExclude(models: Array): SyncRule { - const parseRules = (rule: string[][]) => - _(rule) - .map(array => (array.length > 0 ? array.join(".") : undefined)) - .compact() - .value(); - const rules: MetadataIncludeExcludeRules = models.reduce( (accumulator: any, model: typeof D2Model) => ({ ...accumulator, [model.getMetadataType()]: { - includeRules: parseRules(model.getIncludeRules()), - excludeRules: parseRules(model.getExcludeRules()), + includeRules: model.getIncludeRules().map(array => array.join(".")), + excludeRules: model.getExcludeRules().map(array => array.join(".")), }, }), {} From 81bd54e9cc27178e35b7dc38549f100b57d6bedd Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Tue, 6 Oct 2020 09:25:20 +0200 Subject: [PATCH 23/27] Hide include/exclude rules from summary if empty --- .../sync-wizard/common/SummaryStep.jsx | 78 ++++++++++--------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx b/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx index cf90f17bb..b4c8a58d1 100644 --- a/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx +++ b/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx @@ -205,44 +205,50 @@ const SaveStep = ({ syncRule, onCancel }) => { {syncRule.type === "metadata" && !syncRule.useDefaultIncludeExclude && (
    - {_.keys(syncRule.metadataIncludeExcludeRules).map(key => ( - -
      - -
        - {syncRule.metadataIncludeExcludeRules[ - key - ].includeRules.map((includeRule, idx) => ( -
          - -
        - ))} -
      - + {_.keys(syncRule.metadataIncludeExcludeRules).map(key => { + const { + includeRules, + excludeRules, + } = syncRule.metadataIncludeExcludeRules[key]; + + return ( +
        - {syncRule.metadataIncludeExcludeRules[ - key - ].excludeRules.map((excludeRule, idx) => ( -
          - -
        - ))} + {includeRules.length > 0 && ( + + {includeRules.map((includeRule, idx) => ( +
          + +
        + ))} +
        + )} + + {excludeRules.length > 0 && ( + + {excludeRules.map((excludeRule, idx) => ( +
          + +
        + ))} +
        + )}
      -
    -
    - ))} + + ); + })}
)} From ea798d49b2f8d17e02fa9dc45f935c5413e5cd4f Mon Sep 17 00:00:00 2001 From: Adrian Quintana Date: Tue, 6 Oct 2020 08:38:43 +0100 Subject: [PATCH 24/27] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4f013a99..20c89463e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "metadata-synchronization", "description": "Advanced metadata & data synchronization utility", - "version": "2.2.1", + "version": "2.3.0", "license": "GPL-3.0", "author": "EyeSeeTea team", "homepage": ".", From 78a6667a93e542a2f5c01835b839a22ce7b2801d Mon Sep 17 00:00:00 2001 From: Alexis Rico Date: Tue, 6 Oct 2020 09:36:15 +0200 Subject: [PATCH 25/27] Update summary on pull --- .../sync-wizard/common/SummaryStep.jsx | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx b/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx index b4c8a58d1..12f06e361 100644 --- a/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx +++ b/src/presentation/react/components/sync-wizard/common/SummaryStep.jsx @@ -99,6 +99,22 @@ const SaveStep = ({ syncRule, onCancel }) => { const aggregationItems = useMemo(buildAggregationItems, []); + const destinationInstances = useMemo( + () => + _.compact( + syncRule.targetInstances.map(id => { + if (id === "LOCAL") return { value: id, text: "This instance" }; + return instanceOptions.find(e => e.value === id); + }) + ), + [instanceOptions, syncRule.targetInstances] + ); + + const originInstance = useMemo( + () => instanceOptions.find(e => e.value === syncRule.originInstance), + [instanceOptions, syncRule.originInstance] + ); + return ( { + {originInstance && ( + + )} +
    - {syncRule.targetInstances.map(id => { - const instanceOption = instanceOptions.find(e => e.value === id); - return instanceOption ? ( - - ) : null; - })} + {destinationInstances.map(instanceOption => ( + + ))}
From e061a5b87798f186caa7e2fd2f52cda4fda7b77a Mon Sep 17 00:00:00 2001 From: Adrian Quintana Date: Tue, 6 Oct 2020 11:13:33 +0100 Subject: [PATCH 26/27] missing terms --- i18n/en.pot | 6 +++--- i18n/es.po | 4 ++-- i18n/fr.po | 4 ++-- i18n/pt.po | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 56cd0d2f2..8f7b175fd 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -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: 2020-10-05T07:22:06.919Z\n" -"PO-Revision-Date: 2020-10-05T07:22:06.919Z\n" +"POT-Creation-Date: 2020-10-06T10:10:16.836Z\n" +"PO-Revision-Date: 2020-10-06T10:10:16.836Z\n" msgid "Field {{field}} cannot be blank" msgstr "" @@ -35,7 +35,7 @@ msgstr "" msgid "Error {{status}}" msgstr "" -msgid "Network error {{error}}, check if server is up and CORS is enabled" +msgid "Network error, check if server is up and CORS is enabled" msgstr "" msgid "Unknown error" diff --git a/i18n/es.po b/i18n/es.po index 9a2e90005..438b56715 100644 --- a/i18n/es.po +++ b/i18n/es.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" +"POT-Creation-Date: 2020-10-06T10:10:16.836Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "" msgid "Error {{status}}" msgstr "" -msgid "Network error {{error}}, check if server is up and CORS is enabled" +msgid "Network error, check if server is up and CORS is enabled" msgstr "" msgid "Unknown error" diff --git a/i18n/fr.po b/i18n/fr.po index 0d4b024e7..c22bfe293 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" +"POT-Creation-Date: 2020-10-06T10:10:16.836Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "" msgid "Error {{status}}" msgstr "" -msgid "Network error {{error}}, check if server is up and CORS is enabled" +msgid "Network error, check if server is up and CORS is enabled" msgstr "" msgid "Unknown error" diff --git a/i18n/pt.po b/i18n/pt.po index 0d4b024e7..c22bfe293 100644 --- a/i18n/pt.po +++ b/i18n/pt.po @@ -1,7 +1,7 @@ msgid "" msgstr "" "Project-Id-Version: i18next-conv\n" -"POT-Creation-Date: 2020-10-05T07:22:06.919Z\n" +"POT-Creation-Date: 2020-10-06T10:10:16.836Z\n" "PO-Revision-Date: 2020-07-10T06:53:30.625Z\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -35,7 +35,7 @@ msgstr "" msgid "Error {{status}}" msgstr "" -msgid "Network error {{error}}, check if server is up and CORS is enabled" +msgid "Network error, check if server is up and CORS is enabled" msgstr "" msgid "Unknown error" From 6a8716191f7c4766cd2cbb87a0fc15bfc0fd9a1f Mon Sep 17 00:00:00 2001 From: Adrian Quintana Date: Tue, 6 Oct 2020 11:14:03 +0100 Subject: [PATCH 27/27] upgrade d2-api --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index e2c489def..78f24d17f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "cronstrue": "1.95.0", "cryptr": "4.0.2", "d2": "31.8.1", - "d2-api": "1.2.0-beta.8", + "d2-api": "1.2.0", "d2-manifest": "1.0.0", "d2-ui-components": "2.1.0", "file-saver": "2.0.2", diff --git a/yarn.lock b/yarn.lock index 7613e10db..79665989f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5201,10 +5201,10 @@ cypress@4.10.0: url "0.11.0" yauzl "2.10.0" -d2-api@1.2.0-beta.8: - version "1.2.0-beta.8" - resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0-beta.8.tgz#826ba5da3b4346be0caabf60bd5b08fd21763c78" - integrity sha512-54jFFTo1/7afnzMxGQl93bKTspKasugpfheN8CaC5nqrs989XD7HWOAY3bmp1I+Q9imzMUg3062DtT5P7CXbcA== +d2-api@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d2-api/-/d2-api-1.2.0.tgz#adc25b55cf71401c244f92a452acbf91910c175d" + integrity sha512-+NeQMNrwvRRCMQRyC+nX5ZD4VpO6BPhrssRVQRl2Mo1zVT/qxpl9DpYKMJtHZtSATu8WCl1iXo6xcCR4aGEIfw== dependencies: "@babel/runtime" "^7.5.4" "@dhis2/d2-i18n" "^1.0.5"