diff --git a/cypress/elements/chart.js b/cypress/elements/chart.js
index e2f2bdb966..f3db15ca20 100644
--- a/cypress/elements/chart.js
+++ b/cypress/elements/chart.js
@@ -10,8 +10,6 @@ import {
} from '@dhis2/analytics'
const visualizationContainerEl = 'visualization-container'
-const visualizationTitleEl = 'visualization-title'
-const visualizationSubtitleEl = 'visualization-subtitle'
const chartContainerEl = '.highcharts-container'
const highchartsLegendEl = '.highcharts-legend'
const highchartsTitleEl = '.highcharts-title'
@@ -24,11 +22,7 @@ const AOTitleDirtyEl = 'titlebar-dirty'
const timeout = {
timeout: 40000,
}
-const nonHighchartsTypes = [
- VIS_TYPE_OUTLIER_TABLE,
- VIS_TYPE_PIVOT_TABLE,
- VIS_TYPE_SINGLE_VALUE,
-]
+const nonHighchartsTypes = [VIS_TYPE_OUTLIER_TABLE, VIS_TYPE_PIVOT_TABLE]
export const expectVisualizationToBeVisible = (visType = VIS_TYPE_COLUMN) =>
nonHighchartsTypes.includes(visType)
@@ -64,13 +58,11 @@ export const expectChartToContainDimensionItem = (visType, itemName) => {
case VIS_TYPE_GAUGE:
case VIS_TYPE_YEAR_OVER_YEAR_COLUMN:
case VIS_TYPE_YEAR_OVER_YEAR_LINE:
+ case VIS_TYPE_SINGLE_VALUE:
cy.get(highchartsTitleEl)
.should('be.visible')
.and('contain', itemName)
break
- case VIS_TYPE_SINGLE_VALUE:
- cy.getBySel(visualizationTitleEl).should('contain', itemName)
- break
case VIS_TYPE_PIVOT_TABLE:
cy.getBySel('visualization-column-header')
.contains(itemName)
@@ -119,10 +111,7 @@ export const expectChartItemsToHaveLength = (length) =>
cy.get(highchartsChartItemEl).children().should('have.length', length)
export const expectSVTitleToHaveColor = (color) =>
- cy.getBySel(visualizationTitleEl).invoke('attr', 'fill').should('eq', color)
+ cy.get('text.highcharts-title').should('have.css', 'color', color)
export const expectSVSubtitleToHaveColor = (color) =>
- cy
- .getBySel(visualizationSubtitleEl)
- .invoke('attr', 'fill')
- .should('eq', color)
+ cy.get('text.highcharts-subtitle').should('have.css', 'color', color)
diff --git a/cypress/elements/optionsModal/index.js b/cypress/elements/optionsModal/index.js
index b1a74c55fa..037a33ed55 100644
--- a/cypress/elements/optionsModal/index.js
+++ b/cypress/elements/optionsModal/index.js
@@ -81,7 +81,6 @@ export {
expectLegendDisplayStyleToBeText,
expectLegendDisplayStyleToBeFill,
expectSingleValueToHaveTextColor,
- expectSingleValueToNotHaveBackgroundColor,
expectSingleValueToHaveBackgroundColor,
toggleLegendKeyOption,
expectLegendKeyOptionToBeEnabled,
diff --git a/cypress/elements/optionsModal/legend.js b/cypress/elements/optionsModal/legend.js
index 4036add064..94a2ee7883 100644
--- a/cypress/elements/optionsModal/legend.js
+++ b/cypress/elements/optionsModal/legend.js
@@ -5,7 +5,6 @@ const legendKeyContainerEl = 'legend-key-container'
const legendKeyItemEl = 'legend-key-item'
const singleValueTextEl = 'visualization-primary-value'
const singleValueIconEl = 'visualization-icon'
-const singleValueOutputEl = 'visualization-container'
const legendDisplayStrategyByDataItemEl = 'legend-display-strategy-BY_DATA_ITEM'
const legendDisplayStrategyFixedEl = 'legend-display-strategy-FIXED'
const legendDisplayStyleOptionTextEl = 'legend-display-style-option-TEXT'
@@ -76,16 +75,10 @@ export const expectFixedLegendSetToBe = (legendSetName) =>
cy.getBySel(fixedLegendSetSelectEl).should('contain', legendSetName)
export const expectSingleValueToHaveTextColor = (color) =>
- cy.getBySel(singleValueTextEl).invoke('attr', 'fill').should('eq', color)
-
-export const expectSingleValueToNotHaveBackgroundColor = () =>
- cy.getBySel(singleValueOutputEl).should('not.have.attr', 'style')
+ cy.getBySel(singleValueTextEl).should('have.css', 'color', color)
export const expectSingleValueToHaveBackgroundColor = (color) =>
- cy
- .getBySel(singleValueOutputEl)
- .invoke('attr', 'style')
- .should('contain', `background-color: ${color}`)
+ cy.get('rect.highcharts-background').should('have.attr', 'fill', color)
export const expectSingleValueToHaveIconColor = (color) =>
cy
diff --git a/cypress/integration/options/legend.cy.js b/cypress/integration/options/legend.cy.js
index 42015e3aaf..d94f4ad055 100644
--- a/cypress/integration/options/legend.cy.js
+++ b/cypress/integration/options/legend.cy.js
@@ -60,7 +60,6 @@ import {
setItemToType,
clickOptionsModalHideButton,
expectSingleValueToHaveBackgroundColor,
- expectSingleValueToNotHaveBackgroundColor,
changeDisplayStyleToFill,
changeColor,
OPTIONS_TAB_STYLE,
@@ -156,17 +155,19 @@ describe('Options - Legend', () => {
it('applies different styles of legend to a Single Value chart', () => {
const TEST_ITEM = TEST_ITEMS[0]
- const EXPECTED_STANDARD_TEXT_COLOR = '#212934'
- const EXPECTED_CONTRAST_TEXT_COLOR = '#ffffff'
+ const EXPECTED_STANDARD_TEXT_COLOR = 'rgb(33, 41, 52)'
+ const EXPECTED_CONTRAST_TEXT_COLOR = 'rgb(255, 255, 255)'
const EXPECTED_BACKGROUND_COLOR_1 = '#FFFFB2'
- const EXPECTED_TEXT_COLOR_1 = '#FFFFB2'
+ const EXPECTED_TEXT_COLOR_1 = 'rgb(255, 255, 178)'
const EXPECTED_BACKGROUND_COLOR_2 = '#B3402B'
- const EXPECTED_TEXT_COLOR_2 = '#B3402B'
+ const EXPECTED_TEXT_COLOR_2 = 'rgb(179, 64, 43)'
const EXPECTED_CUSTOM_TITLE_COLOR = '#ff7700'
+ const EXPECTED_CUSTOM_TITLE_COLOR_RGB = 'rgb(255, 119, 0)'
const EXPECTED_CUSTOM_SUBTITLE_COLOR = '#ffaa00'
+ const EXPECTED_CUSTOM_SUBTITLE_COLOR_RGB = 'rgb(255, 170, 0)'
const TEST_LEGEND_SET_WITH_CONTRAST = 'Age 15y interval'
- const EXPECTED_STANDARD_TITLE_COLOR = '#212934'
- const EXPECTED_STANDARD_SUBTITLE_COLOR = '#4a5768'
+ const EXPECTED_STANDARD_TITLE_COLOR = 'rgb(33, 41, 52)'
+ const EXPECTED_STANDARD_SUBTITLE_COLOR = 'rgb(74, 87, 104)'
cy.log('navigates to the start page and adds data items')
goToStartPage()
@@ -176,7 +177,7 @@ describe('Options - Legend', () => {
clickDimensionModalUpdateButton()
expectVisualizationToBeVisible(VIS_TYPE_SINGLE_VALUE)
expectSingleValueToHaveTextColor(EXPECTED_STANDARD_TEXT_COLOR)
- expectSingleValueToNotHaveBackgroundColor()
+ expectSingleValueToHaveBackgroundColor('transparent')
cy.log('enables legend')
openOptionsModal(OPTIONS_TAB_LEGEND)
@@ -206,7 +207,7 @@ describe('Options - Legend', () => {
// Legend on text, no contrast, no custom title colors
cy.log('verifies text color legend is applied')
expectSingleValueToHaveTextColor(EXPECTED_TEXT_COLOR_1)
- expectSingleValueToNotHaveBackgroundColor()
+ expectSingleValueToHaveBackgroundColor('transparent')
expectSVTitleToHaveColor(EXPECTED_STANDARD_TITLE_COLOR)
expectSVSubtitleToHaveColor(EXPECTED_STANDARD_SUBTITLE_COLOR)
@@ -225,11 +226,11 @@ describe('Options - Legend', () => {
// Legend on text, with contrast (N/, no custom title colors
cy.log('verifies text color legend is applied')
expectSingleValueToHaveTextColor(EXPECTED_TEXT_COLOR_2)
- expectSingleValueToNotHaveBackgroundColor()
+ expectSingleValueToHaveBackgroundColor('transparent')
expectSVTitleToHaveColor(EXPECTED_STANDARD_TITLE_COLOR)
expectSVSubtitleToHaveColor(EXPECTED_STANDARD_SUBTITLE_COLOR)
- cy.log('changees legend display style to background color')
+ cy.log('changes legend display style to background color')
openOptionsModal(OPTIONS_TAB_LEGEND)
expectLegendDisplayStrategyToBeFixed()
expectLegendDisplayStyleToBeText()
@@ -259,8 +260,8 @@ describe('Options - Legend', () => {
)
expectSingleValueToHaveTextColor(EXPECTED_CONTRAST_TEXT_COLOR)
expectSingleValueToHaveBackgroundColor(EXPECTED_BACKGROUND_COLOR_2)
- expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR)
- expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR)
+ expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR_RGB)
+ expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR_RGB)
cy.log('changes legend display style to text color')
openOptionsModal(OPTIONS_TAB_LEGEND)
@@ -271,12 +272,12 @@ describe('Options - Legend', () => {
clickOptionsModalUpdateButton()
expectVisualizationToBeVisible(VIS_TYPE_SINGLE_VALUE)
- // Legend on text, with contrast, with custom title colo
+ // Legend on text, with contrast, with custom title colors
cy.log('verifies text color legend and custom title colors are applied')
expectSingleValueToHaveTextColor(EXPECTED_TEXT_COLOR_2)
- expectSingleValueToNotHaveBackgroundColor()
- expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR)
- expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR)
+ expectSingleValueToHaveBackgroundColor('transparent')
+ expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR_RGB)
+ expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR_RGB)
cy.log('changes legend display strategy to by data item')
openOptionsModal(OPTIONS_TAB_LEGEND)
@@ -287,12 +288,12 @@ describe('Options - Legend', () => {
clickOptionsModalUpdateButton()
expectVisualizationToBeVisible(VIS_TYPE_SINGLE_VALUE)
- // Legend on text, no contrast, with custom title colo
+ // Legend on text, no contrast, with custom title colors
cy.log('verifies text color legend and custom title colors are applied')
expectSingleValueToHaveTextColor(EXPECTED_TEXT_COLOR_1)
- expectSingleValueToNotHaveBackgroundColor()
- expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR)
- expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR)
+ expectSingleValueToHaveBackgroundColor('transparent')
+ expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR_RGB)
+ expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR_RGB)
cy.log('changes legend display style to background color')
openOptionsModal(OPTIONS_TAB_LEGEND)
@@ -309,8 +310,8 @@ describe('Options - Legend', () => {
)
expectSingleValueToHaveTextColor(EXPECTED_STANDARD_TEXT_COLOR)
expectSingleValueToHaveBackgroundColor(EXPECTED_BACKGROUND_COLOR_1)
- expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR)
- expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR)
+ expectSVTitleToHaveColor(EXPECTED_CUSTOM_TITLE_COLOR_RGB)
+ expectSVSubtitleToHaveColor(EXPECTED_CUSTOM_SUBTITLE_COLOR_RGB)
cy.log('verifies legend key is hidden')
expectLegendKeyToBeHidden()
@@ -605,7 +606,7 @@ describe('Options - Legend', () => {
const TEST_ITEM = TEST_ITEMS[0]
const EXPECTED_FIXED_COLOR = '#c7e9c0'
const valueCellEl = 'visualization-value-cell'
- const EXPECTED_SV_STANDARD_TEXT_COLOR = '#212934'
+ const EXPECTED_SV_STANDARD_TEXT_COLOR = 'rgb(33, 41, 52)'
const EXPECTED_PT_STANDARD_TEXT_COLOR = 'color: rgb(33, 41, 52)'
cy.log('navigates to the start page and adds data items')
diff --git a/package.json b/package.json
index 9047241eb0..e350776a34 100644
--- a/package.json
+++ b/package.json
@@ -43,7 +43,7 @@
"typescript": "^4.8.4"
},
"dependencies": {
- "@dhis2/analytics": "^26.8.7",
+ "@dhis2/analytics": "^26.9.0",
"@dhis2/app-runtime": "^3.10.4",
"@dhis2/app-runtime-adapter-d2": "^1.1.0",
"@dhis2/app-service-datastore": "^1.0.0-beta.3",
diff --git a/public/fonts/NotoSans-Bold.ttf b/public/fonts/NotoSans-Bold.ttf
new file mode 100644
index 0000000000..54ad879b41
Binary files /dev/null and b/public/fonts/NotoSans-Bold.ttf differ
diff --git a/public/fonts/NotoSans-BoldItalic.ttf b/public/fonts/NotoSans-BoldItalic.ttf
new file mode 100644
index 0000000000..530a82835d
Binary files /dev/null and b/public/fonts/NotoSans-BoldItalic.ttf differ
diff --git a/public/fonts/NotoSans-Italic.ttf b/public/fonts/NotoSans-Italic.ttf
new file mode 100644
index 0000000000..27ff1ed60a
Binary files /dev/null and b/public/fonts/NotoSans-Italic.ttf differ
diff --git a/public/fonts/NotoSans-Regular.ttf b/public/fonts/NotoSans-Regular.ttf
new file mode 100644
index 0000000000..10589e277e
Binary files /dev/null and b/public/fonts/NotoSans-Regular.ttf differ
diff --git a/public/fonts/NotoSansArabic-Bold.ttf b/public/fonts/NotoSansArabic-Bold.ttf
new file mode 100644
index 0000000000..311ecd77c5
Binary files /dev/null and b/public/fonts/NotoSansArabic-Bold.ttf differ
diff --git a/public/fonts/NotoSansArabic-Regular.ttf b/public/fonts/NotoSansArabic-Regular.ttf
new file mode 100644
index 0000000000..79359c460b
Binary files /dev/null and b/public/fonts/NotoSansArabic-Regular.ttf differ
diff --git a/public/fonts/NotoSansBengali-Bold.ttf b/public/fonts/NotoSansBengali-Bold.ttf
new file mode 100644
index 0000000000..0dd8fcef77
Binary files /dev/null and b/public/fonts/NotoSansBengali-Bold.ttf differ
diff --git a/public/fonts/NotoSansBengali-Regular.ttf b/public/fonts/NotoSansBengali-Regular.ttf
new file mode 100644
index 0000000000..810c3f4ec9
Binary files /dev/null and b/public/fonts/NotoSansBengali-Regular.ttf differ
diff --git a/public/fonts/NotoSansEthiopic-Bold.ttf b/public/fonts/NotoSansEthiopic-Bold.ttf
new file mode 100644
index 0000000000..872733b479
Binary files /dev/null and b/public/fonts/NotoSansEthiopic-Bold.ttf differ
diff --git a/public/fonts/NotoSansEthiopic-Regular.ttf b/public/fonts/NotoSansEthiopic-Regular.ttf
new file mode 100644
index 0000000000..c493b7b450
Binary files /dev/null and b/public/fonts/NotoSansEthiopic-Regular.ttf differ
diff --git a/public/fonts/NotoSansHebrew-Bold.ttf b/public/fonts/NotoSansHebrew-Bold.ttf
new file mode 100644
index 0000000000..4275d7829d
Binary files /dev/null and b/public/fonts/NotoSansHebrew-Bold.ttf differ
diff --git a/public/fonts/NotoSansHebrew-Regular.ttf b/public/fonts/NotoSansHebrew-Regular.ttf
new file mode 100644
index 0000000000..b44a0db044
Binary files /dev/null and b/public/fonts/NotoSansHebrew-Regular.ttf differ
diff --git a/public/fonts/NotoSansJP-Bold.ttf b/public/fonts/NotoSansJP-Bold.ttf
new file mode 100644
index 0000000000..384f8ebb89
Binary files /dev/null and b/public/fonts/NotoSansJP-Bold.ttf differ
diff --git a/public/fonts/NotoSansJP-Regular.ttf b/public/fonts/NotoSansJP-Regular.ttf
new file mode 100644
index 0000000000..1583096a2d
Binary files /dev/null and b/public/fonts/NotoSansJP-Regular.ttf differ
diff --git a/public/fonts/NotoSansKR-Bold.ttf b/public/fonts/NotoSansKR-Bold.ttf
new file mode 100644
index 0000000000..6cf639eb7d
Binary files /dev/null and b/public/fonts/NotoSansKR-Bold.ttf differ
diff --git a/public/fonts/NotoSansKR-Regular.ttf b/public/fonts/NotoSansKR-Regular.ttf
new file mode 100644
index 0000000000..1b14d32473
Binary files /dev/null and b/public/fonts/NotoSansKR-Regular.ttf differ
diff --git a/public/fonts/NotoSansKhmer-Bold.ttf b/public/fonts/NotoSansKhmer-Bold.ttf
new file mode 100644
index 0000000000..5ce10a6ba7
Binary files /dev/null and b/public/fonts/NotoSansKhmer-Bold.ttf differ
diff --git a/public/fonts/NotoSansKhmer-Regular.ttf b/public/fonts/NotoSansKhmer-Regular.ttf
new file mode 100644
index 0000000000..21097c423b
Binary files /dev/null and b/public/fonts/NotoSansKhmer-Regular.ttf differ
diff --git a/public/fonts/NotoSansLao-Bold.ttf b/public/fonts/NotoSansLao-Bold.ttf
new file mode 100644
index 0000000000..3849db6b0d
Binary files /dev/null and b/public/fonts/NotoSansLao-Bold.ttf differ
diff --git a/public/fonts/NotoSansLao-Regular.ttf b/public/fonts/NotoSansLao-Regular.ttf
new file mode 100644
index 0000000000..aaf30afa09
Binary files /dev/null and b/public/fonts/NotoSansLao-Regular.ttf differ
diff --git a/public/fonts/NotoSansMyanmar-Bold.ttf b/public/fonts/NotoSansMyanmar-Bold.ttf
new file mode 100644
index 0000000000..aef27f0530
Binary files /dev/null and b/public/fonts/NotoSansMyanmar-Bold.ttf differ
diff --git a/public/fonts/NotoSansMyanmar-Regular.ttf b/public/fonts/NotoSansMyanmar-Regular.ttf
new file mode 100644
index 0000000000..f4552f2ee5
Binary files /dev/null and b/public/fonts/NotoSansMyanmar-Regular.ttf differ
diff --git a/public/fonts/NotoSansOriya-Bold.ttf b/public/fonts/NotoSansOriya-Bold.ttf
new file mode 100644
index 0000000000..c53ac4eebc
Binary files /dev/null and b/public/fonts/NotoSansOriya-Bold.ttf differ
diff --git a/public/fonts/NotoSansOriya-Regular.ttf b/public/fonts/NotoSansOriya-Regular.ttf
new file mode 100644
index 0000000000..19e76e3a6f
Binary files /dev/null and b/public/fonts/NotoSansOriya-Regular.ttf differ
diff --git a/public/fonts/NotoSansSC-Bold.ttf b/public/fonts/NotoSansSC-Bold.ttf
new file mode 100644
index 0000000000..b9010dfffb
Binary files /dev/null and b/public/fonts/NotoSansSC-Bold.ttf differ
diff --git a/public/fonts/NotoSansSC-Regular.ttf b/public/fonts/NotoSansSC-Regular.ttf
new file mode 100644
index 0000000000..4d4cadb980
Binary files /dev/null and b/public/fonts/NotoSansSC-Regular.ttf differ
diff --git a/public/fonts/NotoSansSinhala-Bold.ttf b/public/fonts/NotoSansSinhala-Bold.ttf
new file mode 100644
index 0000000000..feddab66bf
Binary files /dev/null and b/public/fonts/NotoSansSinhala-Bold.ttf differ
diff --git a/public/fonts/NotoSansSinhala-Regular.ttf b/public/fonts/NotoSansSinhala-Regular.ttf
new file mode 100644
index 0000000000..a8e869e6e6
Binary files /dev/null and b/public/fonts/NotoSansSinhala-Regular.ttf differ
diff --git a/public/fonts/NotoSansThai-Bold.ttf b/public/fonts/NotoSansThai-Bold.ttf
new file mode 100644
index 0000000000..0d93c1f26b
Binary files /dev/null and b/public/fonts/NotoSansThai-Bold.ttf differ
diff --git a/public/fonts/NotoSansThai-Regular.ttf b/public/fonts/NotoSansThai-Regular.ttf
new file mode 100644
index 0000000000..638e709b13
Binary files /dev/null and b/public/fonts/NotoSansThai-Regular.ttf differ
diff --git a/src/AppWrapper.js b/src/AppWrapper.js
index df06cbd256..da47583cbf 100644
--- a/src/AppWrapper.js
+++ b/src/AppWrapper.js
@@ -5,6 +5,7 @@ import React from 'react'
import { Provider as ReduxProvider } from 'react-redux'
import thunk from 'redux-thunk'
import { App } from './components/App.js'
+import { ChartProvider } from './components/ChartProvider.js'
import UserSettingsProvider, {
UserSettingsCtx,
} from './components/UserSettingsProvider.js'
@@ -33,37 +34,43 @@ const AppWrapper = () => {
return (
-
-
-
- {({ userSettings }) => {
- return userSettings?.uiLocale ? (
-
- {({ d2 }) => {
- if (!d2) {
- // TODO: Handle errors in d2 initialization
- return null
- } else {
- return (
-
- )
- }
- }}
-
- ) : null
- }}
-
-
-
+
+
+
+
+ {(userSettings) => {
+ return userSettings?.uiLocale ? (
+
+ {({ d2 }) => {
+ if (!d2) {
+ // TODO: Handle errors in d2 initialization
+ return null
+ } else {
+ return (
+
+ )
+ }
+ }}
+
+ ) : null
+ }}
+
+
+
+
)
}
diff --git a/src/actions/chart.js b/src/actions/chart.js
deleted file mode 100644
index cf78f68f02..0000000000
--- a/src/actions/chart.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { SET_CHART } from '../reducers/chart.js'
-
-export const acSetChart = (value) => ({
- type: SET_CHART,
- value,
-})
diff --git a/src/actions/index.js b/src/actions/index.js
index 093282825f..55bc750848 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -28,7 +28,6 @@ import {
sGetSettingsDigitGroupSeparator,
} from '../reducers/settings.js'
import { sGetVisualization } from '../reducers/visualization.js'
-import * as fromChart from './chart.js'
import * as fromCurrent from './current.js'
import * as fromDimensions from './dimensions.js'
import * as fromLoader from './loader.js'
@@ -49,7 +48,6 @@ export {
fromMetadata,
fromSettings,
fromUser,
- fromChart,
fromSnackbar,
fromLoader,
}
diff --git a/src/components/ChartProvider.js b/src/components/ChartProvider.js
new file mode 100644
index 0000000000..da11dc9700
--- /dev/null
+++ b/src/components/ChartProvider.js
@@ -0,0 +1,31 @@
+import PropTypes from 'prop-types'
+import React, { createContext, useCallback, useContext, useRef } from 'react'
+
+const throwIfNotInitialized = () => {
+ throw new Error('ChartContext not yet initialized')
+}
+
+export const ChartContext = createContext({
+ getChart: throwIfNotInitialized,
+ setChart: throwIfNotInitialized,
+})
+
+export const useChartContext = () => useContext(ChartContext)
+
+export const ChartProvider = ({ children }) => {
+ const chartRef = useRef(null)
+ const getChart = useCallback(() => chartRef.current, [])
+ const setChart = useCallback((chart = null) => {
+ chartRef.current = chart
+ }, [])
+
+ return (
+
+ {children}
+
+ )
+}
+
+ChartProvider.propTypes = {
+ children: PropTypes.node,
+}
diff --git a/src/components/DownloadMenu/useDownload.js b/src/components/DownloadMenu/useDownload.js
index 6776a08c17..3b68429dd7 100644
--- a/src/components/DownloadMenu/useDownload.js
+++ b/src/components/DownloadMenu/useDownload.js
@@ -1,9 +1,9 @@
import { Analytics, VIS_TYPE_OUTLIER_TABLE } from '@dhis2/analytics'
-import { useConfig, useDataEngine, useDataMutation } from '@dhis2/app-runtime'
+import { useConfig, useDataEngine } from '@dhis2/app-runtime'
import { useCallback } from 'react'
import { useSelector } from 'react-redux'
import { getAnalyticsRequestForOutlierTable } from '../../api/analytics.js'
-import { sGetChart } from '../../reducers/chart.js'
+import { getNotoPdfFontForLocale } from '../../modules/getNotoPdfFontForLocale/index.js'
import { sGetCurrent } from '../../reducers/current.js'
import { sGetSettingsDisplayProperty } from '../../reducers/settings.js'
import {
@@ -11,27 +11,17 @@ import {
sGetUiLayoutColumns,
sGetUiLayoutRows,
} from '../../reducers/ui.js'
+import { useChartContext } from '../ChartProvider.js'
+import { useUserSettings } from '../UserSettingsProvider.js'
import {
DOWNLOAD_TYPE_PLAIN,
DOWNLOAD_TYPE_TABLE,
FILE_FORMAT_HTML_CSS,
FILE_FORMAT_CSV,
- FILE_FORMAT_PNG,
FILE_FORMAT_XLS,
+ FILE_FORMAT_PDF,
} from './constants.js'
-const downloadPngMutation = {
- resource: 'svg.png',
- type: 'create',
- data: ({ formData }) => formData,
-}
-
-const downloadPdfMutation = {
- resource: 'svg.pdf',
- type: 'create',
- data: ({ formData }) => formData,
-}
-
const addCommonParameters = (req, visualization, options) => {
req = req
.withSkipRounding(visualization.skipRounding)
@@ -59,45 +49,48 @@ const useDownload = (relativePeriodDate) => {
const displayProperty = useSelector(sGetSettingsDisplayProperty)
const visualization = useSelector(sGetCurrent)
const visType = useSelector(sGetUiType)
- const chart = useSelector(sGetChart)
const columns = useSelector(sGetUiLayoutColumns)
const rows = useSelector(sGetUiLayoutRows)
const { baseUrl } = useConfig()
+ const { dbLocale } = useUserSettings()
const dataEngine = useDataEngine()
+ const { getChart } = useChartContext()
const analyticsEngine = Analytics.getAnalytics(dataEngine)
- const openDownloadedFileInBlankTab = useCallback((blob) => {
- const url = URL.createObjectURL(blob)
- window.open(url, '_blank')
- }, [])
-
- const [getPng] = useDataMutation(downloadPngMutation, {
- onComplete: openDownloadedFileInBlankTab,
- })
-
- const [getPdf] = useDataMutation(downloadPdfMutation, {
- onComplete: openDownloadedFileInBlankTab,
- })
-
const doDownloadImage = useCallback(
({ format }) => {
- if (!visualization) {
+ const chart = getChart()
+
+ if (!visualization || !chart) {
return false
}
- const formData = {
+ const isPdfExport = format === FILE_FORMAT_PDF
+
+ /* Custom visualization types (i.e. SingleValue) that need some
+ * specific handling for PDF export can read this when they
+ * re-render before exporting. */
+ chart.update({
+ exporting: {
+ chartOptions: { isPdfExport },
+ },
+ })
+
+ chart.exportChartLocal({
+ sourceHeight: 768,
+ sourceWidth: 1024,
+ scale: 1,
+ fallbackToExportServer: false,
+ allowHTML: true,
+ showExportInProgress: true,
filename: visualization.name,
- }
-
- if (chart) {
- formData.svg = chart
- }
-
- format === FILE_FORMAT_PNG
- ? getPng({ formData })
- : getPdf({ formData })
+ type: isPdfExport ? 'application/pdf' : 'image/png',
+ pdfFont: isPdfExport
+ ? getNotoPdfFontForLocale(dbLocale)
+ : undefined,
+ })
},
- [chart, getPdf, getPng, visualization]
+ [dbLocale, getChart, visualization]
)
const doDownloadData = useCallback(
diff --git a/src/components/UserSettingsProvider.js b/src/components/UserSettingsProvider.js
index 5575535ebb..d2e12a1cca 100644
--- a/src/components/UserSettingsProvider.js
+++ b/src/components/UserSettingsProvider.js
@@ -5,14 +5,14 @@ import React, { useContext, useState, useEffect, createContext } from 'react'
export const userSettingsQuery = {
resource: 'userSettings',
params: {
- key: ['keyUiLocale', 'keyAnalysisDisplayProperty'],
+ key: ['keyUiLocale', 'keyDbLocale', 'keyAnalysisDisplayProperty'],
},
}
export const UserSettingsCtx = createContext({})
const UserSettingsProvider = ({ children }) => {
- const [settings, setSettings] = useState([])
+ const [settings, setSettings] = useState({})
const engine = useDataEngine()
useEffect(() => {
@@ -21,8 +21,12 @@ const UserSettingsProvider = ({ children }) => {
userSettings: userSettingsQuery,
})
- const { keyAnalysisDisplayProperty, keyUiLocale, ...rest } =
- userSettings
+ const {
+ keyAnalysisDisplayProperty,
+ keyUiLocale,
+ keyDbLocale,
+ ...rest
+ } = userSettings
setSettings({
...rest,
@@ -32,17 +36,14 @@ const UserSettingsProvider = ({ children }) => {
? 'displayName'
: 'displayShortName',
uiLocale: keyUiLocale,
+ dbLocale: keyDbLocale,
})
}
fetchData()
}, [engine])
return (
-
+
{children}
)
diff --git a/src/components/Visualization/Visualization.js b/src/components/Visualization/Visualization.js
index 1c9f233526..37196d6ada 100644
--- a/src/components/Visualization/Visualization.js
+++ b/src/components/Visualization/Visualization.js
@@ -3,7 +3,6 @@ import debounce from 'lodash-es/debounce'
import PropTypes from 'prop-types'
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
-import { acSetChart } from '../../actions/chart.js'
import { tSetCurrentFromUi } from '../../actions/current.js'
import { acSetLoadError, acSetPluginLoading } from '../../actions/loader.js'
import { acAddMetadata } from '../../actions/metadata.js'
@@ -32,6 +31,7 @@ import { sGetLoadError, sGetIsPluginLoading } from '../../reducers/loader.js'
import { sGetSettingsDisplayProperty } from '../../reducers/settings.js'
import { sGetUiRightSidebarOpen } from '../../reducers/ui.js'
import LoadingMask from '../../widgets/LoadingMask.js'
+import { ChartContext } from '../ChartProvider.js'
import { VisualizationPlugin } from '../VisualizationPlugin/VisualizationPlugin.js'
import StartScreen from './StartScreen.js'
import styles from './styles/Visualization.style.js'
@@ -99,7 +99,9 @@ export class UnconnectedVisualization extends Component {
this.props.setLoadError(error)
}
- onChartGenerated = (svg) => this.props.setChart(svg)
+ onChartGenerated = (chart) => {
+ this.context.setChart(chart)
+ }
onDataSorted = (sorting) => {
this.props.onLoadingStart()
@@ -247,7 +249,6 @@ UnconnectedVisualization.propTypes = {
error: PropTypes.object,
isLoading: PropTypes.bool,
rightSidebarOpen: PropTypes.bool,
- setChart: PropTypes.func,
setCurrent: PropTypes.func,
setLoadError: PropTypes.func,
setUiDataSorting: PropTypes.func,
@@ -257,6 +258,20 @@ UnconnectedVisualization.propTypes = {
onLoadingStart: PropTypes.func,
}
+UnconnectedVisualization.contextType = ChartContext
+
+/* Setting these contextTypes is required for Jest/Enzyme
+ * context mocking to work, but a React DevTools warning
+ * is thrown in development mode, because contextTypes is
+ * part of the legacy Context API which is deprecated.
+ * So we have to set them conditionally. */
+if (process.env.JEST_WORKER_ID !== undefined) {
+ UnconnectedVisualization.contextTypes = {
+ getChart: PropTypes.func,
+ setChart: PropTypes.func,
+ }
+}
+
const mapStateToProps = (state) => ({
visualization: sGetCurrent(state),
rightSidebarOpen: sGetUiRightSidebarOpen(state),
@@ -271,7 +286,6 @@ const mapDispatchToProps = (dispatch) => ({
addMetadata: (metadata) => dispatch(acAddMetadata(metadata)),
addParentGraphMap: (parentGraphMap) =>
dispatch(acAddParentGraphMap(parentGraphMap)),
- setChart: (chart) => dispatch(acSetChart(chart)),
setLoadError: (error) => dispatch(acSetLoadError(error)),
setUiItems: (data) => dispatch(acSetUiItems(data)),
setUiDataSorting: (sorting) => dispatch(acSetUiDataSorting(sorting)),
diff --git a/src/components/Visualization/__tests__/Visualization.spec.js b/src/components/Visualization/__tests__/Visualization.spec.js
index 98f17d26ef..d18268091c 100644
--- a/src/components/Visualization/__tests__/Visualization.spec.js
+++ b/src/components/Visualization/__tests__/Visualization.spec.js
@@ -10,9 +10,14 @@ describe('Visualization', () => {
describe('component', () => {
let props
let shallowVisualization
+ const setChart = jest.fn()
const vis = () => {
if (!shallowVisualization) {
- shallowVisualization = shallow()
+ shallowVisualization = shallow(, {
+ context: {
+ setChart,
+ },
+ })
}
return shallowVisualization
}
@@ -26,7 +31,6 @@ describe('Visualization', () => {
error: null,
rightSidebarOpen: false,
addMetadata: jest.fn(),
- setChart: jest.fn(),
clearLoadError: jest.fn(),
setLoadError: jest.fn(),
onLoadingComplete: jest.fn(),
@@ -71,12 +75,12 @@ describe('Visualization', () => {
})
it('triggers setChart action when chart has been generated', () => {
- const svg = 'coolChart'
+ const highChartChartInstanceMock = {}
- vis().instance().onChartGenerated(svg)
+ vis().instance().onChartGenerated(highChartChartInstanceMock)
- expect(props.setChart).toHaveBeenCalled()
- expect(props.setChart).toHaveBeenCalledWith(svg)
+ expect(setChart).toHaveBeenCalled()
+ expect(setChart).toHaveBeenCalledWith(highChartChartInstanceMock)
})
it('renders visualization with new id when rightSidebarOpen prop changes', () => {
diff --git a/src/components/VisualizationPlugin/ChartPlugin.js b/src/components/VisualizationPlugin/ChartPlugin.js
index f587b7aa4f..901db54c34 100644
--- a/src/components/VisualizationPlugin/ChartPlugin.js
+++ b/src/components/VisualizationPlugin/ChartPlugin.js
@@ -1,4 +1,4 @@
-import { isSingleValue, createVisualization } from '@dhis2/analytics'
+import { createVisualization } from '@dhis2/analytics'
import PropTypes from 'prop-types'
import React, { useRef, useCallback, useEffect } from 'react'
@@ -31,19 +31,10 @@ const ChartPlugin = ({
},
undefined,
undefined,
- isSingleValue(visualization.type) ? 'dhis' : 'highcharts' // output format
+ 'highcharts' // output format
)
- if (isSingleValue(visualization.type)) {
- onChartGenerated(visualizationConfig.visualization)
- } else {
- onChartGenerated(
- visualizationConfig.visualization.getSVGForExport({
- sourceHeight: 768,
- sourceWidth: 1024,
- })
- )
- }
+ onChartGenerated(visualizationConfig.visualization)
},
[
canvasRef,
diff --git a/src/components/VisualizationPlugin/__tests__/ChartPlugin.spec.js b/src/components/VisualizationPlugin/__tests__/ChartPlugin.spec.js
index 4d5aff6482..6de9d7b526 100644
--- a/src/components/VisualizationPlugin/__tests__/ChartPlugin.spec.js
+++ b/src/components/VisualizationPlugin/__tests__/ChartPlugin.spec.js
@@ -7,33 +7,6 @@ import ChartPlugin from '../ChartPlugin.js'
jest.mock('@dhis2/analytics')
-const dxMock = {
- dimension: 'dx',
- items: [
- {
- id: 'Uvn6LCg7dVU',
- },
- ],
-}
-
-const peMock = {
- dimension: 'pe',
- items: [
- {
- id: 'LAST_12_MONTHS',
- },
- ],
-}
-
-const ouMock = {
- dimension: 'ou',
- items: [
- {
- id: 'ImspTQPwCqd',
- },
- ],
-}
-
const mockExtraOptions = {
dashboard: false,
noData: {
@@ -41,13 +14,6 @@ const mockExtraOptions = {
},
}
-const singleValueCurrentMock = {
- type: analytics.VIS_TYPE_SINGLE_VALUE,
- columns: [dxMock],
- rows: [],
- filters: [ouMock, peMock],
-}
-
const metaDataMock = {
items: {
a: { name: 'a dim' },
@@ -72,17 +38,13 @@ class MockAnalyticsResponse {
const createVisualizationMock = {
visualization: {
- getSVGForExport: () => '',
+ exportChartLocal: jest.fn(),
},
config: {
getConfig: () => {},
},
}
-const isSingleValueMockResponse = (visType) => {
- return visType === analytics.VIS_TYPE_SINGLE_VALUE
-}
-
describe('ChartPlugin', () => {
// eslint-disable-next-line no-import-assign, import/namespace
options.getOptionsForRequest = () => [
@@ -148,39 +110,10 @@ describe('ChartPlugin', () => {
setTimeout(() => {
expect(props.onChartGenerated).toHaveBeenCalled()
expect(props.onChartGenerated).toHaveBeenCalledWith(
- createVisualizationMock.visualization.getSVGForExport()
+ createVisualizationMock.visualization
)
done()
})
})
-
- describe('Single value visualization', () => {
- beforeEach(() => {
- props.visualization = {
- ...singleValueCurrentMock,
- }
-
- // eslint-disable-next-line no-import-assign, import/namespace
- analytics.isSingleValue = jest
- .fn()
- .mockReturnValue(
- isSingleValueMockResponse(props.visualization.type)
- )
- })
-
- it('provides dhis as output format to createChart', (done) => {
- canvas()
-
- setTimeout(() => {
- expect(analytics.createVisualization).toHaveBeenCalled()
-
- expect(
- analytics.createVisualization.mock.calls[0][6]
- ).toEqual('dhis')
-
- done()
- })
- })
- })
})
})
diff --git a/src/modules/getNotoPdfFontForLocale/index.js b/src/modules/getNotoPdfFontForLocale/index.js
new file mode 100644
index 0000000000..ff8581415e
--- /dev/null
+++ b/src/modules/getNotoPdfFontForLocale/index.js
@@ -0,0 +1,50 @@
+import { NOTO_FONT_LOOKUP } from './notoFontLookup.js'
+
+const fontsDir = `${process.env.PUBLIC_URL}/fonts`
+
+const findInNotoFontLookup = (callback) => {
+ for (const [fontName, scriptsAndLanguages] of NOTO_FONT_LOOKUP) {
+ if (callback(scriptsAndLanguages)) {
+ return {
+ normal: `${fontsDir}/${fontName}-Regular.ttf`,
+ bold: `${fontsDir}/${fontName}-Bold.ttf`,
+ // Note that these fonts do not actually have italic variants
+ bolditalic: `${fontsDir}/${fontName}-Regular.ttf`,
+ italic: `${fontsDir}/${fontName}-Regular.ttf`,
+ }
+ }
+ }
+}
+
+const getScriptAndRegionFromJavaLocaleCode = (javaLocaleCode) => {
+ const [rawLanguage, region, script] = javaLocaleCode.split('_')
+ /* This will ensure that 3 character ISO639-2 language codes
+ * for which a 2 character ISO639-1 code also exists are
+ * normalized to the 2 character ISO639-1 code */
+ const jsLocale = new Intl.Locale(rawLanguage, { script, region })
+
+ return {
+ language: jsLocale.language,
+ script,
+ }
+}
+
+export const getNotoPdfFontForLocale = (javaLocale = 'en') => {
+ const { script, language } =
+ getScriptAndRegionFromJavaLocaleCode(javaLocale)
+ return (
+ /* First scan the entire lookup to find a script match because script
+ * matches should take precedence over language matches, since a
+ * language can be written in multiple scripts */
+ findInNotoFontLookup(({ scripts }) => scripts.has(script)) ??
+ // Then scan for language matches
+ findInNotoFontLookup(({ languages }) => languages.has(language)) ?? {
+ /* If no match is found return the Noto base font.
+ * Note that this does have italic variants */
+ normal: `${fontsDir}/NotoSans-Regular.ttf`,
+ bold: `${fontsDir}/NotoSans-Bold.ttf`,
+ bolditalic: `${fontsDir}/NotoSans-BoldItalic.ttf`,
+ italic: `${fontsDir}/NotoSans-Italic.ttf`,
+ }
+ )
+}
diff --git a/src/modules/getNotoPdfFontForLocale/notoFontLookup.js b/src/modules/getNotoPdfFontForLocale/notoFontLookup.js
new file mode 100644
index 0000000000..023b62eb18
--- /dev/null
+++ b/src/modules/getNotoPdfFontForLocale/notoFontLookup.js
@@ -0,0 +1,252 @@
+/* Full list of languages:
+ * https://www.loc.gov/standards/iso639-2/php/English_list.php
+ * Full list of scripts:
+ * https://unicode.org/iso15924/iso15924-codes.html
+ * An overview of scripts commonly used with different languages:
+ * https://www.unicode.org/cldr/charts/44/supplemental/languages_and_scripts.html
+ * We have identified the following languages/scripts which
+ * require a custom Noto font bundle:
+ * - Arabic
+ * - Bengali/Bangla
+ * - Ethiopic
+ * - Hewbrew
+ * - Japanese
+ * - Khmer
+ * - Korean
+ * - Lao
+ * - Myanmar
+ * - Odia
+ * - Simplified Chinese
+ * - Sinhala
+ * - Thai
+ * The lookup below describes the scripts and languages per
+ * custom font bundle. It's likely that this lookup is not
+ * complete and that new font-bundles and script- and
+ * language-codes will be added in the future. When adding a
+ * new font bundle here, new .ttf files also need to be added to
+ * `./public/fonts`.
+ * Note about the language sets: some language codes correspond to
+ * multiple scripts, but we can only add a single font bundle when
+ * convering to PDF. The Latn script is supported without a font
+ * bundle, so if a language corresponds to Latn plus one additional
+ * script, we can include the bundle for that script. However if the
+ * language * corresponds to multiple non-ASCII scripts then choosing
+ * the correct font bundle based on a language code is technicaly
+ * impossible. The only way to ensure the correct font bundle for
+ * PDF generation is by ensuring that the locale string contains a
+ * script section. In the lookup below these ambiguous languages
+ * have been disabled, because it is better to serve the base Noto
+ * font in these cases. */
+
+export const NOTO_FONT_LOOKUP = new Map([
+ [
+ 'NotoSansArabic',
+ {
+ scripts: new Set(['Arab']),
+ languages: new Set([
+ 'arq',
+ 'ar', // Technically maps to both Arab and Syrc but we assume Arab
+ // 'az', (Arab + Cyrl)
+ 'bqi',
+ // 'bft', (Arab + Tibt)
+ 'bal',
+ 'bej',
+ 'brh',
+ 'ckb',
+ 'swb',
+ // 'cop', (Arab + Grek + Copt)
+ 'dcc',
+ // 'doi', (Arab + Deva + Takr)
+ // 'cjm', (Arab + Cham)
+ 'arz',
+ 'glk',
+ 'gju',
+ 'ha',
+ 'haz',
+ 'id',
+ // 'inh', (Arab + Cyrl)
+ 'dyo',
+ 'jrb',
+ 'gjk',
+ // 'ks', (Arab + Deva)
+ // 'kk', (Arab + Cyrl)
+ 'khw',
+ // 'ku', (Arab + Cyrl)
+ // 'ky', (Arab + Cyrl)
+ 'lki',
+ 'ms',
+ 'mzn',
+ 'ary',
+ // 'ttt', (Arab + Cyrl)
+ 'ars',
+ 'wni',
+ 'zdj',
+ 'fia',
+ 'hno',
+ 'lrc',
+ 'kvx',
+ 'prd',
+ 'ps',
+ 'mfa',
+ 'fa',
+ // 'pa', (Arab + Guru)
+ // 'rhg', (Arab + Rohg)
+ 'skr',
+ // 'sd' (Arab + Deva + Khoj + Sind)
+ // 'so',(Arab + Osma)
+ 'hnd',
+ 'sdh',
+ 'luz',
+ 'sus',
+ // 'shi', (Arab + Tfng)
+ // 'tg', (Arab + Cyrl)
+ // 'tly', (Arab + Cyrl)
+ 'aeb',
+ 'tr',
+ // 'tk', (Arab + Cyrl)
+ 'ur',
+ 'ug',
+ // 'uz', (Arab + Cyrl)
+ 'kxp',
+ 'bgn',
+ // 'cja' (Arab + Cham)
+ 'lah',
+ 'wo',
+ 'gbz',
+ ]),
+ },
+ ],
+ [
+ 'NotoSansJP',
+ {
+ scripts: new Set(['Jpan']),
+ languages: new Set(['ja']),
+ },
+ ],
+ [
+ 'NotoSansKR',
+ {
+ scripts: new Set(['Kore']),
+ languages: new Set(['ko']),
+ },
+ ],
+ [
+ 'NotoSansSC',
+ {
+ scripts: new Set(['Hans']),
+ languages: new Set([
+ 'yue',
+ 'zh',
+ 'gan',
+ 'hak',
+ 'lzh',
+ 'nan',
+ 'wuu',
+ 'hsn',
+ 'za',
+ ]),
+ },
+ ],
+ [
+ 'NotoSansThai',
+ {
+ scripts: new Set(['Thai']),
+ languages: new Set([
+ 'lwl',
+ 'kdt',
+ 'tts',
+ 'kxm',
+ 'nod',
+ // 'pi' (Deva + Sinh + Thai)
+ 'sou',
+ 'th',
+ 'lcp',
+ ]),
+ },
+ ],
+ [
+ 'NotoSansHebrew',
+ {
+ scripts: new Set(['Hebr']),
+ languages: new Set([
+ 'he',
+ 'jrb',
+ 'jpr',
+ 'lad',
+ // 'sam', (Hebr + Samr)
+ 'yi',
+ ]),
+ },
+ ],
+ [
+ 'NotoSansLao',
+ {
+ scripts: new Set(['Laoo']),
+ languages: new Set(['hnj', 'kjg', 'lo']),
+ },
+ ],
+ [
+ 'NotoSansEthiopic',
+ {
+ scripts: new Set(['Ethi']),
+ languages: new Set(['am', 'byn', 'gez', 'om', 'tig', 'ti', 'wal']),
+ },
+ ],
+ [
+ 'NotoSansMyanmar',
+ {
+ scripts: new Set(['Mymr']),
+ languages: new Set(['my', 'kht', 'mnw', 'shn']),
+ },
+ ],
+ [
+ 'NotoSansBengali',
+ {
+ scripts: new Set(['Beng']),
+ languages: new Set([
+ 'as',
+ 'bn',
+ 'bpy',
+ // 'ccp', (Beng + Cakm)
+ 'grt',
+ 'kha',
+ // 'mni', (Beng, Mtei)
+ 'lus',
+ // 'unx' (Beng + Deva),
+ // 'unr' (Beng + Deva),
+ 'rkt',
+ // 'sat' (Beng + Deva + Orya + Olck)
+ // 'syl' (Beng + Sylo)
+ ]),
+ },
+ ],
+ [
+ 'NotoSansKhmer',
+ {
+ scripts: new Set(['Khmr']),
+ languages: new Set(['km']),
+ },
+ ],
+ [
+ 'NotoSansOriya',
+ {
+ scripts: new Set(['Orya']),
+ languages: new Set([
+ // 'kxv', (Orya + Deva + Telu)
+ 'or',
+ // 'sat' (Orya + Beng + Deva + Olck)
+ ]),
+ },
+ ],
+ [
+ 'NotoSansSinhala',
+ {
+ scripts: new Set(['Sinh']),
+ languages: new Set([
+ 'si',
+ // 'pi', (Sihn + Deva + Thai)
+ // 'sa', (Sihn + Deva + Gran + Shrd + Sidd)
+ ]),
+ },
+ ],
+])
diff --git a/src/reducers/chart.js b/src/reducers/chart.js
deleted file mode 100644
index 6be8d9a543..0000000000
--- a/src/reducers/chart.js
+++ /dev/null
@@ -1,15 +0,0 @@
-export const SET_CHART = 'SET_CHART'
-
-export const DEFAULT_CHART = null
-
-export default (state = DEFAULT_CHART, action) => {
- switch (action.type) {
- case SET_CHART: {
- return action.value
- }
- default:
- return state
- }
-}
-
-export const sGetChart = (state) => state.chart
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 5cb9ebd8c9..5ccc99767f 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -1,5 +1,4 @@
import { combineReducers } from 'redux'
-import chart, * as fromChart from './chart.js'
import current, * as fromCurrent from './current.js'
import dimensions, * as fromDimensions from './dimensions.js'
import loader, * as fromLoader from './loader.js'
@@ -24,7 +23,6 @@ export default combineReducers({
user,
snackbar,
loader,
- chart,
})
// Selectors
@@ -40,7 +38,6 @@ export {
fromUser,
fromSnackbar,
fromLoader,
- fromChart,
}
export const sGetSeriesSetupItems = (state) =>
diff --git a/yarn.lock b/yarn.lock
index 42d1ab01e4..1cea121a09 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2050,10 +2050,10 @@
classnames "^2.3.1"
prop-types "^15.7.2"
-"@dhis2/analytics@^26.8.7":
- version "26.8.7"
- resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-26.8.7.tgz#46838366066ddd1f92ab7b5bc78f1d87b4f56b75"
- integrity sha512-zPdxVDL8IhCwZF2zDEj+2TPG1kS4MTJUgM2xGjSHnBFfrsn/ddN8D8x2tu+V4hh5F+xYggSkMNeGi2hwLsml+A==
+"@dhis2/analytics@^26.9.0":
+ version "26.9.0"
+ resolved "https://registry.yarnpkg.com/@dhis2/analytics/-/analytics-26.9.0.tgz#562f0f6cb5107df80292f81b4fb53053da947131"
+ integrity sha512-BA2NOKW2r+NRyJnHTzM6IlhmoEZbv8JbU0Omcyq+0YiNHZEw9pNq+6HG98S5MnvlM0f0W8GYb/E+97YCDQG6ZQ==
dependencies:
"@dhis2/multi-calendar-dates" "^1.2.2"
"@dnd-kit/core" "^6.0.7"