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} /> </> )
