diff --git a/airflow-core/src/airflow/ui/src/components/ExpandCollapseButtons.tsx b/airflow-core/src/airflow/ui/src/components/ExpandCollapseButtons.tsx
new file mode 100644
index 0000000000000..fac305a7624a0
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/components/ExpandCollapseButtons.tsx
@@ -0,0 +1,60 @@
+/*!
+ * 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 { ButtonGroup, IconButton } from "@chakra-ui/react";
+import { MdCompress, MdExpand } from "react-icons/md";
+
+type Props = {
+ readonly collapseLabel: string;
+ readonly expandLabel: string;
+ readonly isCollapseDisabled?: boolean;
+ readonly isExpandDisabled?: boolean;
+ readonly onCollapse: () => void;
+ readonly onExpand: () => void;
+};
+
+export const ExpandCollapseButtons = ({
+ collapseLabel,
+ expandLabel,
+ isCollapseDisabled,
+ isExpandDisabled,
+ onCollapse,
+ onExpand,
+ ...rest
+}: Props) => (
+
+
+
+
+
+
+
+
+);
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/ToggleGroups.tsx b/airflow-core/src/airflow/ui/src/layouts/Details/ToggleGroups.tsx
index c55446c1c56be..8abaa3cca3e90 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/ToggleGroups.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/ToggleGroups.tsx
@@ -16,10 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { type ButtonGroupProps, IconButton, ButtonGroup } from "@chakra-ui/react";
+import type { ButtonGroupProps } from "@chakra-ui/react";
import { useTranslation } from "react-i18next";
-import { MdExpand, MdCompress } from "react-icons/md";
+import { ExpandCollapseButtons } from "src/components/ExpandCollapseButtons";
import { useOpenGroups } from "src/context/openGroups";
export const ToggleGroups = (props: ButtonGroupProps) => {
@@ -46,25 +46,14 @@ export const ToggleGroups = (props: ButtonGroupProps) => {
const collapseLabel = translate("dag:taskGroups.collapseAll");
return (
-
-
-
-
-
-
-
-
+
);
};
diff --git a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
index ca19dd3653447..2a3bbefbb3a74 100644
--- a/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Events/Events.tsx
@@ -16,11 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ButtonGroup, Code, Flex, Heading, IconButton, useDisclosure, VStack } from "@chakra-ui/react";
+import { Code, Flex, Heading, useDisclosure, VStack } from "@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import dayjs from "dayjs";
import { useTranslation } from "react-i18next";
-import { MdCompress, MdExpand } from "react-icons/md";
import { useParams, useSearchParams } from "react-router-dom";
import { useEventLogServiceGetEventLogs } from "openapi/queries";
@@ -28,6 +27,7 @@ import type { EventLogResponse } from "openapi/requests/types.gen";
import { DataTable } from "src/components/DataTable";
import { useTableURLState } from "src/components/DataTable/useTableUrlState";
import { ErrorAlert } from "src/components/ErrorAlert";
+import { ExpandCollapseButtons } from "src/components/ExpandCollapseButtons";
import RenderedJsonField from "src/components/RenderedJsonField";
import Time from "src/components/Time";
import { SearchParamsKeys, type SearchParamsKeysType } from "src/constants/searchParams";
@@ -214,24 +214,12 @@ export const Events = () => {
) : undefined}
-
-
-
-
-
-
-
-
+
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 68f3fa7f4df36..0e66988437693 100644
--- a/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/XCom/XCom.tsx
@@ -16,10 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Box, Heading, Link, Flex, ButtonGroup, IconButton, useDisclosure } from "@chakra-ui/react";
+import { Box, Heading, Link, Flex, useDisclosure } from "@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import { useTranslation } from "react-i18next";
-import { MdCompress, MdExpand } from "react-icons/md";
import { Link as RouterLink, useParams, useSearchParams } from "react-router-dom";
import { useXcomServiceGetXcomEntries } from "openapi/queries";
@@ -27,6 +26,7 @@ import type { XComResponse } from "openapi/requests/types.gen";
import { DataTable } from "src/components/DataTable";
import { useTableURLState } from "src/components/DataTable/useTableUrlState";
import { ErrorAlert } from "src/components/ErrorAlert";
+import { ExpandCollapseButtons } from "src/components/ExpandCollapseButtons";
import { TruncatedText } from "src/components/TruncatedText";
import { SearchParamsKeys, type SearchParamsKeysType } from "src/constants/searchParams";
import { getTaskInstanceLink } from "src/utils/links";
@@ -162,22 +162,12 @@ export const XCom = () => {
-
-
-
-
-
-
-
-
+