From d2388a01ad9442711c9a59a6812cc6f82f80da32 Mon Sep 17 00:00:00 2001 From: Andrew Chang Date: Fri, 7 Aug 2026 14:03:09 +0800 Subject: [PATCH 1/4] Make copied task log text match the on-screen format Users expect copying logs to yield exactly what the screen shows. The clipboard rebuild for rows the virtualizer unmounted previously emitted the raw download format, so one copy could mix two timestamp formats and drop the group expand marker. The group marker now also follows the expand state (collapsed / expanded) in both the DOM and the rebuilt text. Follow-up to review feedback on #71156; the log download keeps raw source timestamps. --- .../ui/src/components/renderStructuredLog.tsx | 9 ++- .../src/pages/TaskInstance/Logs/Logs.test.tsx | 76 +++++++++++++++++++ .../TaskInstance/Logs/TaskLogContent.tsx | 22 +++--- .../TaskInstance/Logs/logSelection.test.ts | 14 +++- .../pages/TaskInstance/Logs/logSelection.ts | 15 ++-- .../ui/src/pages/TaskInstance/Logs/utils.ts | 3 + .../airflow/ui/src/queries/useLogs.test.ts | 31 ++++++++ .../src/airflow/ui/src/queries/useLogs.tsx | 34 ++++++++- 8 files changed, 181 insertions(+), 23 deletions(-) diff --git a/airflow-core/src/airflow/ui/src/components/renderStructuredLog.tsx b/airflow-core/src/airflow/ui/src/components/renderStructuredLog.tsx index bac81ef906d01..53e5200193ac4 100644 --- a/airflow-core/src/airflow/ui/src/components/renderStructuredLog.tsx +++ b/airflow-core/src/airflow/ui/src/components/renderStructuredLog.tsx @@ -44,6 +44,8 @@ type ErrorDetail = { }; type RenderStructuredLogProps = { + /** Text mode only: render the timestamp with this instead of emitting the raw source value. */ + formatTimestamp?: (timestamp: string) => string; index: number; logLevelFilters?: Array; logLink: string; @@ -173,6 +175,7 @@ export const extractTIContext = ( }; const renderStructuredLogImpl = ({ + formatTimestamp, index, logLevelFilters, logLink, @@ -216,9 +219,9 @@ const renderStructuredLogImpl = ({ return ""; } - if (Boolean(timestamp) && showTimestamp) { + if (timestamp !== undefined && Boolean(timestamp) && showTimestamp) { if (renderingMode === "text") { - elements.push(`[${timestamp}] `); + elements.push(`[${formatTimestamp?.(timestamp) ?? timestamp}] `); } else { elements.push("[",