From 758c1963dea431f7f2e876d720d886028588e4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 25 Mar 2026 14:43:17 +0100 Subject: [PATCH 1/4] fix: rgl 1.5.3 --- package.json | 4 +- patches/react-grid-layout+1.2.2.patch | 21 --------- patches/react-grid-layout+1.5.3.patch | 21 +++++++++ yarn.lock | 61 ++++++++++++++------------- 4 files changed, 54 insertions(+), 53 deletions(-) delete mode 100644 patches/react-grid-layout+1.2.2.patch create mode 100644 patches/react-grid-layout+1.5.3.patch diff --git a/package.json b/package.json index b327f3dd3..d2f4b0cd8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "d2-utilizr": "^0.2.16", "lodash": "^4.17.21", "moment": "^2.30.1", - "react-grid-layout": "1.2.2", + "react-grid-layout": "1.5.3", "react-redux": "^7.2.9", "react-router-dom": "^5.2.0", "redux": "^4.1.0", @@ -81,4 +81,4 @@ }, "resolutions": {}, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} +} \ No newline at end of file diff --git a/patches/react-grid-layout+1.2.2.patch b/patches/react-grid-layout+1.2.2.patch deleted file mode 100644 index 2094202ec..000000000 --- a/patches/react-grid-layout+1.2.2.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/node_modules/react-grid-layout/build/utils.js b/node_modules/react-grid-layout/build/utils.js -index a72c439..46b477c 100644 ---- a/node_modules/react-grid-layout/build/utils.js -+++ b/node_modules/react-grid-layout/build/utils.js -@@ -291,6 +291,7 @@ function resolveCompactionCollision(layout - var itemIndex = layout.map(function (layoutItem) { - return layoutItem.i; - }).indexOf(item.i); // Go through each item we collide with. -+ var layoutHasStatics = getStatics(layout).length > 0; - - for (var i = itemIndex + 1; i < layout.length; i++) { - var otherItem = layout[i]; // Ignore static items -@@ -298,7 +299,7 @@ function resolveCompactionCollision(layout - if (otherItem.static) continue; // Optimization: we can break early if we know we're past this el - // We can do this b/c it's a sorted layout - -- if (otherItem.y > item.y + item.h) break; -+ if (!layoutHasStatics && otherItem.y > item.y + item.h) break; - - if (collides(item, otherItem)) { - resolveCompactionCollision(layout, otherItem, moveToCoord + item[sizeProp], axis); diff --git a/patches/react-grid-layout+1.5.3.patch b/patches/react-grid-layout+1.5.3.patch new file mode 100644 index 000000000..b08c8998c --- /dev/null +++ b/patches/react-grid-layout+1.5.3.patch @@ -0,0 +1,21 @@ +diff --git a/node_modules/react-grid-layout/lib/utils.js b/node_modules/react-grid-layout/lib/utils.js +index 6d06348..933b961 100644 +--- a/node_modules/react-grid-layout/lib/utils.js ++++ b/node_modules/react-grid-layout/lib/utils.js +@@ -294,6 +294,7 @@ function resolveCompactionCollision( + return layoutItem.i; + }) + .indexOf(item.i); ++ const layoutHasStatics = getStatics(layout).length > 0; + + // Go through each item we collide with. + for (let i = itemIndex + 1; i < layout.length; i++) { +@@ -303,7 +304,7 @@ function resolveCompactionCollision( + + // Optimization: we can break early if we know we're past this el + // We can do this b/c it's a sorted layout +- if (otherItem.y > item.y + item.h) break; ++ if (!layoutHasStatics && otherItem.y > item.y + item.h) break; + + if (collides(item, otherItem)) { + resolveCompactionCollision( diff --git a/yarn.lock b/yarn.lock index f9caa062e..494787c51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5396,7 +5396,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.x, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2: +classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2: version "2.5.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== @@ -5543,10 +5543,10 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== cmd-shim@^5.0.0: version "5.0.0" @@ -7431,6 +7431,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-equals@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-4.0.3.tgz#72884cc805ec3c6679b99875f6b7654f39f0e8c7" + integrity sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg== + fast-fifo@^1.2.0, fast-fifo@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" @@ -10459,11 +10464,6 @@ lodash.isboolean@^3.0.3: resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= -lodash.isequal@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== - lodash.isfunction@^3.0.8: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" @@ -12338,7 +12338,7 @@ promzard@^0.3.0: dependencies: read "1" -prop-types@15.x, prop-types@^15.0.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@15.x, 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== @@ -12515,12 +12515,12 @@ react-dom@^18: loose-envify "^1.1.0" scheduler "^0.23.2" -react-draggable@^4.0.0, react-draggable@^4.0.3: - version "4.4.6" - resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e" - integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw== +react-draggable@^4.4.6, react-draggable@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.5.0.tgz#0b274ccb6965fcf97ed38fcf7e3cc223bc48cdf5" + integrity sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw== dependencies: - clsx "^1.1.1" + clsx "^2.1.1" prop-types "^15.8.1" react-error-boundary@^3.1.0: @@ -12542,16 +12542,17 @@ react-final-form@^6.5.3: dependencies: "@babel/runtime" "^7.15.4" -react-grid-layout@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.2.2.tgz#42cdb4b27fcdc4fad1655d8862b9d54c6f011d6d" - integrity sha512-i5/xPkyi0llA6PCEW2B26e7pTY+JLp0zPvs6MYbbEXWaO1FWG0xr6Q/FqPrh6K86glV5ZRU7DEbvnedZVdFglg== +react-grid-layout@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.5.3.tgz#802de040616c443b0162d73cecde792cb5beeaa2" + integrity sha512-KaG6IbjD6fYhagUtIvOzhftXG+ViKZjCjADe86X1KHl7C/dsBN2z0mi14nbvZKTkp0RKiil9RPcJBgq3LnoA8g== dependencies: - classnames "2.x" - lodash.isequal "^4.0.0" - prop-types "^15.0.0" - react-draggable "^4.0.0" - react-resizable "^1.10.0" + clsx "^2.1.1" + fast-equals "^4.0.3" + prop-types "^15.8.1" + react-draggable "^4.4.6" + react-resizable "^3.0.5" + resize-observer-polyfill "^1.5.1" react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: version "16.13.1" @@ -12611,13 +12612,13 @@ react-refresh@^0.14.2: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9" integrity sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA== -react-resizable@^1.10.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.11.1.tgz#02ca6850afa7a22c1b3e623e64aef71ee252af69" - integrity sha512-S70gbLaAYqjuAd49utRHibtHLrHXInh7GuOR+6OO6RO6uleQfuBnWmZjRABfqNEx3C3Z6VPLg0/0uOYFrkfu9Q== +react-resizable@^3.0.5: + version "3.1.3" + resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-3.1.3.tgz#b8c3f8aeffb7b0b2c2306bfc7a742462e58125fb" + integrity sha512-liJBNayhX7qA4tBJiBD321FDhJxgGTJ07uzH5zSORXoE8h7PyEZ8mLqmosST7ppf6C4zUsbd2gzDMmBCfFp9Lw== dependencies: prop-types "15.x" - react-draggable "^4.0.3" + react-draggable "^4.5.0" react-router-dom@^5.2.0: version "5.2.1" From 4770330c406a22ad92e5ba43dc712cdc1ea215c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 25 Mar 2026 14:44:36 +0100 Subject: [PATCH 2/4] chore: newline --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d2f4b0cd8..3bc8657b5 100644 --- a/package.json +++ b/package.json @@ -81,4 +81,4 @@ }, "resolutions": {}, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" -} \ No newline at end of file +} From ce48e9398e583a328fd242074c1d2fcb2ff29b1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 25 Mar 2026 14:57:42 +0100 Subject: [PATCH 3/4] chore: fix lint warnings --- src/pages/edit/EditDashboard.jsx | 21 ++++---- src/pages/edit/LayoutModal.jsx | 1 + src/pages/edit/NewDashboard.jsx | 3 +- src/pages/print/PrintDashboard.jsx | 9 +++- src/pages/print/PrintLayoutDashboard.jsx | 63 ++++++++++++++---------- src/pages/start/LandingPage.jsx | 2 +- src/pages/start/StartScreen.jsx | 2 +- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/pages/edit/EditDashboard.jsx b/src/pages/edit/EditDashboard.jsx index 5ceeacca4..25ad6e98f 100644 --- a/src/pages/edit/EditDashboard.jsx +++ b/src/pages/edit/EditDashboard.jsx @@ -22,7 +22,7 @@ import ItemGrid from './ItemGrid.jsx' import classes from './styles/EditDashboard.module.css' import TitleBar from './TitleBar.jsx' -const EditDashboard = (props) => { +const EditDashboard = ({ id, isPrintPreviewView, setEditDashboard }) => { const dataEngine = useDataEngine() const { width } = useWindowDimensions() const [redirectUrl, setRedirectUrl] = useState(null) @@ -32,29 +32,28 @@ const EditDashboard = (props) => { useEffect(() => { const loadDashboard = async () => { try { - const dashboard = await apiFetchDashboard( - dataEngine, - props.id, - { mode: EDIT } - ) - props.setEditDashboard(dashboard) + const dashboard = await apiFetchDashboard(dataEngine, id, { + mode: EDIT, + }) + setEditDashboard(dashboard) setHasUpdateAccess(dashboard.access?.update || false) setIsLoading(false) } catch (error) { console.error('Error fetching dashboard:', error) - setRedirectUrl(props.id ? `/${props.id}` : '/') + setRedirectUrl(id ? `/${id}` : '/') setIsLoading(false) } } if (isSmallScreen(width)) { - setRedirectUrl(props.id ? `/${props.id}` : '/') + setRedirectUrl(id ? `/${id}` : '/') return } setHeaderbarVisible(true) loadDashboard() - }, [props.id]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dataEngine, id, setEditDashboard]) if (redirectUrl) { return @@ -71,7 +70,7 @@ const EditDashboard = (props) => { } const renderGrid = () => { - if (props.isPrintPreviewView) { + if (isPrintPreviewView) { return } return ( diff --git a/src/pages/edit/LayoutModal.jsx b/src/pages/edit/LayoutModal.jsx index 548fb1ef9..4018fac03 100644 --- a/src/pages/edit/LayoutModal.jsx +++ b/src/pages/edit/LayoutModal.jsx @@ -30,6 +30,7 @@ export const LayoutModal = ({ columns, onSaveLayout, onClose }) => { const { isDisconnected: offline } = useDhis2ConnectionStatus() const [cols, setCols] = useState(columns) + // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => setCols(columns), []) const setColsWrapper = (value) => { diff --git a/src/pages/edit/NewDashboard.jsx b/src/pages/edit/NewDashboard.jsx index 2990c665e..e2cc999cb 100644 --- a/src/pages/edit/NewDashboard.jsx +++ b/src/pages/edit/NewDashboard.jsx @@ -32,7 +32,8 @@ const NewDashboard = (props) => { dispatch(acSetEditNewDashboard()) dispatch(acClearSelected()) - }, []) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dispatch]) if (redirectUrl) { return diff --git a/src/pages/print/PrintDashboard.jsx b/src/pages/print/PrintDashboard.jsx index 19b547d65..419818ecb 100644 --- a/src/pages/print/PrintDashboard.jsx +++ b/src/pages/print/PrintDashboard.jsx @@ -98,7 +98,14 @@ const PrintDashboard = ({ setHeaderbarVisible(false) loadDashboard() - }, [id]) + }, [ + id, + dataEngine, + setPrintDashboard, + addDashboardItem, + removeDashboardItem, + updateDashboardItem, + ]) if (redirectUrl) { return diff --git a/src/pages/print/PrintLayoutDashboard.jsx b/src/pages/print/PrintLayoutDashboard.jsx index 004bdb825..17b0e3586 100644 --- a/src/pages/print/PrintLayoutDashboard.jsx +++ b/src/pages/print/PrintLayoutDashboard.jsx @@ -45,34 +45,38 @@ const PrintLayoutDashboard = ({ const [redirectUrl, setRedirectUrl] = useState(null) const [isLoading, setIsLoading] = useState(true) - const customizePrintLayoutDashboard = (dboard) => { - // If any items are taller than one page, reduce it to one - // page (react-grid-layout units) - dboard.dashboardItems.forEach((item) => { - if (item.h > MAX_ITEM_GRID_HEIGHT) { - item.shortened = true - updateDashboardItem({ ...item, h: MAX_ITEM_GRID_HEIGHT }) - } - }) - - addPageBreaks(dboard.dashboardItems, addDashboardItem) - - addDashboardItem({ - type: PRINT_TITLE_PAGE, - isOneItemPerPage: false, - }) - - setIsLoading(false) - } - useEffect(() => { + const customizePrintLayoutDashboard = (dboard) => { + // If any items are taller than one page, reduce it to one + // page (react-grid-layout units) + dboard.dashboardItems.forEach((item) => { + if (item.h > MAX_ITEM_GRID_HEIGHT) { + item.shortened = true + updateDashboardItem({ ...item, h: MAX_ITEM_GRID_HEIGHT }) + } + }) + + addPageBreaks(dboard.dashboardItems, addDashboardItem) + + addDashboardItem({ + type: PRINT_TITLE_PAGE, + isOneItemPerPage: false, + }) + + setIsLoading(false) + } + const loadDashboard = async () => { try { - const dashboard = await apiFetchDashboard(dataEngine, id, { - mode: VIEW, - }) - setPrintDashboard(dashboard) - customizePrintLayoutDashboard(dashboard) + const fetchedDashboard = await apiFetchDashboard( + dataEngine, + id, + { + mode: VIEW, + } + ) + setPrintDashboard(fetchedDashboard) + customizePrintLayoutDashboard(fetchedDashboard) } catch (error) { console.error('Error loading dashboard:', error) setRedirectUrl(id ? `/${id}` : '/') @@ -88,7 +92,14 @@ const PrintLayoutDashboard = ({ setPrintDashboard(dashboard) customizePrintLayoutDashboard(dashboard) } - }, [dashboard]) + }, [ + dashboard, + dataEngine, + id, + setPrintDashboard, + addDashboardItem, + updateDashboardItem, + ]) if (redirectUrl) { return diff --git a/src/pages/start/LandingPage.jsx b/src/pages/start/LandingPage.jsx index f11a22666..1ac086d26 100644 --- a/src/pages/start/LandingPage.jsx +++ b/src/pages/start/LandingPage.jsx @@ -6,7 +6,7 @@ import StartScreen from './StartScreen.jsx' const LandingPage = ({ username, onMount }) => { useEffect(() => { onMount() - }, []) + }, [onMount]) return ( <> diff --git a/src/pages/start/StartScreen.jsx b/src/pages/start/StartScreen.jsx index e22b14473..221ba8360 100644 --- a/src/pages/start/StartScreen.jsx +++ b/src/pages/start/StartScreen.jsx @@ -24,7 +24,7 @@ const StartScreen = ({ username }) => { } } populateMostViewedDashboards(dataEngine) - }, [username, online]) + }, [username, online, dataEngine]) const getContent = () => (
From b50d879188c3d9c87d8b6bce63b4259d549714d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 25 Mar 2026 15:49:01 +0100 Subject: [PATCH 4/4] chore: use eslint-disable --- src/pages/start/LandingPage.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/start/LandingPage.jsx b/src/pages/start/LandingPage.jsx index 1ac086d26..7335be0c5 100644 --- a/src/pages/start/LandingPage.jsx +++ b/src/pages/start/LandingPage.jsx @@ -4,9 +4,10 @@ import DashboardsBar from '../../components/DashboardsBar/index.js' import StartScreen from './StartScreen.jsx' const LandingPage = ({ username, onMount }) => { + // eslint-disable-next-line react-hooks/exhaustive-deps useEffect(() => { onMount() - }, [onMount]) + }, []) return ( <>