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

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

commit 333736e464d7a6f9d6e89974d2352df8109ec4bc
Author: Guan Ming(Wesley) Chiu <[email protected]>
AuthorDate: Mon Apr 21 21:43:13 2025 +0800

    AIP-38: merge Backfill and Trigger Dag Run (#49490)
    
    (cherry picked from commit 6b6867d0d60494bc0588fe724afe1c58ee001828)
---
 .../components/DagActions/RunBackfillButton.tsx    |  45 ---------
 .../src/components/DagActions/RunBackfillForm.tsx  |   2 +-
 .../src/components/DagActions/RunBackfillModal.tsx |  47 ---------
 .../src/components/TriggerDag/TriggerDAGForm.tsx   |   4 +-
 .../src/components/TriggerDag/TriggerDAGModal.tsx  | 109 +++++++++++++++++----
 .../src/airflow/ui/src/pages/Dag/Header.tsx        |   2 -
 6 files changed, 93 insertions(+), 116 deletions(-)

diff --git 
a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillButton.tsx 
b/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillButton.tsx
deleted file mode 100644
index 90b43d106ec..00000000000
--- 
a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillButton.tsx
+++ /dev/null
@@ -1,45 +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 { useDisclosure } from "@chakra-ui/react";
-import { RiArrowGoBackFill } from "react-icons/ri";
-
-import type { DAGResponse, DAGWithLatestDagRunsResponse } from 
"openapi/requests/types.gen";
-
-import { Button } from "../ui";
-import RunBackfillModal from "./RunBackfillModal";
-
-type Props = {
-  readonly dag: DAGResponse | DAGWithLatestDagRunsResponse;
-};
-
-const RunBackfillButton: React.FC<Props> = ({ dag }) => {
-  const { onClose, onOpen, open } = useDisclosure();
-
-  return (
-    <>
-      <Button aria-label="Run Backfill" onClick={onOpen} variant="outline">
-        <RiArrowGoBackFill />
-        Run Backfill
-      </Button>
-      <RunBackfillModal dag={dag} onClose={onClose} open={open} />
-    </>
-  );
-};
-
-export default RunBackfillButton;
diff --git 
a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillForm.tsx 
b/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillForm.tsx
index 1bbacf6dced..112631563e3 100644
--- a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillForm.tsx
+++ b/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillForm.tsx
@@ -116,7 +116,7 @@ const RunBackfillForm = ({ dag, onClose }: 
RunBackfillFormProps) => {
 
   return (
     <>
-      <VStack alignItems="stretch" gap={2} p={10}>
+      <VStack alignItems="stretch" gap={2} pt={4}>
         <Box>
           <Text fontSize="md" fontWeight="medium" mb={1}>
             Date Range
diff --git 
a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillModal.tsx 
b/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillModal.tsx
deleted file mode 100644
index 8e48fd60268..00000000000
--- a/airflow-core/src/airflow/ui/src/components/DagActions/RunBackfillModal.tsx
+++ /dev/null
@@ -1,47 +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 { Heading } from "@chakra-ui/react";
-import React from "react";
-
-import type { DAGResponse, DAGWithLatestDagRunsResponse } from 
"openapi/requests/types.gen";
-import { Dialog } from "src/components/ui";
-
-import RunBackfillForm from "./RunBackfillForm";
-
-type RunBackfillModalProps = {
-  readonly dag: DAGResponse | DAGWithLatestDagRunsResponse;
-  readonly onClose: () => void;
-  readonly open: boolean;
-};
-
-const RunBackfillModal: React.FC<RunBackfillModalProps> = ({ dag, onClose, 
open }) => (
-  <Dialog.Root lazyMount onOpenChange={onClose} open={open} size="xl" 
unmountOnExit>
-    <Dialog.Content backdrop>
-      <Dialog.Header bg="blue.muted">
-        <Heading size="xl">Run Backfill</Heading>
-      </Dialog.Header>
-      <Dialog.CloseTrigger />
-      <Dialog.Body>
-        <RunBackfillForm dag={dag} onClose={onClose} />
-      </Dialog.Body>
-    </Dialog.Content>
-  </Dialog.Root>
-);
-
-export default RunBackfillModal;
diff --git 
a/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx 
b/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx
index 112d58175f8..c0f420dcf9d 100644
--- a/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx
+++ b/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGForm.tsx
@@ -121,7 +121,7 @@ const TriggerDAGForm = ({ dagId, isPaused, onClose, open }: 
TriggerDAGFormProps)
         collapsible
         defaultValue={[flexibleFormDefaultSection]}
         mb={4}
-        mt={4}
+        mt={8}
         size="lg"
         variant="enclosed"
       >
@@ -132,7 +132,7 @@ const TriggerDAGForm = ({ dagId, isPaused, onClose, open }: 
TriggerDAGFormProps)
         <Accordion.Item key="advancedOptions" value="advancedOptions">
           <Accordion.ItemTrigger cursor="button">Advanced 
Options</Accordion.ItemTrigger>
           <Accordion.ItemContent>
-            <Box p={5}>
+            <Box p={4}>
               <Controller
                 control={control}
                 name="logicalDate"
diff --git 
a/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGModal.tsx 
b/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGModal.tsx
index b762604410e..9d35fd95efa 100644
--- a/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGModal.tsx
+++ b/airflow-core/src/airflow/ui/src/components/TriggerDag/TriggerDAGModal.tsx
@@ -16,13 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Heading, VStack } from "@chakra-ui/react";
-import React from "react";
+import { Heading, VStack, HStack, Spinner, Center, Text } from 
"@chakra-ui/react";
+import React, { useState } from "react";
 
+import { useDagServiceGetDag } from "openapi/queries";
 import { Dialog } from "src/components/ui";
+import { RadioCardItem, RadioCardRoot } from "src/components/ui/RadioCard";
 
+import RunBackfillForm from "../DagActions/RunBackfillForm";
 import TriggerDAGForm from "./TriggerDAGForm";
 
+enum RunMode {
+  BACKFILL = "backfill",
+  SINGLE = "single",
+}
+
 type TriggerDAGModalProps = {
   readonly dagDisplayName: string;
   readonly dagId: string;
@@ -37,22 +45,85 @@ const TriggerDAGModal: React.FC<TriggerDAGModalProps> = ({
   isPaused,
   onClose,
   open,
-}) => (
-  <Dialog.Root lazyMount onOpenChange={onClose} open={open} size="xl" 
unmountOnExit>
-    <Dialog.Content backdrop>
-      <Dialog.Header paddingBottom={0}>
-        <VStack align="start" gap={4}>
-          <Heading size="xl">Trigger Dag - {dagDisplayName}</Heading>
-        </VStack>
-      </Dialog.Header>
-
-      <Dialog.CloseTrigger />
-
-      <Dialog.Body>
-        <TriggerDAGForm dagId={dagId} isPaused={isPaused} onClose={onClose} 
open={open} />
-      </Dialog.Body>
-    </Dialog.Content>
-  </Dialog.Root>
-);
+}) => {
+  const [runMode, setRunMode] = useState<RunMode>(RunMode.SINGLE);
+  const {
+    data: dag,
+    isError,
+    isLoading,
+  } = useDagServiceGetDag(
+    {
+      dagId,
+    },
+    undefined,
+    {
+      enabled: open,
+    },
+  );
+
+  const hasSchedule = dag?.timetable_summary !== null;
+
+  return (
+    <Dialog.Root lazyMount onOpenChange={onClose} open={open} size="xl" 
unmountOnExit>
+      <Dialog.Content backdrop>
+        <Dialog.Header paddingBottom={0}>
+          <VStack align="start" gap={2} width="100%">
+            <Heading size="xl">
+              {runMode === RunMode.SINGLE ? "Trigger DAG" : "Run Backfill"} - 
{dagDisplayName}
+            </Heading>
+          </VStack>
+        </Dialog.Header>
+
+        <Dialog.CloseTrigger />
+
+        <Dialog.Body>
+          {isLoading ? (
+            <Center py={6}>
+              <VStack>
+                <Spinner size="lg" />
+                <Text mt={2}>Loading DAG information...</Text>
+              </VStack>
+            </Center>
+          ) : isError ? (
+            <Center py={6}>
+              <Text color="red.500">Failed to load DAG information. Please try 
again.</Text>
+            </Center>
+          ) : (
+            <>
+              {dag && hasSchedule ? (
+                <RadioCardRoot
+                  my={4}
+                  onChange={(event) => {
+                    setRunMode((event.target as HTMLInputElement).value as 
RunMode);
+                  }}
+                  value={runMode}
+                >
+                  <HStack align="stretch">
+                    <RadioCardItem
+                      description="Trigger a single run of this DAG"
+                      label="Single Run"
+                      value={RunMode.SINGLE}
+                    />
+                    <RadioCardItem
+                      description="Run this DAG for a range of dates"
+                      label="Backfill"
+                      value={RunMode.BACKFILL}
+                    />
+                  </HStack>
+                </RadioCardRoot>
+              ) : undefined}
+
+              {runMode === RunMode.SINGLE ? (
+                <TriggerDAGForm dagId={dagId} isPaused={isPaused} 
onClose={onClose} open={open} />
+              ) : (
+                hasSchedule && dag && <RunBackfillForm dag={dag} 
onClose={onClose} />
+              )}
+            </>
+          )}
+        </Dialog.Body>
+      </Dialog.Content>
+    </Dialog.Root>
+  );
+};
 
 export default TriggerDAGModal;
diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx 
b/airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx
index 969894a4d38..94874dd8aea 100644
--- a/airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/Dag/Header.tsx
@@ -22,7 +22,6 @@ import { useParams } from "react-router-dom";
 import type { DAGDetailsResponse, DAGWithLatestDagRunsResponse } from 
"openapi/requests/types.gen";
 import { DagIcon } from "src/assets/DagIcon";
 import ParseDag from "src/components/DagActions/ParseDag";
-import RunBackfillButton from "src/components/DagActions/RunBackfillButton";
 import DagRunInfo from "src/components/DagRunInfo";
 import { DagVersion } from "src/components/DagVersion";
 import DisplayMarkdownButton from "src/components/DisplayMarkdownButton";
@@ -99,7 +98,6 @@ export const Header = ({
                 text="Dag Docs"
               />
             )}
-            {dag.timetable_summary === null ? undefined : <RunBackfillButton 
dag={dag} />}
             <ParseDag dagId={dag.dag_id} fileToken={dag.file_token} />
           </>
         )

Reply via email to