This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit 03d75acd4a561cfc8cf4832dec263a5ef07d20f1
Author: Shahar Epstein <[email protected]>
AuthorDate: Sat Sep 13 11:29:06 2025 +0300

    Fix alignment of arrows in RTL mode (#55619)
    
    (cherry picked from commit 7d02b8528892533550d35e0e367f6101c81d9292)
---
 .../src/airflow/ui/src/components/NeedsReviewButton.tsx  |  5 ++++-
 airflow-core/src/airflow/ui/src/components/StatsCard.tsx |  6 ++++--
 .../airflow/ui/src/layouts/Nav/UserSettingsButton.tsx    | 16 +++++++++++++---
 .../ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx     |  5 ++++-
 .../src/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx   |  8 +++++++-
 5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/airflow-core/src/airflow/ui/src/components/NeedsReviewButton.tsx 
b/airflow-core/src/airflow/ui/src/components/NeedsReviewButton.tsx
index 646bca0bca6..78b246f3e36 100644
--- a/airflow-core/src/airflow/ui/src/components/NeedsReviewButton.tsx
+++ b/airflow-core/src/airflow/ui/src/components/NeedsReviewButton.tsx
@@ -41,7 +41,9 @@ export const NeedsReviewButton = ({
   });
 
   const hitlTIsCount = hitlStatsData?.hitl_details.length ?? 0;
-  const { t: translate } = useTranslation("hitl");
+  const { i18n, t: translate } = useTranslation("hitl");
+
+  const isRTL = i18n.dir() === "rtl";
 
   return hitlTIsCount > 0 ? (
     <Box maxW="250px">
@@ -50,6 +52,7 @@ export const NeedsReviewButton = ({
         count={hitlTIsCount}
         icon={<LuUserRoundPen />}
         isLoading={isLoading}
+        isRTL={isRTL}
         label={translate("requiredAction_other")}
         link="required_actions?response_received=false"
       />
diff --git a/airflow-core/src/airflow/ui/src/components/StatsCard.tsx 
b/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
index 7d7bf9c14b4..cbade7d249d 100644
--- a/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
+++ b/airflow-core/src/airflow/ui/src/components/StatsCard.tsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { Box, HStack, Skeleton, Text } from "@chakra-ui/react";
-import { FiChevronRight } from "react-icons/fi";
+import { FiChevronRight, FiChevronLeft } from "react-icons/fi";
 import { Link as RouterLink } from "react-router-dom";
 
 import type { TaskInstanceState } from "openapi/requests/types.gen";
@@ -28,6 +28,7 @@ export const StatsCard = ({
   count,
   icon,
   isLoading = false,
+  isRTL,
   label,
   link,
   onClick,
@@ -37,6 +38,7 @@ export const StatsCard = ({
   readonly count: number;
   readonly icon?: React.ReactNode;
   readonly isLoading?: boolean;
+  readonly isRTL: boolean;
   readonly label: string;
   readonly link?: string;
   readonly onClick?: () => void;
@@ -63,7 +65,7 @@ export const StatsCard = ({
       <Text color="fg" fontSize="sm" fontWeight="bold">
         {label}
       </Text>
-      <FiChevronRight size={16} />
+      {isRTL ? <FiChevronLeft size={16} /> : <FiChevronRight size={16} />}
     </HStack>
   );
 
diff --git a/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx 
b/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx
index a2b99016d91..c8cc8108945 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Nav/UserSettingsButton.tsx
@@ -27,6 +27,7 @@ import {
   FiGlobe,
   FiEye,
   FiChevronRight,
+  FiChevronLeft,
   FiMonitor,
 } from "react-icons/fi";
 import { MdOutlineAccountTree } from "react-icons/md";
@@ -52,7 +53,7 @@ const COLOR_MODES = {
 type ColorMode = (typeof COLOR_MODES)[keyof typeof COLOR_MODES];
 
 export const UserSettingsButton = ({ externalViews }: { readonly 
externalViews: Array<NavItemResponse> }) => {
-  const { t: translate } = useTranslation();
+  const { i18n, t: translate } = useTranslation();
   const { selectedTheme, setColorMode } = useColorMode();
   const { onClose: onCloseTimezone, onOpen: onOpenTimezone, open: 
isOpenTimezone } = useDisclosure();
   const { onClose: onCloseLogout, onOpen: onOpenLogout, open: isOpenLogout } = 
useDisclosure();
@@ -61,6 +62,8 @@ export const UserSettingsButton = ({ externalViews }: { 
readonly externalViews:
 
   const theme = selectedTheme ?? COLOR_MODES.SYSTEM;
 
+  const isRTL = i18n.dir() === "rtl";
+
   return (
     <Menu.Root positioning={{ placement: "right" }}>
       <Menu.Trigger asChild>
@@ -75,7 +78,11 @@ export const UserSettingsButton = ({ externalViews }: { 
readonly externalViews:
           <Menu.TriggerItem>
             <FiEye size="1.25rem" style={{ marginRight: "8px" }} />
             {translate("appearance.appearance")}
-            <FiChevronRight size="1.25rem" style={{ marginLeft: "auto" }} />
+            {isRTL ? (
+              <FiChevronLeft size="1.25rem" style={{ marginRight: "auto" }} />
+            ) : (
+              <FiChevronRight size="1.25rem" style={{ marginLeft: "auto" }} />
+            )}
           </Menu.TriggerItem>
           <Menu.Content>
             <Menu.RadioItemGroup
@@ -121,7 +128,10 @@ export const UserSettingsButton = ({ externalViews }: { 
readonly externalViews:
           <PluginMenuItem {...view} key={view.name} />
         ))}
         <Menu.Item onClick={onOpenLogout} value="logout">
-          <FiLogOut size="1.25rem" style={{ marginRight: "8px" }} />
+          <FiLogOut
+            size="1.25rem"
+            style={{ marginRight: "8px", transform: isRTL ? "rotate(180deg)" : 
undefined }}
+          />
           {translate("logout")}
         </Menu.Item>
       </Menu.Content>
diff --git 
a/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx
index 079472cf353..2966fee23cd 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx
@@ -29,7 +29,9 @@ import { DAGImportErrorsModal } from "./DAGImportErrorsModal";
 
 export const DAGImportErrors = ({ iconOnly = false }: { readonly iconOnly?: 
boolean }) => {
   const { onClose, onOpen, open } = useDisclosure();
-  const { t: translate } = useTranslation("dashboard");
+  const { i18n, t: translate } = useTranslation("dashboard");
+
+  const isRTL = i18n.dir() === "rtl";
 
   const { data, error, isLoading } = useImportErrorServiceGetImportErrors();
   const importErrorsCount = data?.total_entries ?? 0;
@@ -63,6 +65,7 @@ export const DAGImportErrors = ({ iconOnly = false }: { 
readonly iconOnly?: bool
           count={importErrorsCount}
           icon={<LuFileWarning />}
           isLoading={isLoading}
+          isRTL={isRTL}
           label={translate("importErrors.dagImportError", { count: 
importErrorsCount })}
           onClick={onOpen}
         />
diff --git a/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx
index b766cd12b4f..5cfc7b2d7c2 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx
@@ -38,7 +38,9 @@ export const Stats = () => {
   const queuedDagsCount = statsData?.queued_dag_count ?? 0;
   const runningDagsCount = statsData?.running_dag_count ?? 0;
   const activeDagsCount = statsData?.active_dag_count ?? 0;
-  const { t: translate } = useTranslation("dashboard");
+  const { i18n, t: translate } = useTranslation("dashboard");
+
+  const isRTL = i18n.dir() === "rtl";
 
   return (
     <Box>
@@ -56,6 +58,7 @@ export const Stats = () => {
           colorScheme="failed"
           count={failedDagsCount}
           isLoading={isStatsLoading}
+          isRTL={isRTL}
           label={translate("stats.failedDags")}
           link="dags?last_dag_run_state=failed"
           state="failed"
@@ -70,6 +73,7 @@ export const Stats = () => {
             colorScheme="queued"
             count={queuedDagsCount}
             isLoading={isStatsLoading}
+            isRTL={isRTL}
             label={translate("stats.queuedDags")}
             link="dags?last_dag_run_state=queued"
             state="queued"
@@ -80,6 +84,7 @@ export const Stats = () => {
           colorScheme="running"
           count={runningDagsCount}
           isLoading={isStatsLoading}
+          isRTL={isRTL}
           label={translate("stats.runningDags")}
           link="dags?last_dag_run_state=running"
           state="running"
@@ -90,6 +95,7 @@ export const Stats = () => {
           count={activeDagsCount}
           icon={<FiZap />}
           isLoading={isStatsLoading}
+          isRTL={isRTL}
           label={translate("stats.activeDags")}
           link="dags?paused=false"
         />

Reply via email to