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 };
-};

Reply via email to