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 f5774789ea0 Pr/split storage tab (#73989)
f5774789ea0 is described below

commit f5774789ea02120e0fcc712b457a58466aaa4dce
Author: Brent Bovenzi <[email protected]>
AuthorDate: Mon Oct 5 15:56:27 2026 -0400

    Pr/split storage tab (#73989)
    
    * UI: Split the Storage tab into XCom and Task State Store
    
    XCom and the task state store were grouped behind one Storage tab because
    both are key-value stores, which groups them by storage mechanism rather
    than by what a user came to look at. Neither is a sub-view of the other.
    
    * Cleanup i18n
    
    * Drop the dead layout-children branch from task-instance sub-routes
    
    Splitting the Storage tab removed the only pathless layout route, so
    `taskInstanceRoutes` no longer has an entry with `children`. That left the
    `"children" in route` branch unreachable, and with nothing in the union to
    type it `route.children` degraded to `any`, failing the UI lint with four
    `no-unsafe-*` errors.
    
    Co-Authored-By: Claude <[email protected]>
    
    ---------
    
    Co-authored-by: Claude <[email protected]>
---
 .../src/airflow/ui/public/i18n/locales/ar/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/ca/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/de/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/el/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/en/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/es/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/fr/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/he/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/hi/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/hu/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/ko/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/nl/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/pl/dag.json |  1 -
 .../src/airflow/ui/public/i18n/locales/ru/dag.json |  1 -
 .../airflow/ui/public/i18n/locales/zh-CN/dag.json  |  1 -
 .../airflow/ui/public/i18n/locales/zh-TW/dag.json  |  1 -
 .../src/airflow/ui/src/layouts/StorageLayout.tsx   | 40 ----------------------
 .../src/pages/TaskInstance/TaskInstance.test.tsx   |  3 +-
 .../ui/src/pages/TaskInstance/TaskInstance.tsx     | 17 +++++----
 airflow-core/src/airflow/ui/src/router.tsx         | 10 ++----
 airflow-core/src/airflow/ui/src/utils/links.ts     | 15 +-------
 21 files changed, 15 insertions(+), 86 deletions(-)

diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/ar/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/ar/dag.json
index 73b4b152f35..1295499b3a6 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/ar/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/ar/dag.json
@@ -252,7 +252,6 @@
     "renderedTemplates": "القوالب المعروضة",
     "requiredActions": "إجراءات مطلوبة",
     "runs": "تشغيلات",
-    "storage": "التخزين",
     "taskInstances": "مثيلات المهام",
     "taskStateStore": "مخزن حالة المهمة",
     "tasks": "المهام",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/ca/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/ca/dag.json
index 44a598e0b4f..f41ccfed5b2 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/ca/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/ca/dag.json
@@ -216,7 +216,6 @@
     "renderedTemplates": "Plantilles renderitzades",
     "requiredActions": "Accions requerides",
     "runs": "Execucions",
-    "storage": "Emmagatzematge",
     "taskInstances": "Instàncies de tasca",
     "taskStateStore": "Magatzem de tasca",
     "tasks": "Tasques",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/de/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/de/dag.json
index 87f9114acd8..e2f9a1fd214 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/de/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/de/dag.json
@@ -221,7 +221,6 @@
     "renderedTemplates": "Ausgefüllte Vorlagen",
     "requiredActions": "Interaktionen",
     "runs": "Läufe",
-    "storage": "Speicher",
     "taskInstances": "Task Instanzen",
     "taskStateStore": "Task Status Zwischenspeicher",
     "tasks": "Tasks",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/el/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/el/dag.json
index fa3e170889f..12c0f628fb2 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/el/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/el/dag.json
@@ -221,7 +221,6 @@
     "renderedTemplates": "Αποδοθέντα Πρότυπα",
     "requiredActions": "Απαιτούμενες Ενέργειες",
     "runs": "Εκτελέσεις",
-    "storage": "Αποθήκευση",
     "taskInstances": "Στιγμιαίες Καταστάσεις Εργασίας",
     "taskStateStore": "Αποθήκη Καταστάσεων Εργασίας",
     "tasks": "Εργασίες",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
index f82b24453dd..ce354726ad2 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/dag.json
@@ -221,7 +221,6 @@
     "renderedTemplates": "Rendered Templates",
     "requiredActions": "Required Actions",
     "runs": "Runs",
-    "storage": "Storage",
     "taskInstances": "Task Instances",
     "taskStateStore": "Task State Store",
     "tasks": "Tasks",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/es/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/es/dag.json
index 00324562d4d..f017c882610 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/es/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/es/dag.json
@@ -216,7 +216,6 @@
     "renderedTemplates": "Plantillas Renderizadas",
     "requiredActions": "Acciones Requeridas",
     "runs": "Ejecuciones",
-    "storage": "Almacenamiento",
     "taskInstances": "Instancias de Tarea",
     "taskStateStore": "Almacenamiento de Estado de Tarea",
     "tasks": "Tareas",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/fr/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/fr/dag.json
index 5e06822ae46..536aaeb5726 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/fr/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/fr/dag.json
@@ -224,7 +224,6 @@
     "renderedTemplates": "Modèles rendus",
     "requiredActions": "Actions requises",
     "runs": "Runs",
-    "storage": "Stockage",
     "taskInstances": "Task Instances",
     "taskStateStore": "Stockage d'état de tâche",
     "tasks": "Tâches",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/he/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/he/dag.json
index c1ee6c8493b..eb6fba38edf 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/he/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/he/dag.json
@@ -233,7 +233,6 @@
     "renderedTemplates": "תבניות מעובדות",
     "requiredActions": "פעולות נדרשות",
     "runs": "הרצות",
-    "storage": "אחסון",
     "taskInstances": "מופעי משימות",
     "taskStateStore": "מאגר מצבי משימות",
     "tasks": "משימות",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/hi/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/hi/dag.json
index 8e436ab7a4b..8b8c4638942 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/hi/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/hi/dag.json
@@ -225,7 +225,6 @@
     "renderedTemplates": "रेंडर किए गए टेम्प्लेट्स",
     "requiredActions": "आवश्यक क्रियाएं",
     "runs": "रन्स",
-    "storage": "स्टोरेज",
     "taskInstances": "टास्क इंस्टेंसेज",
     "taskStateStore": "Task State Store",
     "tasks": "टास्क्स",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/hu/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/hu/dag.json
index a4a8c1cb057..7cc8523da9b 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/hu/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/hu/dag.json
@@ -225,7 +225,6 @@
     "renderedTemplates": "Renderelt sablonok",
     "requiredActions": "Szükséges műveletek",
     "runs": "Futások",
-    "storage": "Tárhely",
     "taskInstances": "Feladatpéldányok",
     "taskStore": "Feladat tároló",
     "tasks": "Feladatok",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/ko/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/ko/dag.json
index 5f2aacfa6e8..601d06dda9a 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/ko/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/ko/dag.json
@@ -216,7 +216,6 @@
     "renderedTemplates": "렌더링된 템플릿",
     "requiredActions": "필수 작업",
     "runs": "실행",
-    "storage": "스토리지",
     "taskInstances": "태스크 인스턴스",
     "taskStateStore": "태스크 상태 저장소",
     "tasks": "태스크",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/nl/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/nl/dag.json
index fda29c0f75f..3e5e00dcce8 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/nl/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/nl/dag.json
@@ -226,7 +226,6 @@
     "renderedTemplates": "Gerenderde templates",
     "requiredActions": "Vereiste acties",
     "runs": "Runs",
-    "storage": "Opslag",
     "taskInstances": "Taakinstanties",
     "taskStateStore": "Task State Store",
     "tasks": "Taken",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/pl/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/pl/dag.json
index 9c1390aa8c2..f5ca47e39b0 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/pl/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/pl/dag.json
@@ -232,7 +232,6 @@
     "renderedTemplates": "Wyrenderowane szablony",
     "requiredActions": "Wymagane akcje",
     "runs": "Wykonania",
-    "storage": "Magazyn",
     "taskInstances": "Instancje zadań",
     "taskStateStore": "Magazyn stanu zadania",
     "tasks": "Zadania",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/ru/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/ru/dag.json
index 0771d24b42d..96a95157c8e 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/ru/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/ru/dag.json
@@ -240,7 +240,6 @@
     "renderedTemplates": "Отрендеренные шаблоны",
     "requiredActions": "Необходимые действия",
     "runs": "Запуски",
-    "storage": "Хранилище",
     "taskInstances": "Экземпляры задач",
     "taskStateStore": "Хранилище состояния задач",
     "tasks": "Задачи",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/zh-CN/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/zh-CN/dag.json
index 0cfd93ff137..997cc2e2378 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/zh-CN/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/zh-CN/dag.json
@@ -216,7 +216,6 @@
     "renderedTemplates": "渲染后的模板",
     "requiredActions": "待响应的任务实例",
     "runs": "执行记录",
-    "storage": "存储",
     "taskInstances": "任务实例",
     "taskStateStore": "任务存储",
     "tasks": "任务",
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/dag.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/dag.json
index e32e2606d0d..b058abf241a 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/dag.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/zh-TW/dag.json
@@ -216,7 +216,6 @@
     "renderedTemplates": "渲染後的範本",
     "requiredActions": "待回應的任務實例",
     "runs": "執行紀錄",
-    "storage": "儲存空間",
     "taskInstances": "任務實例",
     "taskStateStore": "任務儲存區",
     "tasks": "任務",
diff --git a/airflow-core/src/airflow/ui/src/layouts/StorageLayout.tsx 
b/airflow-core/src/airflow/ui/src/layouts/StorageLayout.tsx
deleted file mode 100644
index 4c68755d508..00000000000
--- a/airflow-core/src/airflow/ui/src/layouts/StorageLayout.tsx
+++ /dev/null
@@ -1,40 +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 { useTranslation } from "react-i18next";
-import { MdOutlineStorage, MdSyncAlt } from "react-icons/md";
-import { Outlet } from "react-router-dom";
-
-import { NavTabs } from "src/layouts/Details/NavTabs";
-
-/** Sub-nav tabs shared by the task-store and xcom routes. */
-export const StorageLayout = () => {
-  const { t: translate } = useTranslation("dag");
-
-  return (
-    <>
-      <NavTabs
-        tabs={[
-          { icon: <MdSyncAlt />, label: translate("tabs.xcom"), value: "xcom" 
},
-          { icon: <MdOutlineStorage />, label: 
translate("tabs.taskStateStore"), value: "task-state-store" },
-        ]}
-      />
-      <Outlet />
-    </>
-  );
-};
diff --git 
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.test.tsx 
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.test.tsx
index c0c66b1f838..369535f0a23 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.test.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.test.tsx
@@ -160,7 +160,8 @@ describe("TaskInstance", () => {
     ["tabs.auditLog", "events"],
     ["tabs.mappedTaskInstances_other", "task_instances"],
     ["tabs.renderedTemplates", "rendered_templates"],
-    ["tabs.storage", "xcom"],
+    ["tabs.xcom", "xcom"],
+    ["tabs.taskStateStore", "task-state-store"],
     ["tabs.assetEvents", "asset_events"],
     ["tabs.code", "code"],
   ])("does not carry try selection into %s", async (label, destination) => {
diff --git 
a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx 
b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
index df0c52d451a..284bf61b2b6 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
@@ -20,7 +20,14 @@ import { Heading } from "@chakra-ui/react";
 import { ReactFlowProvider } from "@xyflow/react";
 import { useTranslation } from "react-i18next";
 import { FiCode, FiDatabase, FiUser } from "react-icons/fi";
-import { MdDetails, MdOutlineEventNote, MdOutlineStorage, MdOutlineTask, 
MdReorder } from "react-icons/md";
+import {
+  MdDetails,
+  MdOutlineEventNote,
+  MdOutlineStorage,
+  MdOutlineTask,
+  MdReorder,
+  MdSyncAlt,
+} from "react-icons/md";
 import { PiBracketsCurlyBold } from "react-icons/pi";
 import { useParams, useSearchParams } from "react-router-dom";
 
@@ -78,12 +85,8 @@ export const TaskInstance = () => {
       label: translate("tabs.renderedTemplates"),
       value: "rendered_templates",
     },
-    {
-      icon: <MdOutlineStorage />,
-      label: translate("tabs.storage"),
-      matchPaths: ["task-state-store", "xcom"],
-      value: "xcom",
-    },
+    { icon: <MdSyncAlt />, label: translate("tabs.xcom"), value: "xcom" },
+    { icon: <MdOutlineStorage />, label: translate("tabs.taskStateStore"), 
value: "task-state-store" },
     { icon: <FiDatabase />, label: translate("tabs.assetEvents"), value: 
"asset_events" },
     { icon: <MdOutlineEventNote />, label: translate("tabs.auditLog"), value: 
"events" },
     { icon: <FiCode />, label: translate("tabs.code"), value: "code" },
diff --git a/airflow-core/src/airflow/ui/src/router.tsx 
b/airflow-core/src/airflow/ui/src/router.tsx
index e94f369c0a3..0345d06cd72 100644
--- a/airflow-core/src/airflow/ui/src/router.tsx
+++ b/airflow-core/src/airflow/ui/src/router.tsx
@@ -77,7 +77,6 @@ import { XCom } from "src/pages/XCom";
 
 import { TabEntity, TabName, TaskInstanceTab } from "src/constants/tab";
 
-import { StorageLayout } from "./layouts/StorageLayout";
 import { client } from "./queryClient";
 
 const pluginRoute = {
@@ -89,13 +88,8 @@ export const taskInstanceRoutes = [
   { element: <TaskInstanceDefaultTab />, index: true, path: undefined },
   { element: <Logs />, path: TaskInstanceTab.Logs },
   { element: <Events />, path: TaskInstanceTab.Events },
-  {
-    children: [
-      { element: <XCom />, path: TaskInstanceTab.XCom },
-      { element: <TaskStateStore />, path: TaskInstanceTab.TaskStateStore },
-    ],
-    element: <StorageLayout />,
-  },
+  { element: <XCom />, path: TaskInstanceTab.XCom },
+  { element: <TaskStateStore />, path: TaskInstanceTab.TaskStateStore },
   { element: <Code />, path: TaskInstanceTab.Code },
   { element: <TaskInstanceDetails />, path: TaskInstanceTab.Details },
   { element: <RenderedTemplates />, path: TaskInstanceTab.RenderedTemplates },
diff --git a/airflow-core/src/airflow/ui/src/utils/links.ts 
b/airflow-core/src/airflow/ui/src/utils/links.ts
index b2d96e93b2b..935b29ef70c 100644
--- a/airflow-core/src/airflow/ui/src/utils/links.ts
+++ b/airflow-core/src/airflow/ui/src/utils/links.ts
@@ -66,20 +66,7 @@ export const getNextHref = (location: Pick<Location, "hash" 
| "pathname" | "sear
   `${location.pathname}${location.search}${location.hash}`;
 
 export const getTaskInstanceAdditionalPath = (pathname: string): string => {
-  const subRoutes = taskInstanceRoutes.flatMap((route) => {
-    if (route.path !== undefined) {
-      return [route.path];
-    }
-
-    // Include paths from children of pathless layout routes (e.g. StoragePage 
wrapping task-store and xcom)
-    if ("children" in route && Array.isArray(route.children)) {
-      return route.children
-        .filter((child) => "path" in child && typeof child.path === "string")
-        .map((child) => child.path);
-    }
-
-    return [];
-  });
+  const subRoutes = taskInstanceRoutes.flatMap((route) => (route.path === 
undefined ? [] : [route.path]));
   // Look for patterns like /tasks/{taskId}/mapped/{mapIndex}/{sub-route}
   const mappedRegex = /\/tasks\/[^/]+\/mapped\/[^/]+\/(?<subRoute>.+)$/u;
   const mappedMatch = mappedRegex.exec(pathname);

Reply via email to