diff --git a/d2.config.js b/d2.config.js index a4e9d6e4..f15156a1 100644 --- a/d2.config.js +++ b/d2.config.js @@ -1,8 +1,10 @@ const config = { type: "app", + pluginType: "DASHBOARD", title: "DHIS2 Climate App", entryPoints: { app: "./src/App.js", + plugin: "./src/DashboardPlugin.js", }, }; diff --git a/i18n/en.pot b/i18n/en.pot index 5fcbbaa9..8ccfadec 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: 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" @@ -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 " diff --git a/package.json b/package.json index 1aa25e24..13fedc95 100644 --- a/package.json +++ b/package.json @@ -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, @@ -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", diff --git a/src/DashboardPlugin.js b/src/DashboardPlugin.js new file mode 100644 index 00000000..5a866be0 --- /dev/null +++ b/src/DashboardPlugin.js @@ -0,0 +1,11 @@ +import { DashboardPluginWrapper } from "@dhis2/analytics"; +import React from "react"; +import Plugin from "./components/plugin/Plugin.js"; + +const DashboardPlugin = (props) => ( + + {(parentProps) => } + +); + +export default DashboardPlugin; diff --git a/src/components/Routes.js b/src/components/Routes.js index dc80c7ce..fadcc7ea 100644 --- a/src/components/Routes.js +++ b/src/components/Routes.js @@ -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"; @@ -161,6 +162,10 @@ const Routes = () => { path: "settings", element: , }, + { + path: "plugin", + element: , + }, ], }, ]); diff --git a/src/components/explore/Chart.js b/src/components/explore/Chart.js index f88b9633..63b5957c 100644 --- a/src/components/explore/Chart.js +++ b/src/components/explore/Chart.js @@ -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
; + return ( +
+ ); }; Chart.propTypes = { config: PropTypes.object.isRequired, + isPlugin: PropTypes.bool, }; export default Chart; diff --git a/src/components/explore/forecast/DayForecast.js b/src/components/explore/forecast/DayForecast.js index adcd1bf8..43583e84 100644 --- a/src/components/explore/forecast/DayForecast.js +++ b/src/components/explore/forecast/DayForecast.js @@ -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)); @@ -62,7 +62,7 @@ const DayForecast = ({ date, series }) => { {precip ? i18n.t("{{precip}} mm", { precip }) : null} - {avgHumidity}% + {!isPlugin && {avgHumidity}%} {maxWind} m/s ); diff --git a/src/components/explore/forecast/Forecast.js b/src/components/explore/forecast/Forecast.js index 279c36d5..9109a668 100644 --- a/src/components/explore/forecast/Forecast.js +++ b/src/components/explore/forecast/Forecast.js @@ -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"; @@ -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(); @@ -57,7 +58,9 @@ const Forecast = () => { {i18n.t("Evening")} {i18n.t("Max/min temp.")} {i18n.t("Precip.")} - {i18n.t("Rel. humidity")} + {!isPlugin && ( + {i18n.t("Rel. humidity")} + )} {i18n.t("Wind")} @@ -67,6 +70,7 @@ const Forecast = () => { key={date} date={date} series={timeseries.filter((t) => t.time.startsWith(date))} + isPlugin={isPlugin} /> ))} @@ -85,24 +89,30 @@ const Forecast = () => { ECMWF HRES
-
- {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 } - )} -
+ {!isPlugin && ( +
+ {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 } + )} +
+ )} ); }; +Forecast.propTypes = { + isPlugin: PropTypes.bool, +}; + export default Forecast; diff --git a/src/components/explore/heat/charts/thermalComfortDaily.js b/src/components/explore/heat/charts/thermalComfortDaily.js index cfa4321d..48f63a67 100644 --- a/src/components/explore/heat/charts/thermalComfortDaily.js +++ b/src/components/explore/heat/charts/thermalComfortDaily.js @@ -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 = @@ -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"]), @@ -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, @@ -142,6 +144,9 @@ const getChart = (name, data, settings) => { zIndex: 0, }, ], + exporting: { + enabled: !isPlugin, + }, }; }; diff --git a/src/components/explore/heat/plugin/HeatDaily.js b/src/components/explore/heat/plugin/HeatDaily.js new file mode 100644 index 00000000..41b4590d --- /dev/null +++ b/src/components/explore/heat/plugin/HeatDaily.js @@ -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 ? ( + + ) : ( + + ); +}; + +export default HeatDaily; diff --git a/src/components/explore/temperature/charts/temperatureDaily.js b/src/components/explore/temperature/charts/temperatureDaily.js index 8706e234..694ca059 100644 --- a/src/components/explore/temperature/charts/temperatureDaily.js +++ b/src/components/explore/temperature/charts/temperatureDaily.js @@ -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) => ({ @@ -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: { @@ -78,6 +80,9 @@ const getChart = (name, data, settings) => { zIndex: 0, }, ], + exporting: { + enabled: !isPlugin, + }, }; }; diff --git a/src/components/explore/temperature/charts/temperatureMonthly.js b/src/components/explore/temperature/charts/temperatureMonthly.js index efd5a00d..2366fc30 100644 --- a/src/components/explore/temperature/charts/temperatureMonthly.js +++ b/src/components/explore/temperature/charts/temperatureMonthly.js @@ -8,7 +8,14 @@ import { } from "../../../../utils/chart"; import { getTimeFromId, toCelcius } from "../../../../utils/calc"; -const getChartConfig = (name, data, normals, referencePeriod, settings) => { +const getChartConfig = ( + name, + data, + normals, + referencePeriod, + settings, + isPlugin = false +) => { const { tempMin, tempMax } = settings; const series = data.map((d) => ({ @@ -34,17 +41,21 @@ const getChartConfig = (name, data, normals, referencePeriod, settings) => { return { title: { - text: i18n.t("{{name}}: Monthly temperatures {{period}}", { - name, - period: getMonthlyPeriod(data), - nsSeparator: ";", - }), + text: !isPlugin + ? i18n.t("{{name}}: Monthly temperatures {{period}}", { + name, + period: getMonthlyPeriod(data), + nsSeparator: ";", + }) + : "", }, subtitle: { text: i18n.t("Normals from reference period: {{period}}", { period: referencePeriod.id, nsSeparator: ";", }), + floating: false, + verticalAlign: "top", }, credits, tooltip: { @@ -109,6 +120,9 @@ const getChartConfig = (name, data, normals, referencePeriod, settings) => { zIndex: 1, }, ], + exporting: { + enabled: !isPlugin, + }, }; }; diff --git a/src/components/explore/temperature/plugin/TemperatureDaily.js b/src/components/explore/temperature/plugin/TemperatureDaily.js new file mode 100644 index 00000000..2a748673 --- /dev/null +++ b/src/components/explore/temperature/plugin/TemperatureDaily.js @@ -0,0 +1,31 @@ +import PropTypes from "prop-types"; +import Chart from "../../Chart"; +import DataLoader from "../../../shared/DataLoader"; +import getDailyConfig from "../charts/temperatureDaily"; +import useEarthEngineTimeSeries from "../../../../hooks/useEarthEngineTimeSeries"; +import useAppSettings from "../../../../hooks/useAppSettings"; +import { era5Daily } from "../../../../data/datasets"; + +const TemperatureDaily = ({ orgUnit, period }) => { + const { settings } = useAppSettings(); + + const data = useEarthEngineTimeSeries(era5Daily, period, orgUnit); + + const isPlugin = true; + + return data ? ( + + ) : ( + + ); +}; + +TemperatureDaily.propTypes = { + orgUnit: PropTypes.object.isRequired, + period: PropTypes.object.isRequired, +}; + +export default TemperatureDaily; diff --git a/src/components/explore/temperature/plugin/TemperatureMonthly.js b/src/components/explore/temperature/plugin/TemperatureMonthly.js new file mode 100644 index 00000000..c658a56f --- /dev/null +++ b/src/components/explore/temperature/plugin/TemperatureMonthly.js @@ -0,0 +1,46 @@ +import PropTypes from "prop-types"; +import Chart from "../../Chart"; +import DataLoader from "../../../shared/DataLoader"; +import getMonthlyConfig from "../charts/temperatureMonthly"; +import useEarthEngineTimeSeries from "../../../../hooks/useEarthEngineTimeSeries"; +import useEarthEngineClimateNormals from "../../../../hooks/useEarthEngineClimateNormals"; +import useAppSettings from "../../../../hooks/useAppSettings"; +import { era5Monthly, era5MonthlyNormals } from "../../../../data/datasets"; + +const TemperatureMonthly = ({ orgUnit, period, referencePeriod }) => { + const { settings } = useAppSettings(); + + const data = useEarthEngineTimeSeries(era5Monthly, period, orgUnit); + + const normals = useEarthEngineClimateNormals( + era5MonthlyNormals, + referencePeriod, + orgUnit + ); + + const isPlugin = true; + + return data && normals ? ( + + ) : ( + + ); +}; + +TemperatureMonthly.propTypes = { + orgUnit: PropTypes.object.isRequired, + period: PropTypes.object.isRequired, + referencePeriod: PropTypes.object.isRequired, +}; + +export default TemperatureMonthly; diff --git a/src/components/import/OrgUnits.js b/src/components/import/OrgUnits.js index af566be0..5d180d3f 100644 --- a/src/components/import/OrgUnits.js +++ b/src/components/import/OrgUnits.js @@ -1,6 +1,6 @@ import PropTypes from "prop-types"; import i18n from "@dhis2/d2-i18n"; -import OrgUnitTree from "./OrgUnitTree"; +import OrgUnitTree from "../shared/OrgUnitTree"; import OrgUnitLevel from "./OrgUnitLevel"; import styles from "./styles/OrgUnits.module.css"; @@ -12,6 +12,7 @@ const OrgUnits = ({ selected = {}, onChange }) => { return ( <> +

{i18n.t("Parent organisation unit")}

onChange({ parent, level })} diff --git a/src/components/plugin/Configuration.js b/src/components/plugin/Configuration.js new file mode 100644 index 00000000..8bd28591 --- /dev/null +++ b/src/components/plugin/Configuration.js @@ -0,0 +1,92 @@ +import { useEffect, useState } from "react"; +import i18n from "@dhis2/d2-i18n"; +import { Button } from "@dhis2/ui"; +import DataSelect from "./DataSelect"; +import OrgUnitTree from "../shared/OrgUnitTree"; +import useOrgUnit from "../../hooks/useOrgUnit"; +import { datasets } from "./DataSelect"; +import styles from "./styles/Configuration.module.css"; + +const noGeometryWarning = i18n.t( + "Selected org unit has no geometry, which is required to display data." +); + +const onlyPointWarning = i18n.t( + "Data is only available for facilities (point locations)." +); + +const getPluginConfig = (datasetId, orgUnit) => { + const { id: orgUnitId, properties } = orgUnit; + + if (datasetId === "forecast10days") { + return { + id: `${orgUnitId}/forecast10days`, + url: `#/explore/${orgUnitId}/forecast10days`, + title: `${properties.name}: ${i18n.t("Weather forecast")}`, + display: "forecast10days", + orgUnitId, + }; + } +}; + +const Configuration = ({ config, onDone }) => { + const [datasetId, setDatasetId] = useState(); + const [orgUnit, setOrgUnit] = useState(null); + const loadedOrgUnit = useOrgUnit(orgUnit?.id); + const dataset = datasets.find((d) => d.id === datasetId); + const isLoaded = !!loadedOrgUnit; + const hasGeometry = loadedOrgUnit?.geometry; + const geometryType = loadedOrgUnit?.geometry?.type; + const isValid = + dataset && + orgUnit && + isLoaded && + hasGeometry && + (dataset.geometryType ? geometryType === dataset.geometryType : true); + + const onDoneClick = () => onDone(getPluginConfig(datasetId, loadedOrgUnit)); + + useEffect(() => { + if (config) { + setDatasetId(config.display); + setOrgUnit({ id: config.orgUnitId }); + } + }, [config]); + + return ( +
+ + {datasetId && (!config || loadedOrgUnit) && ( +
+

{i18n.t("Choose an organisation unit")}

+
+ +
+ {isLoaded && !hasGeometry && ( +
{noGeometryWarning}
+ )} + {dataset.geometryType && + geometryType && + geometryType !== dataset.geometryType && ( +
{onlyPointWarning}
+ )} +
+ )} +
+ +
+
+ ); +}; + +export default Configuration; diff --git a/src/components/plugin/DataSelect.js b/src/components/plugin/DataSelect.js new file mode 100644 index 00000000..d49effb2 --- /dev/null +++ b/src/components/plugin/DataSelect.js @@ -0,0 +1,32 @@ +import i18n from "@dhis2/d2-i18n"; +import { SingleSelectField, SingleSelectOption } from "@dhis2/ui"; +import styles from "./styles/DataSelect.module.css"; + +export const datasets = [ + { + id: "forecast10days", + name: "10 days forecast", + path: "/forecast10days", + geometryType: "Point", + }, +]; + +const DataSelect = ({ value, onChange }) => { + const dataset = datasets.find((d) => d.id === value); + return ( +
+ onChange(selected)} + > + {datasets.map((d, i) => ( + + ))} + + {dataset?.description &&

{dataset.description}

} +
+ ); +}; + +export default DataSelect; diff --git a/src/components/plugin/OrgUnitLoader.js b/src/components/plugin/OrgUnitLoader.js new file mode 100644 index 00000000..fbebe865 --- /dev/null +++ b/src/components/plugin/OrgUnitLoader.js @@ -0,0 +1,21 @@ +import { useEffect } from "react"; +import PluginContent from "./PluginContent"; +import DataLoader from "../shared/DataLoader"; +import exploreStore from "../../store/exploreStore"; +import useOrgUnit from "../../hooks/useOrgUnit"; + +const OrgUnitLoader = (props) => { + const loadedOrgUnit = useOrgUnit(props.orgUnitId); + const { orgUnit, setOrgUnit } = exploreStore(); + + useEffect(() => { + setOrgUnit(loadedOrgUnit); + return () => { + setOrgUnit(null); + }; + }, [loadedOrgUnit]); + + return orgUnit ? : ; +}; + +export default OrgUnitLoader; diff --git a/src/components/plugin/Plugin.js b/src/components/plugin/Plugin.js new file mode 100644 index 00000000..a204cbcd --- /dev/null +++ b/src/components/plugin/Plugin.js @@ -0,0 +1,82 @@ +import { useState, useEffect } from "react"; +import i18n from "@dhis2/d2-i18n"; +import { Button } from "@dhis2/ui"; +import OrgUnitLoader from "./OrgUnitLoader"; +import Configuration from "./Configuration"; +import usePluginConfig from "../../hooks/usePluginConfig"; +import styles from "./styles/Plugin.module.css"; + +const Plugin = (props) => { + const { dashboardItemId, setDashboardItemDetails, dashboardMode } = props; + const [editMode, setEditMode] = useState(); + const { config, loading, setPluginConfig, clearPluginConfig } = + usePluginConfig(dashboardItemId); + + useEffect(() => { + if (config && setDashboardItemDetails) { + setDashboardItemDetails({ + itemTitle: config.title, + appUrl: config.url, + onRemove: clearPluginConfig, + }); + } + }, [setDashboardItemDetails, config]); + + useEffect(() => { + if ( + dashboardMode === "edit" && + !loading && + !config && + editMode === undefined + ) { + setEditMode(true); + } + }, [editMode, config, loading, dashboardMode]); + + if (editMode) { + return ( +
+ { + setPluginConfig(config); + setEditMode(false); + }} + /> +
+ ); + } + + if (loading) { + return ( +
+
{i18n.t("Loading")}...
+
+ ); + } + + return ( + <> +
+ {config ? ( + + ) : ( +
+ {i18n.t( + "No data source. Edit this dashboard to configure this item." + )} +
+ )} +
+ {dashboardMode === "edit" && ( +
+ +
+ )} + + ); +}; + +export default Plugin; diff --git a/src/components/plugin/PluginContent.js b/src/components/plugin/PluginContent.js new file mode 100644 index 00000000..79542712 --- /dev/null +++ b/src/components/plugin/PluginContent.js @@ -0,0 +1,19 @@ +import Forecast from "../explore/forecast/Forecast"; + +const displays = { + forecast10days: Forecast, +}; + +const PluginContent = (props) => { + const { display } = props; + + const Display = displays[display]; + + if (!Display) { + return
Display not found (this should not happen)
; + } + + return ; +}; + +export default PluginContent; diff --git a/src/components/plugin/PluginPage.js b/src/components/plugin/PluginPage.js new file mode 100644 index 00000000..2e9f928d --- /dev/null +++ b/src/components/plugin/PluginPage.js @@ -0,0 +1,31 @@ +import { useState } from "react"; +import Plugin from "./Plugin"; +import styles from "./styles/PluginPage.module.css"; + +const PluginPage = () => { + const [details, setDetails] = useState(null); + + return ( +
+

Plugin

+
+
+
+

{details ? details.itemTitle : "Climate Data"}

+
+
+
+ +
+
+
+
+
+ ); +}; + +export default PluginPage; diff --git a/src/components/plugin/styles/Configuration.module.css b/src/components/plugin/styles/Configuration.module.css new file mode 100644 index 00000000..11bb4139 --- /dev/null +++ b/src/components/plugin/styles/Configuration.module.css @@ -0,0 +1,45 @@ +.configuration { + padding: 0 10px 10px 10px; + height: 100%; + display: flex; + flex-direction: column; + /* background-color: lightblue; */ +} + +.configuration h3 { + font-size: 14px; + line-height: 19px; + font-weight: normal; + color: rgb(33, 41, 52); + margin-top: 16px; + margin-bottom: 3px; +} + +.orgUnitSelect { + flex: 1 1 auto; + /* background-color: antiquewhite; */ + overflow-y: hidden; +} + +.orgUnitTree { + border: 1px solid #e0e0e0; + height: calc(100% - 60px); + /* overflow-y: auto; */ + overflow-y: auto; +} + +.validation { + color: rgb(187, 70, 13); + margin-top: 6px; + font-size: 13px; + line-height: 14px; +} + +.actions { + flex: 0 0 40px; + /* background-color: red; */ +} + +.doneButton { + margin-top: 10px; +} diff --git a/src/components/plugin/styles/DataSelect.module.css b/src/components/plugin/styles/DataSelect.module.css new file mode 100644 index 00000000..8303af51 --- /dev/null +++ b/src/components/plugin/styles/DataSelect.module.css @@ -0,0 +1,3 @@ +.dataSelect { + flex: 0 0 60px; +} diff --git a/src/components/plugin/styles/Plugin.module.css b/src/components/plugin/styles/Plugin.module.css new file mode 100644 index 00000000..18df1eee --- /dev/null +++ b/src/components/plugin/styles/Plugin.module.css @@ -0,0 +1,22 @@ +.container { + width: 100%; + height: 100%; + overflow: auto; + position: relative; +} + +.message { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + color: var(--colors-grey800); + font-size: 14px; + font-style: italic; +} + +.editButton { + position: absolute; + right: 10px; + bottom: 10px; +} diff --git a/src/components/plugin/styles/PluginPage.module.css b/src/components/plugin/styles/PluginPage.module.css new file mode 100644 index 00000000..e12a1e8e --- /dev/null +++ b/src/components/plugin/styles/PluginPage.module.css @@ -0,0 +1,52 @@ +.pluginPage { + height: calc(100% - 50px); +} + +.dashboard { + padding: 50px; + height: calc(100% - 50px); + margin-right: 30px; + background-color: #f4f6f8; +} + +.dashboardItem { + position: absolute; + background-color: #fff; + border-radius: 3px; + box-shadow: 0 0 3px 0 #999; + width: 550px; + height: 500px; + display: flex; + flex-direction: column; + overflow: hidden !important; +} + +.dashboardItemHeader { + display: flex; + margin: 8px; + line-height: 30px; +} + +.dashboardItemHeader p { + color: rgb(64, 75, 90); + font-size: 14px; + font-weight: 700; + margin: 0; + padding: 0; +} + +.dashboardItemContent { + box-sizing: border-box; + margin-block-end: 4px; + margin-block-start: 0; + margin-inline-end: 4px; + margin-inline-start: 4px; + flex: 1 1; + overflow: hidden; + position: relative; +} + +.plugin { + overflow: hidden !important; + height: 100%; +} diff --git a/src/components/import/OrgUnitTree.js b/src/components/shared/OrgUnitTree.js similarity index 54% rename from src/components/import/OrgUnitTree.js rename to src/components/shared/OrgUnitTree.js index 48522a1d..f848e577 100644 --- a/src/components/import/OrgUnitTree.js +++ b/src/components/shared/OrgUnitTree.js @@ -1,34 +1,38 @@ import PropTypes from "prop-types"; -import i18n from "@dhis2/d2-i18n"; import { useEffect } from "react"; import { OrganisationUnitTree } from "@dhis2/ui"; import useOrgUnitRoots from "../../hooks/useOrgUnitRoots"; -const OrgUnitTree = ({ orgUnit, onChange }) => { +const OrgUnitTree = ({ orgUnit, rootIsDefault = true, onChange }) => { const { roots, error } = useOrgUnitRoots(); // Set for root node as default useEffect(() => { - if (roots && !orgUnit) { + if (rootIsDefault && roots && !orgUnit) { const [root] = roots; onChange({ ...root, selected: [root.path] }); } - }, [roots, orgUnit, onChange]); + }, [rootIsDefault, roots, orgUnit, onChange]); + + const path = orgUnit?.properties?.path; + const pathArray = path?.split("/"); + + const initiallyExpanded = + pathArray?.length > 2 + ? [pathArray.slice(0, -1).join("/")] + : roots?.map((r) => r.path); // The warnings "The query should be static, don't create it within the render loop!" // comes from the OrganisationUnitTree component: - // https://dhis2.slack.com/archives/C0BP0RABF/p1641544953003000 + // https://dhis2.slack.com/archives/C0BP0RABF/p1641544953003000x return roots ? ( -
-

{i18n.t("Parent organisation unit")}

- r.id)} - selected={orgUnit?.selected} - onChange={onChange} - singleSelection={true} - initiallyExpanded={roots.map((r) => r.path)} - /> -
+ r.id)} + selected={orgUnit?.selected || path ? [path] : undefined} + onChange={onChange} + singleSelection={true} + initiallyExpanded={initiallyExpanded} + /> ) : error ? (
{error.message}
) : null; @@ -36,6 +40,7 @@ const OrgUnitTree = ({ orgUnit, onChange }) => { OrgUnitTree.propTypes = { orgUnit: PropTypes.object, + rootIsDefault: PropTypes.bool, onChange: PropTypes.func.isRequired, }; diff --git a/src/hooks/useAppSettings.js b/src/hooks/useAppSettings.js index f06853d7..e22d37ef 100644 --- a/src/hooks/useAppSettings.js +++ b/src/hooks/useAppSettings.js @@ -1,5 +1,6 @@ import { useState, useCallback, useEffect } from "react"; import { useDataEngine } from "@dhis2/app-runtime"; +import { createKeyInNamespace } from "../utils/dataStore"; const APP_NAMESPACE = "CLIMATE_DATA"; const SETTINGS_KEY = "settings"; @@ -20,25 +21,24 @@ const useAppSettings = () => { .then(({ dataStore }) => { if (dataStore.includes(APP_NAMESPACE)) { // Fetch settings if namespace/keys exists in data store - engine.query({ settings: { resource } }).then(({ settings }) => { - setSettings(settings); - setLoading(false); - }); - } else { - // Create namespace/keys if missing in data store engine - .mutate({ - resource, - type: "create", - data: {}, + .query({ settings: { resource } }) + .then(({ settings }) => { + setSettings(settings); + setLoading(false); }) - .then((response) => { - if (response.httpStatusCode === 201) { - setLoading(false); - } else { - setError(response); + .catch((error) => { + if (error.message.includes("(404)")) { + // key not found + createKeyInNamespace(engine, resource) + .then(() => setLoading(false)) + .catch(setError); } - }) + }); + } else { + // Create namespace/keys if missing in data store + createKeyInNamespace(engine, resource) + .then(() => setLoading(false)) .catch(setError); } }); diff --git a/src/hooks/useOrgUnit.js b/src/hooks/useOrgUnit.js index 62d68085..047e9a64 100644 --- a/src/hooks/useOrgUnit.js +++ b/src/hooks/useOrgUnit.js @@ -21,6 +21,7 @@ const useOrgUnit = (id) => { geometry: ou.geometry, properties: { name: ou.displayName, + path: ou.path, }, }), }); diff --git a/src/hooks/usePluginConfig.js b/src/hooks/usePluginConfig.js new file mode 100644 index 00000000..c41369db --- /dev/null +++ b/src/hooks/usePluginConfig.js @@ -0,0 +1,113 @@ +import { useState, useCallback, useEffect } from "react"; +import { useDataEngine } from "@dhis2/app-runtime"; +import { createKeyInNamespace } from "../utils/dataStore"; + +const APP_NAMESPACE = "CLIMATE_DATA"; +const PLUGINS_KEY = "plugins"; + +const resource = `dataStore/${APP_NAMESPACE}/${PLUGINS_KEY}`; + +// TODO: Only load one plugin config at a time +const usePluginConfig = (pluginId) => { + const [loading, setLoading] = useState(true); + const [plugins, setPlugins] = useState(); + const [error, setError] = useState(); + const engine = useDataEngine(); + + const config = plugins?.[pluginId]; + + // Fetch plugin configs / create namspace/key if missing + const getPlugins = useCallback(() => { + setLoading(true); + engine + .query({ dataStore: { resource: "dataStore" } }) + .then(({ dataStore }) => { + if (dataStore.includes(APP_NAMESPACE)) { + // Fetch plugin configs if namespace/keys exists in data store + engine + .query({ plugins: { resource } }) + .then(({ plugins }) => { + setPlugins(plugins); + setLoading(false); + }) + .catch((error) => { + if (error.message.includes("(404)")) { + // key not found + createKeyInNamespace(engine, resource) + .then(() => setLoading(false)) + .catch(setError); + } + }); + } else { + createKeyInNamespace(engine, resource) + .then(() => setLoading(false)) + .catch(setError); + } + }); + }, [engine]); + + const setPluginConfig = useCallback( + (config) => { + engine + .mutate({ + resource, + type: "update", + data: { + ...plugins, + [pluginId]: config, + }, + }) + .then((response) => { + if (response.httpStatusCode === 200) { + getPlugins(); + } else { + setError(response); + } + }) + .catch(setError); + }, + [engine, pluginId, plugins, getPlugins] + ); + + const clearPluginConfig = useCallback( + () => + new Promise((resolve, reject) => { + const { [pluginId]: removedPlugin, ...remainingPlugins } = plugins; + + engine + .mutate({ + resource, + type: "update", + data: remainingPlugins, + }) + .then((response) => { + if (response.httpStatusCode === 200) { + getPlugins(); + resolve(response); + } else { + setError(response); + reject(response); + } + }) + .catch((error) => { + setError(error); + reject(error); + }); + }), + [engine, pluginId, plugins, getPlugins] + ); + + useEffect(() => { + getPlugins(); + }, [engine, getPlugins]); + + return { + config, + loading: !config && loading, + error, + setPluginConfig, + clearPluginConfig, + }; +}; + +export default usePluginConfig; diff --git a/src/utils/dataStore.js b/src/utils/dataStore.js new file mode 100644 index 00000000..ffaa5000 --- /dev/null +++ b/src/utils/dataStore.js @@ -0,0 +1,17 @@ +export const createKeyInNamespace = (engine, resource) => + new Promise((resolve, reject) => { + engine + .mutate({ + resource, + type: "create", + data: {}, + }) + .then((response) => { + if (response.httpStatusCode === 201) { + resolve(response); + } else { + reject(response); + } + }) + .catch(reject); + }); diff --git a/yarn.lock b/yarn.lock index aa10635a..e494d9b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1110,7 +1110,15 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.10.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": +"@babel/runtime-corejs2@^7.4.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.24.7.tgz#28e73d50c44812060a58548c5096be4243ee3ee5" + integrity sha512-+Lf6xofiPZLtFwNkpjGHPgJck4b22Yo8h9+WHf3bEbS4ikOyOMNtJk6HSTolEQ2irH1XSoeguaCkrkcgyThrMA== + dependencies: + core-js "^2.6.12" + regenerator-runtime "^0.14.0" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== @@ -1855,6 +1863,26 @@ classnames "^2.3.1" prop-types "^15.7.2" +"@dhis2/analytics@git+https://github.com/d2-ci/analytics.git#dca4316cdf2a8fd9482dfe1244575baad7ffe228": + version "26.7.3" + resolved "git+https://github.com/d2-ci/analytics.git#dca4316cdf2a8fd9482dfe1244575baad7ffe228" + dependencies: + "@dhis2/multi-calendar-dates" "1.0.0" + "@dnd-kit/core" "^6.0.7" + "@dnd-kit/sortable" "^7.0.2" + "@dnd-kit/utilities" "^3.2.1" + "@react-hook/debounce" "^4.0.0" + classnames "^2.3.1" + crypto-js "^4.1.1" + d2-utilizr "^0.2.16" + d3-color "^1.2.3" + highcharts "^10.3.3" + lodash "^4.17.21" + markdown-it "^13.0.1" + mathjs "^9.4.2" + react-beautiful-dnd "^10.1.1" + resize-observer-polyfill "^1.5.1" + "@dhis2/app-adapter@11.7.0": version "11.7.0" resolved "https://registry.yarnpkg.com/@dhis2/app-adapter/-/app-adapter-11.7.0.tgz#5ceb982dc377dd4cdcf70ce1cbc5b0a038780ca6" @@ -2005,7 +2033,7 @@ i18next "^10.3" moment "^2.24.0" -"@dhis2/multi-calendar-dates@1.0.0-alpha.27": +"@dhis2/multi-calendar-dates@1.0.0", "@dhis2/multi-calendar-dates@1.0.0-alpha.27": version "1.0.0-alpha.27" resolved "https://registry.yarnpkg.com/@dhis2/multi-calendar-dates/-/multi-calendar-dates-1.0.0-alpha.27.tgz#01bacfba4fdcfd8125fc3493041352ec136f6233" integrity sha512-gaWQ2BclRL6U36FcmGKfl26qS7B2Q+4EGuz5ckYOHblgbkiyh5rZ3JQ5uOvdKIWoPcsOhBri+ZuGc8T9/MTNeQ== @@ -2125,6 +2153,37 @@ "@dhis2/ui-icons" "9.11.1" prop-types "^15.7.2" +"@dnd-kit/accessibility@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.0.tgz#1054e19be276b5f1154ced7947fc0cb5d99192e0" + integrity sha512-ea7IkhKvlJUv9iSHJOnxinBcoOI3ppGnnL+VDJ75O45Nss6HtZd8IdN8touXPDtASfeI2T2LImb8VOZcL47wjQ== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@^6.0.7": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.1.0.tgz#e81a3d10d9eca5d3b01cbf054171273a3fe01def" + integrity sha512-J3cQBClB4TVxwGo3KEjssGEXNJqGVWx17aRTZ1ob0FliR5IjYgTxl5YJbKTzA6IzrtelotH19v6y7uoIRUZPSg== + dependencies: + "@dnd-kit/accessibility" "^3.1.0" + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/sortable@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-7.0.2.tgz#791d550872457f3f3c843e00d159b640f982011c" + integrity sha512-wDkBHHf9iCi1veM834Gbk1429bd4lHX4RpAwT0y2cHLf246GAvU2sVw/oxWNpPKQNQRQaeGXhAVgrOl1IT+iyA== + dependencies: + "@dnd-kit/utilities" "^3.2.0" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.0", "@dnd-kit/utilities@^3.2.1", "@dnd-kit/utilities@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b" + integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg== + dependencies: + tslib "^2.0.0" + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2523,6 +2582,13 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== +"@react-hook/debounce@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@react-hook/debounce/-/debounce-4.0.0.tgz#5da87e7bfa158cfe2830ffc997dc1b755e261379" + integrity sha512-706Xcg+KKWHk9BuZQUQ0ZQKp9zhv3/MbqFenWVfHcynYpSGRVwQTzJRGvPxvsdtXxJv+HfgKTY/O/hEejakwmA== + dependencies: + "@react-hook/latest" "^1.0.2" + "@react-hook/latest@^1.0.2": version "1.0.3" resolved "https://registry.yarnpkg.com/@react-hook/latest/-/latest-1.0.3.tgz#c2d1d0b0af8b69ec6e2b3a2412ba0768ac82db80" @@ -4556,6 +4622,11 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== +complex.js@^2.0.15: + version "2.1.1" + resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.1.1.tgz#0675dac8e464ec431fb2ab7d30f41d889fb25c31" + integrity sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg== + compress-commons@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610" @@ -4674,6 +4745,11 @@ core-js-pure@^3.23.3: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.38.0.tgz#bc802cd152e33d5b0ec733b656c71cb847cac701" integrity sha512-8balb/HAXo06aHP58mZMtXgD8vcnXz9tUDePgqBgJgKdmTlMt+jw3ujqniuBDQXMvTzxnMpxHFeuSM3g1jWQuQ== +core-js@^2.6.12: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + core-js@^3.19.2: version "3.38.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.38.0.tgz#8acb7c050bf2ccbb35f938c0d040132f6110f636" @@ -4768,6 +4844,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crypto-js@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -4785,6 +4866,13 @@ css-blank-pseudo@^3.0.3: dependencies: postcss-selector-parser "^6.0.9" +css-box-model@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-declaration-sorter@^6.3.1: version "6.4.1" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71" @@ -4968,6 +5056,24 @@ csstype@^3.0.2: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +d2-utilizr@^0.2.16: + version "0.2.16" + resolved "https://registry.yarnpkg.com/d2-utilizr/-/d2-utilizr-0.2.16.tgz#b71df7ca8c7ab5125ca8bdb4899611bc6782a754" + integrity sha512-8Cqwe/3TIsHeLfRVsWFKYqRrY3ZzuHAJqkEMCPGW9gyNCAAnTPVjROFwBwonv0zodQhVntn1DlJCay/GTBPj1A== + dependencies: + lodash.isboolean "^3.0.3" + lodash.isfunction "^3.0.8" + lodash.ismap "^4.3.0" + lodash.isnumber "^3.0.3" + lodash.isobject "^3.0.2" + lodash.isset "^4.3.0" + lodash.isstring "^4.0.1" + +d3-color@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" + integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== + damerau-levenshtein@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -5042,7 +5148,7 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== -decimal.js@^10.2.1: +decimal.js@^10.2.1, decimal.js@^10.3.1: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== @@ -5449,6 +5555,11 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" + integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== + eol@^0.9.1: version "0.9.1" resolved "https://registry.yarnpkg.com/eol/-/eol-0.9.1.tgz#f701912f504074be35c6117a5c4ade49cd547acd" @@ -5619,6 +5730,11 @@ escape-html@^1.0.3, escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +escape-latex@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1" + integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -6281,7 +6397,7 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.3.7: +fraction.js@^4.1.1, fraction.js@^4.3.7: version "4.3.7" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== @@ -6748,6 +6864,13 @@ highcharts@^10.3.3: resolved "https://registry.yarnpkg.com/highcharts/-/highcharts-10.3.3.tgz#b8acca24f2d4b1f2f726540734166e59e07b35c4" integrity sha512-r7wgUPQI9tr3jFDn3XT36qsNwEIZYcfgz4mkKEA6E4nn5p86y+u1EZjazIG4TRkl5/gmGRtkBUiZW81g029RIw== +hoist-non-react-statics@^3.3.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + hoopy@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" @@ -7079,6 +7202,13 @@ internal-slot@^1.0.4, internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -7541,6 +7671,11 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" +javascript-natural-sort@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" + integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw== + jest-changed-files@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" @@ -8314,6 +8449,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +linkify-it@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec" + integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw== + dependencies: + uc.micro "^1.0.1" + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -8389,11 +8531,46 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isfunction@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + +lodash.ismap@^4.3.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.ismap/-/lodash.ismap-4.4.2.tgz#836bf06dee57fd3d2aa357bf6946e61d1e77e279" + integrity sha512-djSMwsQ2aRroLLC+xNzJXIFkEkM28FYzNykbBPZpcgdsNV9vx+BIwuMUoSBSf+1f7wB+pym/nlAWCOeI+L8ysw== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isobject@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" + integrity sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA== + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== +lodash.isset@^4.3.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.isset/-/lodash.isset-4.4.2.tgz#d5eecc56b7a97ab588509e4795b3541b1cdb67bb" + integrity sha512-3+m3GgoE5hTnRfbgCvOjGVHp2YAm/+MKpAS2JkaL9b5BISNRT+VkGngS7r3nAAschsx4fdLnWsM4wcDyvu0UCA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -8508,6 +8685,17 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +markdown-it@^13.0.1: + version "13.0.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.2.tgz#1bc22e23379a6952e5d56217fbed881e0c94d536" + integrity sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w== + dependencies: + argparse "^2.0.1" + entities "~3.0.1" + linkify-it "^4.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + match-sorter@^6.0.2: version "6.3.4" resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7" @@ -8516,6 +8704,21 @@ match-sorter@^6.0.2: "@babel/runtime" "^7.23.8" remove-accents "0.5.0" +mathjs@^9.4.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-9.5.2.tgz#e0f3279320dc6f49e45d99c4fcdd8b52231f0462" + integrity sha512-c0erTq0GP503/Ch2OtDOAn50GIOsuxTMjmE00NI/vKJFSWrDaQHRjx6ai+16xYv70yBSnnpUgHZGNf9FR9IwmA== + dependencies: + "@babel/runtime" "^7.15.4" + complex.js "^2.0.15" + decimal.js "^10.3.1" + escape-latex "^1.2.0" + fraction.js "^4.1.1" + javascript-natural-sort "^0.7.1" + seedrandom "^3.0.5" + tiny-emitter "^2.1.0" + typed-function "^2.0.0" + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -8526,6 +8729,11 @@ mdn-data@2.0.4: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -8538,6 +8746,11 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.4" +memoize-one@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-descriptors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" @@ -9916,7 +10129,7 @@ prompts@^2.0.1, prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -10000,6 +10213,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +raf-schd@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -10051,6 +10269,20 @@ react-app-polyfill@^3.0.0: regenerator-runtime "^0.13.9" whatwg-fetch "^3.6.2" +react-beautiful-dnd@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-10.1.1.tgz#d753088d77d7632e77cf8a8935fafcffa38f574b" + integrity sha512-TdE06Shfp56wm28EzjgC56EEMgGI5PDHejJ2bxuAZvZr8CVsbksklsJC06Hxf0MSL7FHbflL/RpkJck9isuxHg== + dependencies: + "@babel/runtime-corejs2" "^7.4.2" + css-box-model "^1.1.1" + memoize-one "^5.0.1" + prop-types "^15.6.1" + raf-schd "^4.0.0" + react-redux "^5.0.7" + redux "^4.0.1" + tiny-invariant "^1.0.4" + react-dev-utils@^12.0.0, react-dev-utils@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" @@ -10108,7 +10340,7 @@ react-final-form@^6.5.3: dependencies: "@babel/runtime" "^7.15.4" -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -10123,6 +10355,11 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + react-popper@^2.2.5: version "2.3.0" resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba" @@ -10140,6 +10377,19 @@ react-query@^3.13.11: broadcast-channel "^3.4.1" match-sorter "^6.0.2" +react-redux@^5.0.7: + version "5.1.2" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57" + integrity sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q== + dependencies: + "@babel/runtime" "^7.1.2" + hoist-non-react-statics "^3.3.0" + invariant "^2.2.4" + loose-envify "^1.1.0" + prop-types "^15.6.1" + react-is "^16.6.0" + react-lifecycles-compat "^3.0.0" + react-refresh@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046" @@ -10267,6 +10517,13 @@ recursive-readdir@^2.2.2: dependencies: minimatch "^3.0.5" +redux@^4.0.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + reflect.getprototypeof@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" @@ -10693,6 +10950,11 @@ schema-utils@^4.0.0, schema-utils@^4.2.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" +seedrandom@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" + integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -11604,6 +11866,16 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== +tiny-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + +tiny-invariant@^1.0.4, tiny-invariant@^1.0.6: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -11710,7 +11982,7 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.3.1: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.3.1: version "2.6.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== @@ -11825,6 +12097,11 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" +typed-function@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.1.0.tgz#ded6f8a442ba8749ff3fe75bc41419c8d46ccc3f" + integrity sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ== + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -11847,6 +12124,11 @@ typescript@^3.6.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + uglify-js@^3.1.4: version "3.19.2" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.2.tgz#319ae26a5fbd18d03c7dc02496cfa1d6f1cd4307"