This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 547d5e6b386 Remove react-resizable dependency from UI (#62226)
547d5e6b386 is described below
commit 547d5e6b386cf5837da85797a282395fc9016475
Author: Guan-Ming (Wesley) Chiu <[email protected]>
AuthorDate: Tue Feb 24 00:59:51 2026 +0800
Remove react-resizable dependency from UI (#62226)
Signed-off-by: Guan-Ming (Wesley) Chiu
<[email protected]>
---
airflow-core/src/airflow/ui/package.json | 2 -
airflow-core/src/airflow/ui/pnpm-lock.yaml | 60 ----------------
.../ui/src/components/ui/ResizableWrapper.tsx | 81 ++++++++++++----------
.../ui/src/utils/usePersistentResizableState.ts | 38 ----------
4 files changed, 46 insertions(+), 135 deletions(-)
diff --git a/airflow-core/src/airflow/ui/package.json
b/airflow-core/src/airflow/ui/package.json
index cb3373a16cd..dcb41fdc47e 100644
--- a/airflow-core/src/airflow/ui/package.json
+++ b/airflow-core/src/airflow/ui/package.json
@@ -62,7 +62,6 @@
"react-innertext": "^1.1.5",
"react-json-view": "^1.21.3",
"react-markdown": "^9.1.0",
- "react-resizable": "^3.0.5",
"react-resizable-panels": "^3.0.6",
"react-router-dom": "^7.12.0",
"react-syntax-highlighter": "^15.6.1",
@@ -85,7 +84,6 @@
"@types/node": "^24.10.1",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
- "@types/react-resizable": "^3.0.8",
"@types/react-syntax-highlighter": "^15.5.13",
"@typescript-eslint/eslint-plugin": "^8.49.0",
"@typescript-eslint/parser": "^8.49.0",
diff --git a/airflow-core/src/airflow/ui/pnpm-lock.yaml
b/airflow-core/src/airflow/ui/pnpm-lock.yaml
index 5f96dad36d8..6ae510da234 100644
--- a/airflow-core/src/airflow/ui/pnpm-lock.yaml
+++ b/airflow-core/src/airflow/ui/pnpm-lock.yaml
@@ -127,9 +127,6 @@ importers:
react-markdown:
specifier: ^9.1.0
version: 9.1.0(@types/[email protected])([email protected])
- react-resizable:
- specifier: ^3.0.5
- version: 3.0.5([email protected]([email protected]))([email protected])
react-resizable-panels:
specifier: ^3.0.6
version: 3.0.6([email protected]([email protected]))([email protected])
@@ -191,9 +188,6 @@ importers:
'@types/react-dom':
specifier: ^19.2.3
version: 19.2.3(@types/[email protected])
- '@types/react-resizable':
- specifier: ^3.0.8
- version: 3.0.8
'@types/react-syntax-highlighter':
specifier: ^15.5.13
version: 15.5.13
@@ -1015,67 +1009,56 @@ packages:
resolution: {integrity:
sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
cpu: [arm]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
cpu: [arm]
os: [linux]
- libc: [musl]
'@rollup/[email protected]':
resolution: {integrity:
sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
cpu: [arm64]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
cpu: [arm64]
os: [linux]
- libc: [musl]
'@rollup/[email protected]':
resolution: {integrity:
sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
cpu: [loong64]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
cpu: [ppc64]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
cpu: [riscv64]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
cpu: [riscv64]
os: [linux]
- libc: [musl]
'@rollup/[email protected]':
resolution: {integrity:
sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
cpu: [s390x]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
cpu: [x64]
os: [linux]
- libc: [glibc]
'@rollup/[email protected]':
resolution: {integrity:
sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
cpu: [x64]
os: [linux]
- libc: [musl]
'@rollup/[email protected]':
resolution: {integrity:
sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
@@ -1131,28 +1114,24 @@ packages:
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
- libc: [glibc]
'@swc/[email protected]':
resolution: {integrity:
sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==}
engines: {node: '>=10'}
cpu: [arm64]
os: [linux]
- libc: [musl]
'@swc/[email protected]':
resolution: {integrity:
sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
- libc: [glibc]
'@swc/[email protected]':
resolution: {integrity:
sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==}
engines: {node: '>=10'}
cpu: [x64]
os: [linux]
- libc: [musl]
'@swc/[email protected]':
resolution: {integrity:
sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==}
@@ -1383,9 +1362,6 @@ packages:
peerDependencies:
'@types/react': ^19.2.0
- '@types/[email protected]':
- resolution: {integrity:
sha512-Pcvt2eGA7KNXldt1hkhVhAgZ8hK41m0mp89mFgQi7LAAEZiaLgm4fHJ5zbJZ/4m2LVaAyYrrRRv1LHDcrGQanA==}
-
'@types/[email protected]':
resolution: {integrity:
sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==}
@@ -2261,10 +2237,6 @@ packages:
resolution: {integrity:
sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
- [email protected]:
- resolution: {integrity:
sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
- engines: {node: '>=6'}
-
[email protected]:
resolution: {integrity:
sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==}
@@ -3855,12 +3827,6 @@ packages:
peerDependencies:
react: ^19.2.4
- [email protected]:
- resolution: {integrity:
sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==}
- peerDependencies:
- react: '>= 16.3.0'
- react-dom: '>= 16.3.0'
-
[email protected]:
resolution: {integrity:
sha512-vpfuHuQMF/L6GpuQ4c3ZDo+pRYxIi40gQqsCmmfUBwm+oqvBhKhwghCuj2o00YCgSfU6bR9KC/xnQGWm3Gr08A==}
engines: {node: '>=18.0.0'}
@@ -3931,11 +3897,6 @@ packages:
react: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
- [email protected]:
- resolution: {integrity:
sha512-vKpeHhI5OZvYn82kXOs1bC8aOXktGU5AmKAgaZS4F5JPburCtbmDPqE7Pzp+1kN4+Wb81LlF33VpGwWwtXem+w==}
- peerDependencies:
- react: '>= 16.3'
-
[email protected]:
resolution: {integrity:
sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA==}
engines: {node: '>=20.0.0'}
@@ -5861,10 +5822,6 @@ snapshots:
dependencies:
'@types/react': 19.2.7
- '@types/[email protected]':
- dependencies:
- '@types/react': 18.3.19
-
'@types/[email protected]':
dependencies:
'@types/react': 18.3.19
@@ -7412,8 +7369,6 @@ snapshots:
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
- [email protected]: {}
-
[email protected]: {}
[email protected](@lezer/[email protected]):
@@ -9390,13 +9345,6 @@ snapshots:
react: 19.2.4
scheduler: 0.27.0
- [email protected]([email protected]([email protected]))([email protected]):
- dependencies:
- clsx: 2.1.1
- prop-types: 15.8.1
- react: 19.2.4
- react-dom: 19.2.4([email protected])
-
[email protected]([email protected]):
dependencies:
react: 19.2.4
@@ -9468,14 +9416,6 @@ snapshots:
react: 19.2.4
react-dom: 19.2.4([email protected])
- [email protected]([email protected]([email protected]))([email protected]):
- dependencies:
- prop-types: 15.8.1
- react: 19.2.4
- react-draggable: 4.5.0([email protected]([email protected]))([email protected])
- transitivePeerDependencies:
- - react-dom
-
[email protected]([email protected]([email protected]))([email protected]):
dependencies:
react: 19.2.4
diff --git a/airflow-core/src/airflow/ui/src/components/ui/ResizableWrapper.tsx
b/airflow-core/src/airflow/ui/src/components/ui/ResizableWrapper.tsx
index a8e37aa9d30..d448a181bbc 100644
--- a/airflow-core/src/airflow/ui/src/components/ui/ResizableWrapper.tsx
+++ b/airflow-core/src/airflow/ui/src/components/ui/ResizableWrapper.tsx
@@ -17,26 +17,9 @@
* under the License.
*/
import { Box } from "@chakra-ui/react";
-import { forwardRef } from "react";
import type { PropsWithChildren } from "react";
-import { ResizableBox } from "react-resizable";
-import "react-resizable/css/styles.css";
-
-import { usePersistentResizableState } from
"src/utils/usePersistentResizableState";
-
-const ResizeHandle = forwardRef<HTMLDivElement>((props, ref) => (
- <Box
- background="linear-gradient(-45deg, transparent 6px, #ccc 6px, #ccc 8px,
transparent 8px, transparent 12px, #ccc 12px, #ccc 14px, transparent 14px)"
- bottom={0}
- cursor="se-resize"
- height={5}
- position="absolute"
- ref={ref}
- right={0}
- width={5}
- {...props}
- />
-));
+import { useEffect, useRef } from "react";
+import { useLocalStorage } from "usehooks-ts";
type ResizableWrapperProps = {
readonly defaultSize?: { height: number; width: number };
@@ -55,28 +38,56 @@ export const ResizableWrapper = ({
maxConstraints = MAX_SIZE,
storageKey,
}: ResizableWrapperProps) => {
- const { handleResize, handleResizeStop, size } =
usePersistentResizableState(storageKey, defaultSize);
+ const ref = useRef<HTMLDivElement>(null);
+ const [storedSize, setStoredSize] = useLocalStorage(storageKey, defaultSize);
+
+ useEffect(() => {
+ const el = ref.current;
+
+ if (!el) {
+ return undefined;
+ }
+
+ let timeoutId: ReturnType<typeof setTimeout>;
+
+ const observer = new ResizeObserver((entries) => {
+ for (const entry of entries) {
+ const { height, width } = entry.contentRect;
+
+ if (width > 0 && height > 0) {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(() => {
+ setStoredSize({ height: Math.round(height), width:
Math.round(width) });
+ }, 300);
+ }
+ }
+ });
+
+ observer.observe(el);
+
+ return () => {
+ observer.disconnect();
+ clearTimeout(timeoutId);
+ };
+ }, [setStoredSize]);
return (
- <ResizableBox
- handle={<ResizeHandle />}
- height={size.height}
- maxConstraints={maxConstraints}
- minConstraints={[DEFAULT_SIZE.width, DEFAULT_SIZE.height]}
- onResize={handleResize}
- onResizeStop={handleResizeStop}
- resizeHandles={["se"]}
- style={{
- backgroundColor: "inherit",
- borderRadius: "inherit",
+ <Box
+ css={{
display: "flex",
flexDirection: "column",
overflow: "hidden",
- position: "relative",
+ resize: "both",
}}
- width={size.width}
+ height={`${storedSize.height}px`}
+ maxHeight={`${maxConstraints[1]}px`}
+ maxWidth={`${maxConstraints[0]}px`}
+ minHeight={`${DEFAULT_SIZE.height}px`}
+ minWidth={`${DEFAULT_SIZE.width}px`}
+ ref={ref}
+ width={`${storedSize.width}px`}
>
- <div>{children}</div>
- </ResizableBox>
+ {children}
+ </Box>
);
};
diff --git
a/airflow-core/src/airflow/ui/src/utils/usePersistentResizableState.ts
b/airflow-core/src/airflow/ui/src/utils/usePersistentResizableState.ts
deleted file mode 100644
index 95f24d2ee32..00000000000
--- a/airflow-core/src/airflow/ui/src/utils/usePersistentResizableState.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-/*!
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-import { useState } from "react";
-import { useLocalStorage } from "usehooks-ts";
-
-type Size = { height: number; width: number };
-
-export const usePersistentResizableState = (storageKey: string, defaultSize:
Size) => {
- const [storedSize, setStoredSize] = useLocalStorage(storageKey, defaultSize);
- const [size, setSize] = useState(storedSize);
-
- const handleResize = (_event: React.SyntheticEvent, { size: newSize }: {
size: Size }) => {
- setSize(newSize);
- };
-
- const handleResizeStop = (_event: React.SyntheticEvent, { size: finalSize }:
{ size: Size }) => {
- setSize(finalSize);
- setStoredSize(finalSize);
- };
-
- return { handleResize, handleResizeStop, size };
-};