diff --git a/src/frontend/package.json b/src/frontend/package.json
index 10e1d887c8..22721f78a0 100644
--- a/src/frontend/package.json
+++ b/src/frontend/package.json
@@ -95,7 +95,7 @@
"qrcode": "^1.5.4",
"react": "^19.2.7",
"react-dom": "^19.2.7",
- "react-grid-layout": "1.4.4",
+ "react-grid-layout": "2.2.3",
"react-hook-form": "^7.78.0",
"react-is": "^19.2.7",
"react-router-dom": "^6.30.4",
@@ -122,7 +122,7 @@
"@types/qrcode": "^1.5.6",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
- "@types/react-grid-layout": "^1.3.5",
+ "@types/react-grid-layout": "^2.1.0",
"@types/react-router-dom": "^5.3.3",
"@types/react-window": "^1.8.8",
"@vanilla-extract/vite-plugin": "^5.2.2",
diff --git a/src/frontend/src/components/dashboard/DashboardLayout.tsx b/src/frontend/src/components/dashboard/DashboardLayout.tsx
index 0278bc60f8..da46af1d86 100644
--- a/src/frontend/src/components/dashboard/DashboardLayout.tsx
+++ b/src/frontend/src/components/dashboard/DashboardLayout.tsx
@@ -11,7 +11,11 @@ import {
import { useDisclosure } from '@mantine/hooks';
import { IconExclamationCircle, IconInfoCircle } from '@tabler/icons-react';
import { useCallback, useEffect, useMemo, useState } from 'react';
-import { type Layout, Responsive, WidthProvider } from 'react-grid-layout';
+import {
+ ResponsiveGridLayout,
+ useContainerWidth,
+ verticalCompactor
+} from 'react-grid-layout';
import { useInvenTreeHotkeys } from '@lib/functions/Events';
import { useShallow } from 'zustand/react/shallow';
@@ -22,8 +26,6 @@ import DashboardMenu from './DashboardMenu';
import DashboardWidget, { type DashboardWidgetProps } from './DashboardWidget';
import DashboardWidgetDrawer from './DashboardWidgetDrawer';
-const ReactGridLayout = WidthProvider(Responsive);
-
export default function DashboardLayout() {
const user = useUserState();
@@ -129,9 +131,7 @@ export default function DashboardLayout() {
const _layouts: any = { ...layouts };
Object.keys(_layouts).forEach((key) => {
- _layouts[key] = _layouts[key].filter(
- (item: Layout) => item.i !== widget
- );
+ _layouts[key] = _layouts[key].filter((item: any) => item.i !== widget);
});
setLayouts(_layouts);
@@ -142,7 +142,7 @@ export default function DashboardLayout() {
// When the layout is rendered, ensure that the widget attributes are observed
const updateLayoutForWidget = useCallback(
(layout: any[], widgets: any[], overrideSize: boolean) => {
- return layout.map((item: Layout): Layout => {
+ return layout.map((item: any) => {
// Find the matching widget
const widget = widgets.find(
(widget: DashboardWidgetProps) => widget.label === item.i
@@ -191,7 +191,7 @@ export default function DashboardLayout() {
const reducedLayouts: any = {};
// Reduce the layouts to exclude default attributes from the dataset
Object.keys(newLayouts).forEach((key) => {
- reducedLayouts[key] = newLayouts[key].map((item: Layout) => {
+ reducedLayouts[key] = newLayouts[key].map((item: any) => {
return {
...item,
moved: item.moved ? true : undefined,
@@ -316,26 +316,26 @@ export default function DashboardLayout() {
{showSampleDashboard && (
<>
- {WidgetGrid(
- defaultLayouts,
- () => {},
- editing,
- defaultWidgets,
- removing,
- () => {}
- )}
+ {}}
+ editing={editing}
+ widgets={defaultWidgets}
+ removing={removing}
+ removeWidget={() => {}}
+ />
>
)}
>
) : (
- WidgetGrid(
- layouts,
- onLayoutChange,
- editing,
- widgets,
- removing,
- removeWidget
- )
+
)}
>
) : (
@@ -347,28 +347,38 @@ export default function DashboardLayout() {
);
}
-function WidgetGrid(
- layouts: {},
- onLayoutChange: (layout: any, newLayouts: any) => void,
- editing: boolean,
- widgets: DashboardWidgetProps[],
- removing: boolean,
- removeWidget: (widget: string) => void
-) {
+function WidgetGrid({
+ layouts,
+ onLayoutChange,
+ editing,
+ widgets,
+ removing,
+ removeWidget
+}: {
+ layouts: {};
+ onLayoutChange: (layout: any, newLayouts: any) => void;
+ editing: boolean;
+ widgets: DashboardWidgetProps[];
+ removing: boolean;
+ removeWidget: (widget: string) => void;
+}) {
+ const { width, containerRef } = useContainerWidth();
+
return (
-
{widgets.map((item: DashboardWidgetProps) => {
return DashboardWidget({
@@ -380,6 +390,6 @@ function WidgetGrid(
}
});
})}
-
+
);
}
diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts
index 2aa813204e..19175a62ba 100644
--- a/src/frontend/vite.config.ts
+++ b/src/frontend/vite.config.ts
@@ -90,7 +90,8 @@ export default defineConfig(({ command, mode }) => {
}
},
define: {
- ...__INVENTREE_VERSION_INFO__
+ ...__INVENTREE_VERSION_INFO__,
+ 'process.env.NODE_ENV': JSON.stringify(mode)
}
};
});
diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock
index 0612b6ef65..4b79b9b7b3 100644
--- a/src/frontend/yarn.lock
+++ b/src/frontend/yarn.lock
@@ -1787,12 +1787,12 @@
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c"
integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==
-"@types/react-grid-layout@^1.3.5":
- version "1.3.6"
- resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-1.3.6.tgz#394f9995df1192b7d0cfe33ce017ec70356e7e73"
- integrity sha512-Cw7+sb3yyjtmxwwJiXtEXcu5h4cgs+sCGkHwHXsFmPyV30bf14LeD/fa2LwQovuD2HWxCcjIdNhDlcYGj95qGA==
+"@types/react-grid-layout@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@types/react-grid-layout/-/react-grid-layout-2.1.0.tgz#e6043ff473a7f6704513bf387ab41722bb8f24b2"
+ integrity sha512-pHEjVg9ert6BDFHFQ1IEdLUkd2gasJvyti5lV2kE46N/R07ZiaSZpAXeXJAA1MXy/Qby23fZmiuEgZkITxPXug==
dependencies:
- "@types/react" "*"
+ react-grid-layout "*"
"@types/react-router-dom@^5.3.3":
version "5.3.3"
@@ -2294,7 +2294,7 @@ clone@^1.0.2:
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
-clsx@^2.0.0, clsx@^2.1.1:
+clsx@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
@@ -4005,7 +4005,15 @@ react-dom@^19.2.7:
dependencies:
scheduler "^0.27.0"
-react-draggable@^4.4.5, react-draggable@^4.5.0:
+react-draggable@^4.4.6:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.7.0.tgz#29ff90b2feb9ddd320419bfff866035c4dfc7156"
+ integrity sha512-kTpANmKWVnFXiZ76Ag2ZowiFStuBYnJ606PI1TbUsOg29/400/JNIxI9+CuenhiAqFuXWJffz6F4UI3R51kUug==
+ dependencies:
+ clsx "^2.1.1"
+ prop-types "^15.8.1"
+
+react-draggable@^4.5.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.6.0.tgz#bae07fc729afe1a80c6cedd4775cc0d6856a0e0b"
integrity sha512-g4vqY53xhmPrBnZvGP+1YQV0eYnB3o0VLzoi6q2IpwnQrxIZ34tYRKpVtsWIXPg4D/pvLn+oYCW5gOK2cWIrgA==
@@ -4022,16 +4030,16 @@ react-dropzone@15.0.0:
file-selector "^2.1.0"
prop-types "^15.8.1"
-react-grid-layout@1.4.4:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.4.4.tgz#0bdb19d6db061556868fef1f430cc8c14d21f131"
- integrity sha512-7+Lg8E8O8HfOH5FrY80GCIR1SHTn2QnAYKh27/5spoz+OHhMmEhU/14gIkRzJOtympDPaXcVRX/nT1FjmeOUmQ==
+react-grid-layout@*, react-grid-layout@2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-2.2.3.tgz#6daf24b8c48448af617238520dd233a9375e2f16"
+ integrity sha512-OAEJHBxmfuxQfVtZwRzmsokijGlBgzYIJ7MUlLk/VSa43SaGzu15w5D0P2RDrfX5EvP9POMbL6bFrai/huDzbQ==
dependencies:
- clsx "^2.0.0"
+ clsx "^2.1.1"
fast-equals "^4.0.3"
prop-types "^15.8.1"
- react-draggable "^4.4.5"
- react-resizable "^3.0.5"
+ react-draggable "^4.4.6"
+ react-resizable "^3.1.3"
resize-observer-polyfill "^1.5.1"
react-hook-form@^7.78.0:
@@ -4091,7 +4099,7 @@ react-remove-scroll@^2.7.2:
use-callback-ref "^1.3.3"
use-sidecar "^1.1.3"
-react-resizable@^3.0.5:
+react-resizable@^3.1.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-3.2.0.tgz#09a6f77fcc4d59ca810098f58e46f39376cacef5"
integrity sha512-3NKQ0SLZV7rs3LQHeXlOzDSRQfFrkX6TVet77/Qk03zqiZyee37b7N8/gwDJAA8UUjRz7PdWCCy49hcso45SMQ==