Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
425cea2
feat: enable dashboard plugin entry point
edoardo Jun 19, 2024
20a3428
chore: use latest cli-app-scripts and analytics dev branch
edoardo Jun 19, 2024
297f425
chore: indicate this is a dashboard plugin in d2.config.js
edoardo Aug 12, 2024
642f6f9
chore: use uppercase for pluginType value
edoardo Aug 16, 2024
fbd92db
chore: restore missing dep after rebase
edoardo Aug 16, 2024
b593c0a
Merge with main
turban Aug 21, 2024
9ae7804
Minimal dashboard plugin
turban Aug 21, 2024
89fc48b
Fix merge conflict
turban Aug 21, 2024
b327516
console.log for debugging
turban Aug 22, 2024
2d72c3f
Code cleaning
turban Aug 22, 2024
16e2781
yarn deuplicate
turban Aug 22, 2024
8572f3b
Plugin setup
turban Aug 22, 2024
6b3ad99
Plugin test version
turban Aug 22, 2024
e0467c0
Component name change
turban Aug 22, 2024
571deaf
Dummy plugin
turban Aug 22, 2024
d09bac8
Dummy plugin
turban Aug 22, 2024
18dd4b0
refactor: rewrite resize logic for Highcharts
edoardo Aug 30, 2024
9143363
feat: call callback for setting custom title/url on dashboard item
edoardo Sep 6, 2024
2d5b97b
Merge in main
turban Sep 10, 2024
e892913
Refactor
turban Sep 11, 2024
15c25fd
Plugin refactor
turban Sep 11, 2024
ce3b0eb
Plugin update
turban Sep 11, 2024
eddd398
Revert changes
turban Sep 11, 2024
89acbbe
Plugin fix
turban Sep 11, 2024
30e94ab
New plugin version
turban Sep 11, 2024
2eb9702
Merge in main
turban Sep 11, 2024
7daba13
Merge in main
turban Sep 24, 2024
5e27a8c
Merge in main
turban Oct 9, 2024
7ec4f8e
Plugin fix
turban Oct 14, 2024
99ec215
Plugin configuration
turban Oct 19, 2024
cfbd3c3
Plugin configuration
turban Nov 12, 2024
9cc8120
Plugin configuration
turban Nov 13, 2024
a706a82
Bump plugin version
turban Nov 14, 2024
c01c590
onRemove callback
turban Nov 14, 2024
8ac13d7
Merge branch 'main' into feat/dashboard-plugin
turban Nov 20, 2024
eaff940
Merge in main
turban Nov 25, 2024
d251e46
Plugin state handling
turban Nov 25, 2024
acd5dbf
Finalise plugin support
turban Dec 4, 2024
34bc225
Style fix
turban Dec 4, 2024
e0354c9
Merge in main
turban Jan 8, 2025
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
2 changes: 2 additions & 0 deletions d2.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const config = {
type: "app",
pluginType: "DASHBOARD",
title: "DHIS2 Climate App",
entryPoints: {
app: "./src/App.js",
plugin: "./src/DashboardPlugin.js",
},
};

Expand Down
31 changes: 29 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2024-11-20T14:17:35.520Z\n"
"PO-Revision-Date: 2024-11-20T14:17:35.520Z\n"
"POT-Creation-Date: 2024-12-04T13:59:15.469Z\n"
"PO-Revision-Date: 2024-12-04T13:59:15.469Z\n"

msgid "About this app"
msgstr "About this app"
Expand Down Expand Up @@ -663,6 +663,33 @@ msgstr "Org unit parent needs to be above or equal to the org unit level"
msgid "Daily values will be imported between start and end dates"
msgstr "Daily values will be imported between start and end dates"

msgid "Selected org unit has no geometry, which is required to display data."
msgstr "Selected org unit has no geometry, which is required to display data."

msgid "Data is only available for facilities (point locations)."
msgstr "Data is only available for facilities (point locations)."

msgid "Weather forecast"
msgstr "Weather forecast"

msgid "Choose an organisation unit"
msgstr "Choose an organisation unit"

msgid "Done"
msgstr "Done"

msgid "Choose a data source"
msgstr "Choose a data source"

msgid "Loading"
msgstr "Loading"

msgid "No data source. Edit this dashboard to configure this item."
msgstr "No data source. Edit this dashboard to configure this item."

msgid "Configure data source"
msgstr "Configure data source"

msgid ""
"Set y-axis values for charts in the Explore data section to make it easier "
"to compare different org units. Leave blank to calculate based on data "
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "climate-data",
"version": "1.5.1",
"version": "999.99.0-dashboard-plugin.25",
"description": "Explore and import weather and climate data in DHIS2.",
"license": "BSD-3-Clause",
"private": true,
Expand All @@ -14,6 +14,7 @@
"@dhis2/cli-app-scripts": "^11.7.0"
},
"dependencies": {
"@dhis2/analytics": "git+https://github.com/d2-ci/analytics.git#dca4316cdf2a8fd9482dfe1244575baad7ffe228",
"@dhis2/app-runtime": "^3.10.6",
"@dhis2/multi-calendar-dates": "1.0.0-alpha.27",
"@turf/area": "^6.5.0",
Expand Down
11 changes: 11 additions & 0 deletions src/DashboardPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DashboardPluginWrapper } from "@dhis2/analytics";
import React from "react";
import Plugin from "./components/plugin/Plugin.js";

const DashboardPlugin = (props) => (
<DashboardPluginWrapper {...props}>
{(parentProps) => <Plugin {...parentProps} />}
</DashboardPluginWrapper>
);

export default DashboardPlugin;
5 changes: 5 additions & 0 deletions src/components/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import SetupPage from "./setup/SetupPage";
import SettingsPage from "./settings/SettingsPage";
import ErrorPage from "./ErrorPage";
import CheckPage from "./check/CheckPage";
import PluginPage from "./plugin/PluginPage";
import orgUnitLoader from "../utils/orgUnitLoader";
import checkPlaceLoader from "../utils/checkPlaceLoader";

Expand Down Expand Up @@ -161,6 +162,10 @@ const Routes = () => {
path: "settings",
element: <SettingsPage />,
},
{
path: "plugin",
element: <PluginPage />,
},
],
},
]);
Expand Down
48 changes: 44 additions & 4 deletions src/components/explore/Chart.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,68 @@
import PropTypes from "prop-types";
import { useCallback, useRef, useLayoutEffect, useMemo } from "react";
import Highcharts from "highcharts";
import accessibility from "highcharts/modules/accessibility";
import highchartsMore from "highcharts/highcharts-more";
import exporting from "highcharts/modules/exporting";
import patternFill from "highcharts/modules/pattern-fill";
import React, { useRef, useLayoutEffect } from "react";

accessibility(Highcharts);
exporting(Highcharts);
highchartsMore(Highcharts);
patternFill(Highcharts);

const Chart = ({ config }) => {
const Chart = ({ config, isPlugin }) => {
const containerRef = useRef(null);
const chartRef = useRef();

const titleHeight = 32;

const onResize = useCallback(() => {
chartRef.current?.setSize(
containerRef.current.offsetWidth,
containerRef.current.offsetHeight,
false
);
}, []);

const sizeObserver = useMemo(
() => new window.ResizeObserver(onResize),
[onResize]
);

const mountAndObserveContainerRef = useCallback(
(node) => {
if (node === null) {
return;
}

containerRef.current = node;
sizeObserver.observe(node);

return sizeObserver.disconnect;
},
[sizeObserver]
);

useLayoutEffect(() => {
Highcharts.chart(chartRef.current, config);
chartRef.current = new Highcharts.chart(containerRef.current, config);
}, [config, chartRef]);

return <div ref={chartRef} />;
return (
<div
style={{
// height: `calc(100% - ${isPlugin ? titleHeight : 0}px)`,
height: "100%",
width: "100%",
}}
ref={mountAndObserveContainerRef}
/>
);
};

Chart.propTypes = {
config: PropTypes.object.isRequired,
isPlugin: PropTypes.bool,
};

export default Chart;
4 changes: 2 additions & 2 deletions src/components/explore/forecast/DayForecast.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const sixHours = [
{ start: "18", end: "24" },
];

const DayForecast = ({ date, series }) => {
const DayForecast = ({ date, series, isPlugin }) => {
const day = new Date(date).toDateString().slice(0, -5);
const temp = series.map((s) => s.data.instant.details.air_temperature);
const minTemp = Math.round(Math.min(...temp));
Expand Down Expand Up @@ -62,7 +62,7 @@ const DayForecast = ({ date, series }) => {
<td className={styles.precip}>
{precip ? i18n.t("{{precip}} mm", { precip }) : null}
</td>
<td className={styles.precip}>{avgHumidity}%</td>
{!isPlugin && <td className={styles.precip}>{avgHumidity}%</td>}
<td className={styles.wind}>{maxWind} m/s</td>
</tr>
);
Expand Down
46 changes: 28 additions & 18 deletions src/components/explore/forecast/Forecast.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PropTypes from "prop-types";
import { useState, useEffect } from "react";
import i18n from "@dhis2/d2-i18n";
import DataLoader from "../../shared/DataLoader.js";
Expand All @@ -11,7 +12,7 @@ const convertTimezone = (date, timeZone) =>

const browserTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;

const Forecast = () => {
const Forecast = ({ isPlugin }) => {
const orgUnit = exploreStore((state) => state.orgUnit);
const [data, setData] = useState();
const { settings, loading } = useAppSettings();
Expand Down Expand Up @@ -57,7 +58,9 @@ const Forecast = () => {
<td>{i18n.t("Evening")}</td>
<td className={styles.right}>{i18n.t("Max/min temp.")}</td>
<td className={styles.right}>{i18n.t("Precip.")}</td>
<td className={styles.right}>{i18n.t("Rel. humidity")}</td>
{!isPlugin && (
<td className={styles.right}>{i18n.t("Rel. humidity")}</td>
)}
<td className={styles.right}>{i18n.t("Wind")}</td>
</tr>
</thead>
Expand All @@ -67,6 +70,7 @@ const Forecast = () => {
key={date}
date={date}
series={timeseries.filter((t) => t.time.startsWith(date))}
isPlugin={isPlugin}
/>
))}
</tbody>
Expand All @@ -85,24 +89,30 @@ const Forecast = () => {
ECMWF HRES
</a>
</div>
<div className={styles.timeZone}>
{settings.timeZone
? i18n.t(
'The forecast is using the "{{- timeZone}}" time zone. You can change the time zone for your org units under "Settings".',
{ timeZone }
)
: browserTimeZone
? i18n.t(
'The forecast is using the time zone of your browser ({{- timeZone}}). You can set the time zone for your org units under "Settings".',
{ timeZone }
)
: i18n.t(
'The forecast is using the default "{{- timeZone}}" time zone. You can set the time zone for your org units under "Settings".',
{ timeZone }
)}
</div>
{!isPlugin && (
<div className={styles.timeZone}>
{settings.timeZone
? i18n.t(
'The forecast is using the "{{- timeZone}}" time zone. You can change the time zone for your org units under "Settings".',
{ timeZone }
)
: browserTimeZone
? i18n.t(
'The forecast is using the time zone of your browser ({{- timeZone}}). You can set the time zone for your org units under "Settings".',
{ timeZone }
)
: i18n.t(
'The forecast is using the default "{{- timeZone}}" time zone. You can set the time zone for your org units under "Settings".',
{ timeZone }
)}
</div>
)}
</>
);
};

Forecast.propTypes = {
isPlugin: PropTypes.bool,
};

export default Forecast;
23 changes: 14 additions & 9 deletions src/components/explore/heat/charts/thermalComfortDaily.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "../../../../utils/chart";
import { toCelcius } from "../../../../utils/calc";

export const getPlotBands = (minMax, settings) => {
export const getPlotBands = (minMax, settings = {}) => {
const { heatMin, heatMax } = settings;

const minValue =
Expand Down Expand Up @@ -61,7 +61,7 @@ export const getThickPositons = (plotBands) => [
plotBands[plotBands.length - 1].to,
];

const getChart = (name, data, settings) => {
const getChart = (name, data, settings, isPlugin) => {
const series = data.map((d) => ({
x: new Date(d.id).getTime(),
y: toCelcius(d["utci_mean"]),
Expand All @@ -78,13 +78,15 @@ const getChart = (name, data, settings) => {
const tickPositions = getThickPositons(plotBands);

return {
title: {
text: i18n.t("{{name}}: Thermal comfort {{period}}", {
name,
period: getDailyPeriod(data),
nsSeparator: ";",
}),
},
title: !isPlugin
? {
text: i18n.t("{{name}}: Thermal comfort {{period}}", {
name,
period: getDailyPeriod(data),
nsSeparator: ";",
}),
}
: "",
credits: heatCredits,
tooltip: {
crosshairs: true,
Expand Down Expand Up @@ -142,6 +144,9 @@ const getChart = (name, data, settings) => {
zIndex: 0,
},
],
exporting: {
enabled: !isPlugin,
},
};
};

Expand Down
25 changes: 25 additions & 0 deletions src/components/explore/heat/plugin/HeatDaily.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Chart from "../../Chart";
import DataLoader from "../../../shared/DataLoader";
import getDailyConfig from "../charts/thermalComfortDaily";
import useEarthEngineTimeSeries from "../../../../hooks/useEarthEngineTimeSeries";
import useAppSettings from "../../../../hooks/useAppSettings";
import { era5HeatDaily } from "../../../../data/datasets";

const HeatDaily = ({ orgUnit, period }) => {
const { settings } = useAppSettings();

const data = useEarthEngineTimeSeries(era5HeatDaily, period, orgUnit);

const isPlugin = true;

return data ? (
<Chart
config={getDailyConfig(orgUnit.properties.name, data, settings, isPlugin)}
isPlugin={isPlugin}
/>
) : (
<DataLoader />
);
};

export default HeatDaily;
17 changes: 11 additions & 6 deletions src/components/explore/temperature/charts/temperatureDaily.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { colors } from "@dhis2/ui";
import { animation, credits, getDailyPeriod } from "../../../../utils/chart";
import { toCelcius } from "../../../../utils/calc";

const getChart = (name, data, settings) => {
const getChart = (name, data, settings, isPlugin) => {
const { tempMin, tempMax } = settings;

const series = data.map((d) => ({
Expand All @@ -19,11 +19,13 @@ const getChart = (name, data, settings) => {

return {
title: {
text: i18n.t("{{name}}: Daily temperatures {{period}}", {
name,
period: getDailyPeriod(data),
nsSeparator: ";",
}),
text: !isPlugin
? i18n.t("{{name}}: Daily temperatures {{period}}", {
name,
period: getDailyPeriod(data),
nsSeparator: ";",
})
: "",
},
credits,
tooltip: {
Expand Down Expand Up @@ -78,6 +80,9 @@ const getChart = (name, data, settings) => {
zIndex: 0,
},
],
exporting: {
enabled: !isPlugin,
},
};
};

Expand Down
Loading