pierrejeambrun commented on code in PR #54447:
URL: https://github.com/apache/airflow/pull/54447#discussion_r2293851940


##########
airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogContent.tsx:
##########
@@ -54,14 +54,8 @@ const ScrollToButton = ({
       openDelay={100}
     >
       <IconButton
-        _ltr={{
-          left: "auto",
-          right: 4,
-        }}
-        _rtl={{
-          left: 4,
-          right: "auto",
-        }}
+        _ltr={{ left: "auto", right: 4 }}
+        _rtl={{ left: 4, right: "auto" }}

Review Comment:
   Not needed, to change formatting there.



##########
airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/TaskLogContent.tsx:
##########
@@ -94,16 +90,114 @@ export const TaskLogContent = ({ error, isLoading, 
logError, parsedLogs, wrap }:
     return parsedLogs.length > 1 && contentHeight > containerHeight;
   }, [rowVirtualizer, parsedLogs]);
 
+  // Precise jump to hash index
   useLayoutEffect(() => {
-    if (location.hash && !isLoading) {
-      rowVirtualizer.scrollToIndex(Math.min(Number(hash) + 5, 
parsedLogs.length - 1));
+    if (!location.hash || isLoading || parsedLogs.length === 0) {
+      return;
+    }
+
+    const targetIndex = Math.max(0, Math.min(parsedLogs.length - 1, 
Number(hash) || 0));
+    const el = parentRef.current;
+
+    // Prefer exact offset if we already have the virtual item measured
+    const total = rowVirtualizer.getTotalSize();
+    const clientH = el?.clientHeight ?? 0;
+
+    // If the item is currently virtualized, use its start; otherwise 
approximate
+    const vItem = rowVirtualizer.getVirtualItems().find((virtualRow) => 
virtualRow.index === targetIndex);
+    const approxPerItem = 20; // same as estimateSize
+    const anchor = vItem?.start ?? targetIndex * approxPerItem;
+
+    const offset = Math.max(0, Math.min(total - clientH, anchor));
+
+    if (el) {
+      // Force both virtualizer and DOM to the exact offset to avoid slow 
incremental scrolling
+      if (typeof rowVirtualizer.scrollToOffset === "function") {
+        try {
+          rowVirtualizer.scrollToOffset(offset);
+        } catch {
+          rowVirtualizer.scrollToIndex(targetIndex, { align: "start" });
+        }
+      } else {
+        rowVirtualizer.scrollToIndex(targetIndex, { align: "start" });
+      }
+
+      el.scrollTop = offset;
+
+      // One more frame to settle measurements for large lists
+      requestAnimationFrame(() => {
+        el.scrollTop = offset;
+      });
+    } else {
+      rowVirtualizer.scrollToIndex(targetIndex, { align: "start" });
     }
   }, [isLoading, rowVirtualizer, hash, parsedLogs]);
 
+  // Robust, instant jump-to handler
   const handleScrollTo = (to: "bottom" | "top") => {
-    if (parsedLogs.length > 0) {
-      rowVirtualizer.scrollToIndex(to === "bottom" ? parsedLogs.length - 1 : 
0);
+    if (parsedLogs.length === 0) {
+      return;
+    }
+
+    const el = rowVirtualizer.scrollElement ?? parentRef.current;
+
+    if (!el) {
+      return;
+    }
+
+    if (to === "top") {
+      // Jump instantly to top
+      if (typeof rowVirtualizer.scrollToOffset === "function") {
+        try {
+          rowVirtualizer.scrollToOffset(0);
+        } catch {
+          rowVirtualizer.scrollToIndex(0, { align: "start" });
+        }
+      } else {
+        rowVirtualizer.scrollToIndex(0, { align: "start" });
+      }
+      el.scrollTop = 0;
+      requestAnimationFrame(() => {
+        el.scrollTop = 0;
+      });
+
+      return;
     }
+
+    // === bottom === (instant jump even for huge lists)
+    const total = rowVirtualizer.getTotalSize();
+    const clientH = el.clientHeight || 0;
+    const offset = Math.max(0, Math.floor(total - clientH));
+
+    // First tell the virtualizer where we want to be
+    if (typeof rowVirtualizer.scrollToOffset === "function") {
+      try {
+        rowVirtualizer.scrollToOffset(offset);
+      } catch {
+        rowVirtualizer.scrollToIndex(parsedLogs.length - 1, { align: "end" });
+      }
+    } else {
+      rowVirtualizer.scrollToIndex(parsedLogs.length - 1, { align: "end" });
+    }
+
+    // Then force the DOM to that exact pixel offset
+    el.scrollTop = offset;
+
+    // A couple of RAFs to ensure post-measurement settling for very large 
lists
+    requestAnimationFrame(() => {
+      el.scrollTop = offset;
+      requestAnimationFrame(() => {
+        // final nudge + fallback to last item visibility if needed
+        el.scrollTop = offset;
+        const lastItem = el.querySelector<HTMLElement>(
+          `[data-testid="virtualized-item-${parsedLogs.length - 1}"]`,
+        );
+
+        if (lastItem) {
+          lastItem.scrollIntoView({ behavior: "auto", block: "end" });
+        }
+      });
+    });

Review Comment:
   This looks overly complicated to achieve what we want (maybe hinted by an AI 
agent?). Can we trim this down to the bare minimum to achieve the feature 
please.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to