From d6a3525744e276453f30977fddde6d35d57cf123 Mon Sep 17 00:00:00 2001 From: Ryan Hamilton Date: Tue, 18 Aug 2026 14:58:53 -0400 Subject: [PATCH] UI: Make dialogs consistent and fix their dark mode background Dialog scaffolding was hand-assembled in around fifty places and had drifted apart: close triggers, mount flags, heading sizes and the placement of action buttons all varied, so a dialog's chrome depended on which screen happened to open it. Keeping any of that consistent relied on each author copying the surrounding code correctly, and several dialogs had already diverged. In dark mode Chakra's default panel background resolves much darker than the page background, leaving dialogs looking detached from the app behind them. Light mode resolves both to white, so the discrepancy was easy to miss and had gone unnoticed. Giving the scaffolding a single definition means the chrome is consistent by construction rather than by convention, and puts theming in one place that applies to every dialog at once. --- .../components/Clear/Run/ClearRunDialog.tsx | 151 ++++++------- .../ClearGroupTaskInstanceDialog.tsx | 179 +++++++-------- .../TaskInstance/ClearTaskInstanceDialog.tsx | 192 ++++++++-------- .../ui/src/components/ConfirmationModal.tsx | 53 ++--- .../ui/src/components/DAGWarningsModal.tsx | 52 ++--- .../ui/src/components/DeleteDialog.tsx | 57 +++-- .../src/components/DisplayMarkdownButton.tsx | 12 +- .../components/HITLReview/HITLReviewModal.tsx | 100 +++++---- .../KeyboardShortcutsModal.tsx | 74 +++---- .../components/MarkAs/Run/MarkRunAsDialog.tsx | 67 +++--- .../TaskGroup/MarkTaskGroupAsDialog.tsx | 139 ++++++------ .../TaskInstance/MarkTaskInstanceAsDialog.tsx | 142 ++++++------ .../ui/src/components/MarkdownModal.tsx | 12 +- .../components/TriggerDag/TriggerDAGModal.tsx | 148 ++++++------- .../src/components/ui/Dialog/CloseTrigger.tsx | 14 +- .../ui/src/components/ui/Modal/Modal.test.tsx | 183 ++++++++++++++++ .../ui/src/components/ui/Modal/Modal.tsx | 107 +++++++++ .../ui/src/components/ui/Modal/index.ts | 19 ++ .../src/airflow/ui/src/components/ui/index.ts | 29 +-- .../ui/src/layouts/Nav/LanguageModal.tsx | 14 +- .../ui/src/layouts/Nav/TimezoneModal.tsx | 14 +- .../src/layouts/Nav/TokenGenerationModal.tsx | 96 ++++---- .../AssetStateStore/AssetStateStoreModal.tsx | 87 ++++---- .../Asset/CreateAssetEventModal.test.tsx | 32 +-- .../src/pages/Asset/CreateAssetEventModal.tsx | 160 +++++++------- .../pages/Connections/AddConnectionButton.tsx | 32 +-- .../Connections/DeleteConnectionButton.tsx | 70 +++--- .../Connections/DeleteConnectionsButton.tsx | 70 +++--- .../Connections/EditConnectionButton.tsx | 38 ++-- .../Dag/Backfills/BackfillDagRunsModal.tsx | 47 ++-- .../airflow/ui/src/pages/Dag/Code/Code.tsx | 40 ++-- .../ui/src/pages/Dag/DagImportErrorModal.tsx | 68 +++--- .../pages/Dag/Overview/AllDeadlinesModal.tsx | 85 +++---- .../pages/DagRuns/BulkClearDagRunsButton.tsx | 94 ++++---- .../pages/DagRuns/BulkDeleteDagRunsButton.tsx | 158 +++++++------ .../pages/DagRuns/BulkMarkDagRunsAsButton.tsx | 87 ++++---- .../DagsList/PartitionScheduleModal.test.tsx | 48 ++-- .../pages/DagsList/PartitionScheduleModal.tsx | 51 +++-- .../Dashboard/Stats/DagImportErrorsModal.tsx | 142 ++++++------ .../Stats/PluginImportErrorsModal.tsx | 128 +++++------ .../ui/src/pages/Pools/AddPoolButton.tsx | 32 +-- .../ui/src/pages/Pools/EditPoolButton.tsx | 32 +-- .../ui/src/pages/Run/DeadlineStatusModal.tsx | 200 ++++++++--------- .../ui/src/pages/TaskInstance/Logs/Logs.tsx | 42 ++-- .../BulkClearTaskInstancesButton.tsx | 147 ++++++------- .../BulkDeleteTaskInstancesButton.tsx | 161 +++++++------- .../BulkMarkTaskInstancesAsButton.tsx | 153 +++++++------ .../TaskStateStore/TaskStateStoreModal.tsx | 207 +++++++++--------- .../pages/Variables/DeleteVariablesButton.tsx | 91 ++++---- .../pages/Variables/ImportVariablesButton.tsx | 22 +- .../ManageVariable/AddVariableButton.tsx | 32 +-- .../ManageVariable/DeleteVariableButton.tsx | 70 +++--- .../ManageVariable/EditVariableButton.tsx | 32 +-- .../airflow/ui/src/pages/XCom/XComModal.tsx | 79 ++++--- airflow-core/src/airflow/ui/src/theme.ts | 32 ++- .../src/airflow/ui/src/utils/TrimText.tsx | 88 ++++---- 56 files changed, 2392 insertions(+), 2319 deletions(-) create mode 100644 airflow-core/src/airflow/ui/src/components/ui/Modal/Modal.test.tsx create mode 100644 airflow-core/src/airflow/ui/src/components/ui/Modal/Modal.tsx create mode 100644 airflow-core/src/airflow/ui/src/components/ui/Modal/index.ts diff --git a/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx b/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx index 7be08d27af4bf..9f680efe65f4d 100644 --- a/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx +++ b/airflow-core/src/airflow/ui/src/components/Clear/Run/ClearRunDialog.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Button, Flex, Heading, VStack } from "@chakra-ui/react"; +import { Button, Flex } from "@chakra-ui/react"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { CgRedo } from "react-icons/cg"; @@ -26,7 +26,7 @@ import type { DAGRunResponse } from "openapi/requests/types.gen"; import { ActionAccordion } from "src/components/ActionAccordion"; import { getRunOnLatestVersionState } from "src/components/Clear/TaskInstance/runOnLatestVersion"; import { useRerunWithLatestVersion } from "src/components/Clear/useRerunWithLatestVersion"; -import { Checkbox, Dialog } from "src/components/ui"; +import { Checkbox, Modal } from "src/components/ui"; import SegmentedControl from "src/components/ui/SegmentedControl"; import { useClearRunDefaultOptions } from "src/hooks/useUserSettings"; import { useClearDagRunDryRun } from "src/queries/useClearDagRunDryRun"; @@ -108,7 +108,44 @@ const ClearRunDialog = ({ dagRun, onClose, open }: Props) => { const shouldShowBundleVersionOption = shouldShowRunOnLatestOption && !onlyNew; return ( - + + {shouldShowBundleVersionOption ? ( + setRunOnLatestVersion(Boolean(event.checked))} + title={ + runOnLatestVersionForced + ? translate("dags:runAndTaskActions.options.runOnLatestVersionForced") + : undefined + } + > + {translate("dags:runAndTaskActions.options.runOnLatestVersion")} + + ) : undefined} + + } lazyMount onOpenChange={(details) => { if (!details.open) { @@ -116,85 +153,37 @@ const ClearRunDialog = ({ dagRun, onClose, open }: Props) => { } }} open={open} + title={ + <> + + {translate("dags:runAndTaskActions.clear.title", { type: translate("dagRun_one") })}:{" "} + {" "} + {dagRunId} + + } > - - - - - - {translate("dags:runAndTaskActions.clear.title", { type: translate("dagRun_one") })}:{" "} - {" "} - {dagRunId} - - - - - - - - - - - - - {shouldShowBundleVersionOption ? ( - setRunOnLatestVersion(Boolean(event.checked))} - title={ - runOnLatestVersionForced - ? translate("dags:runAndTaskActions.options.runOnLatestVersionForced") - : undefined - } - > - {translate("dags:runAndTaskActions.options.runOnLatestVersion")} - - ) : undefined} - - - - - + + + + + ); }; diff --git a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearGroupTaskInstanceDialog.tsx b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearGroupTaskInstanceDialog.tsx index aec9bd55c6656..55f97b5d11718 100644 --- a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearGroupTaskInstanceDialog.tsx +++ b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearGroupTaskInstanceDialog.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Button, Flex, Heading, VStack } from "@chakra-ui/react"; +import { Button, Flex } from "@chakra-ui/react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { CgRedo } from "react-icons/cg"; @@ -30,7 +30,7 @@ import { import type { LightGridTaskInstanceSummary, TaskInstanceResponse } from "openapi/requests/types.gen"; import { ActionAccordion } from "src/components/ActionAccordion"; import { useRerunWithLatestVersion } from "src/components/Clear/useRerunWithLatestVersion"; -import { Checkbox, Dialog } from "src/components/ui"; +import { Checkbox, Modal } from "src/components/ui"; import SegmentedControl from "src/components/ui/SegmentedControl"; import { useClearTaskInstanceDefaultOptions } from "src/hooks/useUserSettings"; import { useClearTaskInstances } from "src/queries/useClearTaskInstances"; @@ -135,101 +135,90 @@ export const ClearGroupTaskInstanceDialog = ({ onClose, open, taskInstance }: Pr }; return ( - - - - - - - {translate("dags:runAndTaskActions.clear.title", { - type: translate("taskInstance", { count: affectedTasks.total_entries ?? 0 }), - })} - : - {" "} - {groupId} - - - - - - - - - + + {shouldShowRunOnLatestOption ? ( + setRunOnLatestVersion(Boolean(event.checked))} + title={ + runOnLatestVersionForced + ? translate("dags:runAndTaskActions.options.runOnLatestVersionForced") + : undefined + } > - {translate("modal.confirm")} - - - - - + {translate("dags:runAndTaskActions.options.runOnLatestVersion")} + + ) : undefined} + + } + lazyMount + onOpenChange={onClose} + open={open} + title={ + <> + {translate("dags:runAndTaskActions.clear.title", { + type: translate("taskInstance", { count: affectedTasks.total_entries ?? 0 }), + })} + : {groupId} + + } + > + + + + + ); }; diff --git a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx index 074e3f2d40ae4..feeeb98e7483d 100644 --- a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx +++ b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import { Button, Flex, Heading, useDisclosure, VStack } from "@chakra-ui/react"; +import { Button, Flex, useDisclosure } from "@chakra-ui/react"; import { useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { CgRedo } from "react-icons/cg"; @@ -27,7 +27,7 @@ import { ActionAccordion } from "src/components/ActionAccordion"; import { taskInstanceKey } from "src/components/ActionAccordion/columns"; import { useRerunWithLatestVersion } from "src/components/Clear/useRerunWithLatestVersion"; import Time from "src/components/Time"; -import { Checkbox, Dialog } from "src/components/ui"; +import { Checkbox, Modal } from "src/components/ui"; import SegmentedControl from "src/components/ui/SegmentedControl"; import { useClearPreventRunningTaskDefault, @@ -198,108 +198,100 @@ const ClearTaskInstanceDialog = (props: Props) => { return ( <> - - - - - - - {allMapped - ? translate("dags:runAndTaskActions.clearAllMapped.title") - : translate("dags:runAndTaskActions.clear.title", { - type: translate("taskInstance_one"), - })} - : - {" "} - {allMapped ? ( - taskId - ) : ( - <> - {taskInstance?.task_display_name} - - - - - - - - - - - + + setPreventRunningTask(Boolean(event.checked))} + style={{ marginRight: "auto" }} > - {shouldShowRunOnLatestOption ? ( - setRunOnLatestVersion(Boolean(event.checked))} - title={ - runOnLatestVersionForced - ? translate("dags:runAndTaskActions.options.runOnLatestVersionForced") - : undefined - } - > - {translate("dags:runAndTaskActions.options.runOnLatestVersion")} - - ) : undefined} + {translate("dags:runAndTaskActions.options.preventRunningTasks")} + + {shouldShowRunOnLatestOption ? ( setPreventRunningTask(Boolean(event.checked))} - style={{ marginRight: "auto" }} + checked={runOnLatestVersionForced || runOnLatestVersion} + disabled={runOnLatestVersionForced} + onCheckedChange={(event) => setRunOnLatestVersion(Boolean(event.checked))} + title={ + runOnLatestVersionForced + ? translate("dags:runAndTaskActions.options.runOnLatestVersionForced") + : undefined + } > - {translate("dags:runAndTaskActions.options.preventRunningTasks")} + {translate("dags:runAndTaskActions.options.runOnLatestVersion")} - - - - - + ) : undefined} + + } + lazyMount + onOpenChange={onCloseDialog} + open={openDialog ? !open : false} + title={ + <> + + {allMapped + ? translate("dags:runAndTaskActions.clearAllMapped.title") + : translate("dags:runAndTaskActions.clear.title", { + type: translate("taskInstance_one"), + })} + : + {" "} + {allMapped ? ( + taskId + ) : ( + <> + {taskInstance?.task_display_name}