This is an automated email from the ASF dual-hosted git repository.
vatsrahul1001 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 0f8d6f88b0e UI: Keep unnamed columns out of the table columns menu
(#74774)
0f8d6f88b0e is described below
commit 0f8d6f88b0e983a7861ccc56b5b55cee15f6b0d9
Author: Yuseok Jo <[email protected]>
AuthorDate: Sun Oct 18 16:47:52 2026 +0900
UI: Keep unnamed columns out of the table columns menu (#74774)
---
.../DataTable/DataTable.columnVisibility.test.tsx | 20 ++++++++++++++
.../ui/src/components/DataTable/DataTable.tsx | 20 +++++++++++++-
.../Asset/AssetStateStore/AssetStateStore.tsx | 1 +
.../ui/src/pages/Connections/Connections.tsx | 1 +
.../src/airflow/ui/src/pages/DagRuns/DagRuns.tsx | 1 +
.../ui/src/pages/DagsList/DagsListColumns.test.tsx | 31 ++++++++++++++++++++++
.../ui/src/pages/DagsList/DagsListColumns.tsx | 4 +++
.../ui/src/pages/TaskInstances/TaskInstances.tsx | 1 +
.../ui/src/pages/TaskStateStore/TaskStateStore.tsx | 1 +
.../airflow/ui/src/pages/Variables/Variables.tsx | 1 +
.../src/airflow/ui/src/pages/XCom/XCom.tsx | 1 +
11 files changed, 81 insertions(+), 1 deletion(-)
diff --git
a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.columnVisibility.test.tsx
b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.columnVisibility.test.tsx
index 72c1124eab7..8a7500e124b 100644
---
a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.columnVisibility.test.tsx
+++
b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.columnVisibility.test.tsx
@@ -54,4 +54,24 @@ describe("DataTable column visibility", () => {
expect(screen.getByRole("columnheader", { name: "Name"
})).toBeInTheDocument();
expect(screen.queryByRole("columnheader", { name: "Added" })).toBeNull();
});
+
+ it("shows a column that cannot be hidden even when stored as hidden", () => {
+ localStorage.setItem("dataTable:pinned:columnVisibility", JSON.stringify({
Added: false, name: false }));
+
+ render(
+ <DataTable
+ columns={[
+ { accessorKey: "name", cell: () => "Name", enableHiding: false,
header: "Name" },
+ { cell: () => "Added", header: "Added", id: "Added" },
+ ]}
+ data={[{ name: "John Doe" }]}
+ modelName="pinned"
+ total={1}
+ />,
+ { wrapper: ChakraWrapper },
+ );
+
+ expect(screen.getByRole("columnheader", { name: "Name"
})).toBeInTheDocument();
+ expect(screen.queryByRole("columnheader", { name: "Added" })).toBeNull();
+ });
});
diff --git a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
index 83151985ebd..e7783f11a3f 100644
--- a/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DataTable/DataTable.tsx
@@ -108,6 +108,21 @@ type DataTableProps<TData extends RowData> = {
readonly totalEntriesLimit?: number;
};
+// Columns with hiding disabled are left out of the columns menu, so a hidden
state stored for them
+// (e.g. saved before hiding was disabled) could never be undone. Such columns
always show.
+const buildColumnVisibility = <TData extends RowData>(
+ columns: Array<MetaColumn<TData>>,
+ visibility: ColumnVisibilityState,
+): ColumnVisibilityState => {
+ const unhideableIds = new Set(
+ columns
+ .filter((column) => column.enableHiding === false)
+ .map((column) => column.id ?? ("accessorKey" in column ?
String(column.accessorKey) : undefined)),
+ );
+
+ return Object.fromEntries(Object.entries(visibility).filter(([id]) =>
!unhideableIds.has(id)));
+};
+
export const DataTable = <TData extends RowData>({
cardDef,
columns,
@@ -187,7 +202,10 @@ export const DataTable = <TData extends RowData>({
);
// Stored visibility only covers columns that existed when it was saved, so
columns added
// later still need their default visibility.
- const columnVisibility = { ...initialState?.columnVisibility,
...storedColumnVisibility };
+ const columnVisibility = buildColumnVisibility(columns, {
+ ...initialState?.columnVisibility,
+ ...storedColumnVisibility,
+ });
// An absent total means the endpoint gives no count (e.g. cursor
pagination), which the heading
// reflects by naming the model without a number. Everything else still
needs a real number.
diff --git
a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
index bf4649d69d8..da27f134b42 100644
---
a/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
+++
b/airflow-core/src/airflow/ui/src/pages/Asset/AssetStateStore/AssetStateStore.tsx
@@ -133,6 +133,7 @@ const getColumns = ({
<DeleteAssetStateStoreButton assetId={assetId} storeKey={original.key}
/>
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
},
diff --git a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
index 6279938f574..3d0f199c575 100644
--- a/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Connections/Connections.tsx
@@ -128,6 +128,7 @@ const getColumns = ({
<DeleteConnectionButton connectionId={original.connection_id}
disabled={hasSelection} />
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
meta: {
diff --git a/airflow-core/src/airflow/ui/src/pages/DagRuns/DagRuns.tsx
b/airflow-core/src/airflow/ui/src/pages/DagRuns/DagRuns.tsx
index ccc190c8e23..a9cc7c59194 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagRuns/DagRuns.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagRuns/DagRuns.tsx
@@ -241,6 +241,7 @@ const runColumns = ({
<DeleteRunButton dagRun={row.original} />
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
meta: {
diff --git
a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.test.tsx
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.test.tsx
new file mode 100644
index 00000000000..a53c41d82cb
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.test.tsx
@@ -0,0 +1,31 @@
+/*!
+ * 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 { describe, expect, it } from "vitest";
+
+import { createColumns } from "./DagsListColumns";
+
+describe("createColumns", () => {
+ it("lets only columns with a header be hidden, so the columns menu has no
unnamed entries", () => {
+ const unnamedHideable = createColumns((key) => key, { multiTeam: true,
showRecentTasks: true })
+ .filter((column) => column.enableHiding !== false && column.header ===
"")
+ .map((column) => ("accessorKey" in column ? column.accessorKey :
column.id));
+
+ expect(unnamedHideable).toEqual([]);
+ });
+});
diff --git a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
index 74bc5577ccc..ebd40300c15 100644
--- a/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/DagsList/DagsListColumns.tsx
@@ -184,6 +184,7 @@ export const createColumns = (
{
accessorKey: "is_paused",
cell: PauseCell,
+ enableHiding: false,
enableSorting: false,
header: "",
meta: {
@@ -237,12 +238,14 @@ export const createColumns = (
{
accessorKey: "pending_actions",
cell: PendingActionsCell,
+ enableHiding: false,
enableSorting: false,
header: "",
},
{
accessorKey: "trigger",
cell: TriggerCell,
+ enableHiding: false,
enableSorting: false,
header: "",
},
@@ -256,6 +259,7 @@ export const createColumns = (
{
accessorKey: "delete",
cell: DeleteCell,
+ enableHiding: false,
enableSorting: false,
header: "",
},
diff --git
a/airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx
index 48e33005e3d..35d42da362e 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx
@@ -294,6 +294,7 @@ const taskInstanceColumns = ({
<DeleteTaskInstanceButton taskInstance={row.original} />
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
meta: {
diff --git
a/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
b/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
index e81e679ab85..3d84f4e7c5d 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskStateStore/TaskStateStore.tsx
@@ -105,6 +105,7 @@ const getColumns = ({
/>
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
},
diff --git a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
index 2dd6c20fac8..981bf7ddfe5 100644
--- a/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Variables/Variables.tsx
@@ -134,6 +134,7 @@ const getColumns = ({
<DeleteVariableButton deleteKey={original.key}
disabled={hasSelection} />
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
meta: {
diff --git a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
index ed5e1f2d5e9..bbf4eba432a 100644
--- a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
@@ -174,6 +174,7 @@ const getColumns = ({
<DeleteXComButton xcom={original} />
</Flex>
),
+ enableHiding: false,
enableSorting: false,
header: "",
},