diff --git a/packages/scenes-react/package.json b/packages/scenes-react/package.json index 6382437c9..4275a5d02 100644 --- a/packages/scenes-react/package.json +++ b/packages/scenes-react/package.json @@ -74,7 +74,7 @@ "@types/node": "20.11.30", "@types/react": "18.2.74", "@types/react-dom": "18.2.24", - "@types/react-grid-layout": "1.3.2", + "@types/react-grid-layout": "1.3.5", "@types/react-virtualized-auto-sizer": "1.0.1", "@types/uuid": "8.3.4", "@typescript-eslint/eslint-plugin": "^8.34.0", diff --git a/packages/scenes/package.json b/packages/scenes/package.json index 2f0277795..1c6ef603a 100644 --- a/packages/scenes/package.json +++ b/packages/scenes/package.json @@ -42,7 +42,7 @@ "@leeoniya/ufuzzy": "^1.0.16", "@tanstack/react-virtual": "^3.9.0", "i18next-parser": "9.3.0", - "react-grid-layout": "1.3.4", + "react-grid-layout": "1.5.2", "react-use": "17.5.0", "react-virtualized-auto-sizer": "1.0.24", "uuid": "^9.0.0" @@ -64,7 +64,6 @@ "@eslint/compat": "1.3.0", "@eslint/js": "^9.28.0", "@grafana/eslint-config": "^8.1.0", - "@grafana/i18n": "12.1.0", "@grafana/tsconfig": "^1.3.0-rc1", "@rollup/plugin-dynamic-import-vars": "2.1.5", "@rollup/plugin-json": "^6.1.0", @@ -82,7 +81,7 @@ "@types/node": "20.11.30", "@types/react": "18.2.74", "@types/react-dom": "18.2.24", - "@types/react-grid-layout": "1.3.2", + "@types/react-grid-layout": "1.3.5", "@types/react-virtualized-auto-sizer": "1.0.1", "@types/systemjs": "^6.15.1", "@types/uuid": "8.3.4", diff --git a/packages/scenes/src/components/layout/grid/SceneGridItem.tsx b/packages/scenes/src/components/layout/grid/SceneGridItem.tsx index b5d3ced70..885679b0d 100644 --- a/packages/scenes/src/components/layout/grid/SceneGridItem.tsx +++ b/packages/scenes/src/components/layout/grid/SceneGridItem.tsx @@ -31,6 +31,6 @@ export function isSceneGridRow(child: SceneObject): child is SceneGridRow { return child instanceof SceneGridRow; } -function isSceneGridLayout(child: SceneObject): child is SceneGridLayout { +export function isSceneGridLayout(child: SceneObject): child is SceneGridLayout { return child instanceof SceneGridLayout; } diff --git a/packages/scenes/src/components/layout/grid/SceneGridLayout.tsx b/packages/scenes/src/components/layout/grid/SceneGridLayout.tsx index ce9f5cd2a..06fc01df2 100644 --- a/packages/scenes/src/components/layout/grid/SceneGridLayout.tsx +++ b/packages/scenes/src/components/layout/grid/SceneGridLayout.tsx @@ -28,6 +28,7 @@ interface SceneGridLayoutState extends SceneObjectState { */ UNSAFE_fitPanels?: boolean; children: SceneGridItemLike[]; + _placeholderItem: SceneGridItemLike | null; } export class SceneGridLayout extends SceneObjectBase implements SceneLayout { @@ -37,10 +38,11 @@ export class SceneGridLayout extends SceneObjectBase imple private _oldLayout: ReactGridLayout.Layout[] = []; private _loadOldLayout = false; - public constructor(state: SceneGridLayoutState) { + public constructor(state: Omit) { super({ ...state, children: sortChildrenByPosition(state.children), + _placeholderItem: null, }); } @@ -189,6 +191,10 @@ export class SceneGridLayout extends SceneObjectBase imple * Will also scan row children and return child of the row */ public getSceneLayoutChild(key: string): SceneGridItemLike { + if (key === this.state._placeholderItem?.state.key) { + return this.state._placeholderItem!; + } + for (const child of this.state.children) { if (child.state.key === key) { return child; @@ -312,13 +318,15 @@ export class SceneGridLayout extends SceneObjectBase imple return rootChildren; } - public onDragStart: ReactGridLayout.ItemCallback = (gridLayout) => { - this._oldLayout = [...gridLayout]; - }; - - public onDragStop: ReactGridLayout.ItemCallback = (gridLayout, o, updatedItem) => { + public onDragStop = (gridLayout: ReactGridLayout.Layout[], updatedItem: ReactGridLayout.Layout) => { const sceneChild = this.getSceneLayoutChild(updatedItem.i)!; + // gridLayout contains both the original item and the updated item + // we need to remove the original item + gridLayout = gridLayout.filter( + (item) => item.i !== updatedItem.i || (item.i === updatedItem.i && item === updatedItem) + ); + // Need to resort the grid layout based on new position (needed to find the new parent) gridLayout = sortGridLayout(gridLayout); @@ -361,7 +369,7 @@ export class SceneGridLayout extends SceneObjectBase imple newChildren = this.moveChildTo(sceneChild, newParent); } - this.setState({ children: sortChildrenByPosition(newChildren) }); + this.setState({ children: sortChildrenByPosition(newChildren), _placeholderItem: null }); this._skipOnLayoutChange = true; }; @@ -420,6 +428,12 @@ export class SceneGridLayout extends SceneObjectBase imple return cells; } + + public setPlaceholder(placeholderItem: SceneGridItemLike | null) { + if (this.state._placeholderItem !== placeholderItem) { + this.setState({ _placeholderItem: placeholderItem }); + } + } } function isItemSizeEqual(a: SceneGridItemPlacement, b: SceneGridItemPlacement) { diff --git a/packages/scenes/src/components/layout/grid/SceneGridLayoutRenderer.tsx b/packages/scenes/src/components/layout/grid/SceneGridLayoutRenderer.tsx index f21bf707b..8fa848723 100644 --- a/packages/scenes/src/components/layout/grid/SceneGridLayoutRenderer.tsx +++ b/packages/scenes/src/components/layout/grid/SceneGridLayoutRenderer.tsx @@ -11,7 +11,7 @@ import { GrafanaTheme2 } from '@grafana/data'; import { useMeasure } from 'react-use'; export function SceneGridLayoutRenderer({ model }: SceneComponentProps) { - const { children, isLazy, isDraggable, isResizable } = model.useState(); + const { children, isLazy, isDraggable, isResizable, _placeholderItem } = model.useState(); const [outerDivRef, { width, height }] = useMeasure(); const ref = useRef(null); @@ -45,7 +45,7 @@ export function SceneGridLayoutRenderer({ model }: SceneComponentProps 768} + isDraggable={false} isResizable={isResizable ?? false} containerPadding={[0, 0]} useCSSTransforms={true} @@ -55,12 +55,21 @@ export function SceneGridLayoutRenderer({ model }: SceneComponentProps} + isDroppable={true} + onDrop={model.onDragStop} > {layout.map((gridItem, index) => ( =18" - checksum: 10/9f0c2f36527a18e654d9bf66051c0b1fe3c90addb3fc55c8e53ede9d16e477eb04949cd6725cb56663d1cc5f86872f704e34508adc1c9271530ea7c8a0f978f1 - languageName: node - linkType: hard - "@grafana/runtime@npm:^11.6.0": version: 11.6.1 resolution: "@grafana/runtime@npm:11.6.1" @@ -3934,7 +3868,7 @@ __metadata: "@types/node": "npm:20.11.30" "@types/react": "npm:18.2.74" "@types/react-dom": "npm:18.2.24" - "@types/react-grid-layout": "npm:1.3.2" + "@types/react-grid-layout": "npm:1.3.5" "@types/react-virtualized-auto-sizer": "npm:1.0.1" "@types/uuid": "npm:8.3.4" "@typescript-eslint/eslint-plugin": "npm:^8.34.0" @@ -3988,7 +3922,6 @@ __metadata: "@eslint/js": "npm:^9.28.0" "@floating-ui/react": "npm:^0.26.16" "@grafana/eslint-config": "npm:^8.1.0" - "@grafana/i18n": "npm:12.1.0" "@grafana/tsconfig": "npm:^1.3.0-rc1" "@leeoniya/ufuzzy": "npm:^1.0.16" "@rollup/plugin-dynamic-import-vars": "npm:2.1.5" @@ -4008,7 +3941,7 @@ __metadata: "@types/node": "npm:20.11.30" "@types/react": "npm:18.2.74" "@types/react-dom": "npm:18.2.24" - "@types/react-grid-layout": "npm:1.3.2" + "@types/react-grid-layout": "npm:1.3.5" "@types/react-virtualized-auto-sizer": "npm:1.0.1" "@types/systemjs": "npm:^6.15.1" "@types/uuid": "npm:8.3.4" @@ -4029,7 +3962,7 @@ __metadata: jest-matcher-utils: "npm:29.7.0" lodash: "npm:4.17.21" prettier: "npm:2.5.1" - react-grid-layout: "npm:1.3.4" + react-grid-layout: "npm:1.5.2" react-router-dom: "npm:^6.28.0" react-select-event: "npm:^5.5.1" react-use: "npm:17.5.0" @@ -8015,12 +7948,12 @@ __metadata: languageName: node linkType: hard -"@types/react-grid-layout@npm:1.3.2": - version: 1.3.2 - resolution: "@types/react-grid-layout@npm:1.3.2" +"@types/react-grid-layout@npm:1.3.5": + version: 1.3.5 + resolution: "@types/react-grid-layout@npm:1.3.5" dependencies: "@types/react": "npm:*" - checksum: 10/a21fe7f790d8bd2ae385829e5d5c369788c2facfc0a9f888dc1f07b4982398e02d1ffc8fca902cd77495094a598e0951e5c907edeb773abd1bf8a6db293d54a1 + checksum: 10/21599054dfa977ed8445b1ab3198a842531cb36bd620564c3f8a469688cbea051149eb644a99b2f8f6d02f8d9909a6145668f385781b5647601e9663de216946 languageName: node linkType: hard @@ -8384,7 +8317,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.34.0, @typescript-eslint/utils@npm:^8.13.0, @typescript-eslint/utils@npm:^8.33.1": +"@typescript-eslint/utils@npm:8.34.0, @typescript-eslint/utils@npm:^8.13.0": version: 8.34.0 resolution: "@typescript-eslint/utils@npm:8.34.0" dependencies: @@ -10704,6 +10637,13 @@ __metadata: languageName: node linkType: hard +"clsx@npm:^2.1.1": + version: 2.1.1 + resolution: "clsx@npm:2.1.1" + checksum: 10/cdfb57fa6c7649bbff98d9028c2f0de2f91c86f551179541cf784b1cfdc1562dcb951955f46d54d930a3879931a980e32a46b598acaea274728dbe068deca919 + languageName: node + linkType: hard + "cmd-shim@npm:6.0.3": version: 6.0.3 resolution: "cmd-shim@npm:6.0.3" @@ -12354,13 +12294,6 @@ __metadata: languageName: node linkType: hard -"decimal.js@npm:^10.4.3": - version: 10.5.0 - resolution: "decimal.js@npm:10.5.0" - checksum: 10/714d49cf2f2207b268221795ede330e51452b7c451a0c02a770837d2d4faed47d603a729c2aa1d952eb6c4102d999e91c9b952c1aa016db3c5cba9fc8bf4cda2 - languageName: node - linkType: hard - "decode-named-character-reference@npm:^1.0.0": version: 1.0.2 resolution: "decode-named-character-reference@npm:1.0.2" @@ -14370,6 +14303,13 @@ __metadata: languageName: node linkType: hard +"fast-equals@npm:^4.0.3": + version: 4.0.3 + resolution: "fast-equals@npm:4.0.3" + checksum: 10/04c1ff47b79923314e9b63ec6c81beeaa5e3b9588ec230ee6aff7ece725ff834a72abf627055055127bd0f53ae8a92cc04c3a6e187783fd932dbef743f9b13bf + languageName: node + linkType: hard + "fast-fifo@npm:^1.3.2": version: 1.3.2 resolution: "fast-fifo@npm:1.3.2" @@ -16702,24 +16642,6 @@ __metadata: languageName: node linkType: hard -"i18next-pseudo@npm:^2.2.1": - version: 2.2.1 - resolution: "i18next-pseudo@npm:2.2.1" - dependencies: - i18next: "npm:^19.1.0" - checksum: 10/4eeec03540c6e9bb823b804cffcb2b95555b0a1d185e0287c74d2deaf7e6bfa206b0223d69db4fbe7b90c66faba451737b06151c85708afd2c5e9502adf817b2 - languageName: node - linkType: hard - -"i18next@npm:^19.1.0": - version: 19.9.2 - resolution: "i18next@npm:19.9.2" - dependencies: - "@babel/runtime": "npm:^7.12.0" - checksum: 10/a3b8da898edf74257984821b8eaf11929db4cab2c123dadad05c641af98bfcf94ddddee951d091e45f6f7510db47294f4d67134906b1dd82f144f01534153710 - languageName: node - linkType: hard - "i18next@npm:^23.5.1 || ^24.2.0": version: 24.2.3 resolution: "i18next@npm:24.2.3" @@ -16748,20 +16670,6 @@ __metadata: languageName: node linkType: hard -"i18next@npm:^25.0.0": - version: 25.3.2 - resolution: "i18next@npm:25.3.2" - dependencies: - "@babel/runtime": "npm:^7.27.6" - peerDependencies: - typescript: ^5 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10/fb6b2035cc8f3bcc89f56e164d22cefbefd54e5a569315b20ddcfa6e1b68c48962307181b271fea7e5ee37ddfaa90721a4a7f7814b739f24bf00a3a670b8eb93 - languageName: node - linkType: hard - "iconv-lite@npm:0.4.24, iconv-lite@npm:^0.4.8": version: 0.4.24 resolution: "iconv-lite@npm:0.4.24" @@ -19304,13 +19212,6 @@ __metadata: languageName: node linkType: hard -"lodash.isequal@npm:^4.0.0": - version: 4.5.0 - resolution: "lodash.isequal@npm:4.5.0" - checksum: 10/82fc58a83a1555f8df34ca9a2cd300995ff94018ac12cc47c349655f0ae1d4d92ba346db4c19bbfc90510764e0c00ddcc985a358bdcd4b3b965abf8f2a48a214 - languageName: node - linkType: hard - "lodash.ismatch@npm:^4.4.0": version: 4.4.0 resolution: "lodash.ismatch@npm:4.4.0" @@ -24112,7 +24013,7 @@ __metadata: languageName: node linkType: hard -"react-draggable@npm:^4.0.0, react-draggable@npm:^4.0.3": +"react-draggable@npm:^4.0.3": version: 4.4.6 resolution: "react-draggable@npm:4.4.6" dependencies: @@ -24125,6 +24026,19 @@ __metadata: languageName: node linkType: hard +"react-draggable@npm:^4.4.6": + version: 4.5.0 + resolution: "react-draggable@npm:4.5.0" + dependencies: + clsx: "npm:^2.1.1" + prop-types: "npm:^15.8.1" + peerDependencies: + react: ">= 16.3.0" + react-dom: ">= 16.3.0" + checksum: 10/fd4080a082fad199103c6978c8a78c80154a0205dbd14ca2c7bb75634132a6afd83a3e4669f2d8fe54efe68569ef24a992439183289d83e71030b0a1791d3476 + languageName: node + linkType: hard + "react-dropzone@npm:14.3.5": version: 14.3.5 resolution: "react-dropzone@npm:14.3.5" @@ -24172,19 +24086,20 @@ __metadata: languageName: node linkType: hard -"react-grid-layout@npm:1.3.4": - version: 1.3.4 - resolution: "react-grid-layout@npm:1.3.4" +"react-grid-layout@npm:1.5.2": + version: 1.5.2 + resolution: "react-grid-layout@npm:1.5.2" dependencies: - clsx: "npm:^1.1.1" - lodash.isequal: "npm:^4.0.0" + clsx: "npm:^2.1.1" + fast-equals: "npm:^4.0.3" prop-types: "npm:^15.8.1" - react-draggable: "npm:^4.0.0" - react-resizable: "npm:^3.0.4" + react-draggable: "npm:^4.4.6" + react-resizable: "npm:^3.0.5" + resize-observer-polyfill: "npm:^1.5.1" peerDependencies: react: ">= 16.3.0" react-dom: ">= 16.3.0" - checksum: 10/944ab133e59bfaa5633625f57be9f69133b5cec2de0232d9581e2c988e257ebafe010ee9bbbff6c2754f9d7d8bb0053072bac103f20fc232be2a58e15d14fc64 + checksum: 10/0b2ed84b8b7eeebfd30671a879c84b7873830354389bcec98f38efccf51c2e78115bf76b19a77d5b07e139478ba7cc26593e122a0e5e71487ad8ad2b6af55629 languageName: node linkType: hard @@ -24353,7 +24268,7 @@ __metadata: languageName: node linkType: hard -"react-resizable@npm:^3.0.4": +"react-resizable@npm:^3.0.5": version: 3.0.5 resolution: "react-resizable@npm:3.0.5" dependencies: @@ -28036,7 +27951,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:2.8.1, tslib@npm:^2, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.7.0, tslib@npm:^2.8.0": +"tslib@npm:2.8.1, tslib@npm:^2, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.0, tslib@npm:^2.4.0, tslib@npm:^2.5.0, tslib@npm:^2.6.0, tslib@npm:^2.6.2, tslib@npm:^2.7.0": version: 2.8.1 resolution: "tslib@npm:2.8.1" checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7