Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2026-04-20T04:35:46.003Z\n"
"PO-Revision-Date: 2026-04-20T04:35:46.003Z\n"
"POT-Creation-Date: 2026-04-23T07:13:29.327Z\n"
"PO-Revision-Date: 2026-04-23T07:13:29.328Z\n"

msgid ""
"THIS NEW RELEASE INCLUDES SHARING SETTINGS PER INSTANCES. FOR THIS VERSION "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import { TextField } from "@material-ui/core";
import React, { ChangeEvent, useMemo } from "react";
import styled from "styled-components";
import i18n from "../../../../../utils/i18n";
import {
AnalyticsOptions,
AnalyticsPanelKind,
defaultAnalyticsOptions,
RunAnalyticsSettings,
} from "../../../../webapp/msf-aggregate-data/pages/MSFEntities";
import Dropdown from "../../../core/components/dropdown/Dropdown";
import { Toggle } from "../../../core/components/toggle/Toggle";

export interface AnalyticsPanelProps {
title: string;
kind: AnalyticsPanelKind;
runSetting: RunAnalyticsSettings;
onRunSettingChange(value: RunAnalyticsSettings): void;
options: AnalyticsOptions | undefined;
onOptionsChange(options: AnalyticsOptions): void;
}

type SkipFlag = keyof Omit<AnalyticsOptions, "lastYears">;

type FlagDef = { key: SkipFlag; label: string };

const individualFlags = (): FlagDef[] => [
{ key: "skipResourceTables", label: i18n.t("Skip generation of resource tables") },
{ key: "skipEvents", label: i18n.t("Skip generation of event data") },
{ key: "skipEnrollment", label: i18n.t("Skip generation of enrollment data") },
{ key: "skipOrgUnitOwnership", label: i18n.t("Skip generation of organisation unit ownership data") },
{ key: "skipTrackedEntities", label: i18n.t("Skip generation of tracked entity data") },
];

const aggregateFlags = (): FlagDef[] => [
{ key: "skipResourceTables", label: i18n.t("Skip generation of resource tables") },
{ key: "skipAggregate", label: i18n.t("Skip generation of aggregate data and completeness data") },
{ key: "skipOutliers", label: i18n.t("Skip generation of outlier data") },
];

export const AnalyticsPanel: React.FC<AnalyticsPanelProps> = ({
title,
kind,
runSetting,
onRunSettingChange,
options,
onOptionsChange,
}) => {
const runSettingItems = useMemo(
() => [
{ id: "true" as const, name: i18n.t("True") },
{ id: "false" as const, name: i18n.t("False") },
{ id: "by-sync-rule-settings" as const, name: i18n.t("Use sync rule settings") },
],
[]
);

const flags = useMemo(() => (kind === "individual" ? individualFlags() : aggregateFlags()), [kind]);

const effectiveOptions = options ?? defaultAnalyticsOptions;
const showOptions = runSetting === "true";

const setLastYears = (event: ChangeEvent<HTMLInputElement>) => {
const lastYears = parseInt(event.target.value);
onOptionsChange({ ...effectiveOptions, lastYears });
};

const setFlag = (key: SkipFlag) => (value: boolean) => {
onOptionsChange({ ...effectiveOptions, [key]: value });
};

return (
<Panel>
<PanelTitle>{title}</PanelTitle>

<Dropdown<RunAnalyticsSettings>
label={i18n.t("Run Analytics")}
items={runSettingItems}
onValueChange={onRunSettingChange}
value={runSetting}
hideEmpty
/>

{showOptions && (
<Options>
<Flags>
{flags.map(({ key, label }) => (
<Toggle
key={key}
label={label}
value={effectiveOptions[key] ?? false}
onValueChange={setFlag(key)}
/>
))}
</Flags>

<YearsField
label={i18n.t("Number of last years of data to include")}
value={effectiveOptions.lastYears}
onChange={setLastYears}
type="number"
InputLabelProps={{ shrink: true }}
/>
</Options>
)}
</Panel>
);
};

const Panel = styled.div`
flex: 1;
min-width: 320px;
padding: 8px 16px 16px;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 4px;
`;

const PanelTitle = styled.h4`
margin-top: 0;
`;

const Options = styled.div`
margin-top: 16px;
`;

const Flags = styled.div`
display: flex;
flex-direction: column;
margin-bottom: 16px;
`;

const YearsField = styled(TextField)`
width: 300px;
`;
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Divider, makeStyles, TextField, Theme } from "@material-ui/core";
import { Divider } from "@material-ui/core";
import { ConfirmationDialog } from "@eyeseetea/d2-ui-components";
import { Dictionary } from "lodash";
import React, { ChangeEvent, useMemo, useState } from "react";
import React, { useState } from "react";
import styled from "styled-components";
import i18n from "../../../../../utils/i18n";
import { MSFSettings, RunAnalyticsSettings } from "../../../../webapp/msf-aggregate-data/pages/MSFEntities";
import Dropdown from "../../../core/components/dropdown/Dropdown";
import {
AnalyticsOptions,
MSFSettings,
RunAnalyticsSettings,
} from "../../../../webapp/msf-aggregate-data/pages/MSFEntities";
import { Toggle } from "../../../core/components/toggle/Toggle";
import { NamedDate, OrgUnitDateSelector } from "../org-unit-date-selector/OrgUnitDateSelector";
import { AnalyticsPanel } from "./AnalyticsPanel";

export interface MSFSettingsDialogProps {
settings: MSFSettings;
Expand All @@ -15,27 +20,8 @@ export interface MSFSettingsDialogProps {
}

export const MSFSettingsDialog: React.FC<MSFSettingsDialogProps> = ({ onClose, onSave, settings: defaultSettings }) => {
const classes = useStyles();

const [settings, updateSettings] = useState<MSFSettings>(defaultSettings);

const analyticsSettingItems = useMemo(() => {
return [
{
id: "true" as const,
name: i18n.t("True"),
},
{
id: "false" as const,
name: i18n.t("False"),
},
{
id: "by-sync-rule-settings" as const,
name: i18n.t("Use sync rule settings"),
},
];
}, []);

const setRunAnalyticsBefore = (runAnalyticsBefore: RunAnalyticsSettings) => {
updateSettings(settings => ({ ...settings, runAnalyticsBefore }));
};
Expand All @@ -44,9 +30,12 @@ export const MSFSettingsDialog: React.FC<MSFSettingsDialogProps> = ({ onClose, o
updateSettings(settings => ({ ...settings, runAnalyticsAfter }));
};

const setAnalyticsYears = (event: ChangeEvent<HTMLInputElement>) => {
const analyticsYears = parseInt(event.target.value);
updateSettings(settings => ({ ...settings, analyticsYears }));
const setAnalyticsBefore = (analyticsBefore: AnalyticsOptions) => {
updateSettings(settings => ({ ...settings, analyticsBefore }));
};

const setAnalyticsAfter = (analyticsAfter: AnalyticsOptions) => {
updateSettings(settings => ({ ...settings, analyticsAfter }));
};

const updateProjectMinimumDates = (projectStartDates: Dictionary<NamedDate>) => {
Expand Down Expand Up @@ -76,36 +65,31 @@ export const MSFSettingsDialog: React.FC<MSFSettingsDialogProps> = ({ onClose, o
cancelText={i18n.t("Cancel")}
saveText={i18n.t("Save")}
>
<div className={classes.section}>
<h3 className={classes.title}>{i18n.t("Analytics")}</h3>

<div className={classes.selector}>
<Dropdown<RunAnalyticsSettings>
label={i18n.t("Run Analytics Before")}
items={analyticsSettingItems}
onValueChange={setRunAnalyticsBefore}
value={settings.runAnalyticsBefore}
hideEmpty
/>
<Dropdown<RunAnalyticsSettings>
label={i18n.t("Run Analytics After")}
items={analyticsSettingItems}
onValueChange={setRunAnalyticsAfter}
value={settings.runAnalyticsAfter}
hideEmpty
<Section>
<SectionTitle>{i18n.t("Analytics")}</SectionTitle>

<Panels>
<AnalyticsPanel
title={i18n.t("Before sync · Individual data")}
kind="individual"
runSetting={settings.runAnalyticsBefore}
onRunSettingChange={setRunAnalyticsBefore}
options={settings.analyticsBefore}
onOptionsChange={setAnalyticsBefore}
/>
<TextField
className={classes.yearsSelector}
label={i18n.t("Number of years to include")}
value={settings.analyticsYears}
onChange={setAnalyticsYears}
type="number"
<AnalyticsPanel
title={i18n.t("After sync · Aggregate data")}
kind="aggregate"
runSetting={settings.runAnalyticsAfter}
onRunSettingChange={setRunAnalyticsAfter}
options={settings.analyticsAfter}
onOptionsChange={setAnalyticsAfter}
/>
</div>
</div>
</Panels>
</Section>

<div className={classes.section}>
<h3 className={classes.title}>{i18n.t("Data values settings")}</h3>
<Section>
<SectionTitle>{i18n.t("Data values settings")}</SectionTitle>

<div>
<Toggle
Expand All @@ -122,44 +106,38 @@ export const MSFSettingsDialog: React.FC<MSFSettingsDialogProps> = ({ onClose, o
value={settings.checkInPreviousPeriods ?? false}
/>
</div>
</div>
</Section>

<Divider className={classes.divider} />
<SpacedDivider />

<div className={classes.section}>
<h3 className={classes.title}>{i18n.t("Project minimum dates")}</h3>
<Section>
<SectionTitle>{i18n.t("Project minimum dates")}</SectionTitle>

<div>
<OrgUnitDateSelector
projectMinimumDates={settings.projectMinimumDates}
onChange={updateProjectMinimumDates}
/>
</div>
</div>
</Section>
</ConfirmationDialog>
);
};

const useStyles = makeStyles((theme: Theme) => ({
selector: {
margin: theme.spacing(0, 0, 3, 0),
},
yearsSelector: {
minWidth: 250,
marginTop: -8,
marginLeft: 15,
},
info: {
margin: theme.spacing(0, 0, 2, 1),
fontSize: "0.8em",
},
title: {
marginTop: 0,
},
section: {
marginBottom: 20,
},
divider: {
marginBottom: 20,
},
}));
const Section = styled.div`
margin-bottom: 20px;
`;

const SectionTitle = styled.h3`
margin-top: 0;
`;

const Panels = styled.div`
display: flex;
gap: 16px;
flex-wrap: wrap;
`;

const SpacedDivider = styled(Divider)`
margin-bottom: 20px;
`;
Loading
Loading