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

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new e4177217f46 Feature/aip 38 add dag warning (#49236)
e4177217f46 is described below

commit e4177217f46cd70c89e5cc818405f2b5efbf5516
Author: Aritra Basu <[email protected]>
AuthorDate: Tue Apr 15 19:48:15 2025 +0530

    Feature/aip 38 add dag warning (#49236)
    
    * AIP-38 :: created new dag warning banner added to dag details page
    
    * AIP-38 :: replaced type with existing response type
    
    * AIP-38 :: updated key with timestamp to make unique
    
    * AIP-38 :: removed console log
    
    * AIP-38 :: adding warnings & errors to accordion
    
    * AIP-38 :: overflow scroll support for accordion
    
    * Updated warning to be in a modal
    
    * Updated margin
    
    * Updating heading of dialog and button name
    
    ---------
    
    Co-authored-by: Tyrell C <[email protected]>
---
 .../src/airflow/ui/src/components/WarningAlert.tsx | 39 ++++++++++++
 .../ui/src/components/ui/DagWarningsModal.tsx      | 70 ++++++++++++++++++++++
 .../ui/src/layouts/Details/DetailsLayout.tsx       | 36 +++++++++--
 3 files changed, 141 insertions(+), 4 deletions(-)

diff --git a/airflow-core/src/airflow/ui/src/components/WarningAlert.tsx 
b/airflow-core/src/airflow/ui/src/components/WarningAlert.tsx
new file mode 100644
index 00000000000..69cbe4e4186
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/components/WarningAlert.tsx
@@ -0,0 +1,39 @@
+/*!
+ * 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 { Flex } from "@chakra-ui/react";
+
+import { Alert } from "./ui";
+
+type Props = {
+  readonly warning?: {
+    message: string;
+  };
+};
+
+export const WarningAlert = ({ warning }: Props) => {
+  if (!Boolean(warning)) {
+    return undefined;
+  }
+
+  return (
+    <Alert status="warning">
+      <Flex align="center">{warning?.message}</Flex>
+    </Alert>
+  );
+};
diff --git a/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx 
b/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
new file mode 100644
index 00000000000..80ff7c63304
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/components/ui/DagWarningsModal.tsx
@@ -0,0 +1,70 @@
+/*!
+ * 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, HStack, Spacer, VStack } from "@chakra-ui/react";
+import { LuFileWarning } from "react-icons/lu";
+
+import type { DAGWarningResponse } from "openapi/requests/types.gen";
+import { Dialog } from "src/components/ui";
+import { pluralize } from "src/utils";
+
+import { ErrorAlert } from "../ErrorAlert";
+import { WarningAlert } from "../WarningAlert";
+
+type ImportDAGErrorModalProps = {
+  error?: unknown;
+  onClose: () => void;
+  open: boolean;
+  warnings?: Array<DAGWarningResponse>;
+};
+
+export const DAGWarningsModal: React.FC<ImportDAGErrorModalProps> = ({ error, 
onClose, open, warnings }) => (
+  <Dialog.Root onOpenChange={onClose} open={open} scrollBehavior="inside" 
size="xl">
+    <Dialog.Content backdrop>
+      <Dialog.Header>
+        <HStack fontSize="xl">
+          <LuFileWarning />
+          <Heading>
+            {Boolean(error) ? "1 Error" : ""}
+            {Boolean(error) && warnings?.length !== undefined && 
warnings.length > 0 ? " and " : ""}
+            {warnings?.length !== undefined && warnings.length > 0
+              ? pluralize("Warning", warnings.length)
+              : ""}
+          </Heading>
+        </HStack>
+      </Dialog.Header>
+
+      <Dialog.CloseTrigger />
+
+      <Dialog.Body>
+        {Boolean(error) && (
+          <VStack>
+            <ErrorAlert error={error} />
+            <Spacer />
+          </VStack>
+        )}
+        {warnings?.map((warning) => (
+          <VStack key={warning.message}>
+            <WarningAlert warning={warning} />
+            <Spacer />
+          </VStack>
+        ))}
+      </Dialog.Body>
+    </Dialog.Content>
+  </Dialog.Root>
+);
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx 
b/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
index 560c78be7d1..69d32034fc4 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/DetailsLayout.tsx
@@ -16,21 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { Box, HStack, Flex } from "@chakra-ui/react";
+import { Box, HStack, Flex, useDisclosure } from "@chakra-ui/react";
 import { useReactFlow } from "@xyflow/react";
 import type { PropsWithChildren, ReactNode } from "react";
+import { LuFileWarning } from "react-icons/lu";
 import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
 import { Outlet, useParams } from "react-router-dom";
 import { useLocalStorage } from "usehooks-ts";
 
-import { useDagServiceGetDag } from "openapi/queries";
+import { useDagServiceGetDag, useDagWarningServiceListDagWarnings } from 
"openapi/queries";
 import type { DAGResponse } from "openapi/requests/types.gen";
 import BackfillBanner from "src/components/Banner/BackfillBanner";
-import { ErrorAlert } from "src/components/ErrorAlert";
 import { SearchDagsButton } from "src/components/SearchDags";
 import TriggerDAGButton from "src/components/TriggerDag/TriggerDAGButton";
 import { ProgressBar } from "src/components/ui";
 import { Toaster } from "src/components/ui";
+import ActionButton from "src/components/ui/ActionButton";
+import { DAGWarningsModal } from "src/components/ui/DagWarningsModal";
 import { OpenGroupsProvider } from "src/context/openGroups";
 
 import { DagBreadcrumb } from "./DagBreadcrumb";
@@ -56,6 +58,11 @@ export const DetailsLayout = ({ children, error, isLoading, 
tabs }: Props) => {
 
   const { fitView, getZoom } = useReactFlow();
 
+  const { data: warningData } = useDagWarningServiceListDagWarnings({
+    dagId,
+  });
+  const { onClose, onOpen, open } = useDisclosure();
+
   return (
     <OpenGroupsProvider dagId={dagId}>
       <HStack justifyContent="space-between" mb={2}>
@@ -90,7 +97,28 @@ export const DetailsLayout = ({ children, error, isLoading, 
tabs }: Props) => {
           <Panel defaultSize={dagView === "graph" ? 30 : 80} minSize={20}>
             <Box display="flex" flexDirection="column" h="100%">
               {children}
-              <ErrorAlert error={error} />
+              {Boolean(error) || (warningData?.dag_warnings.length ?? 0) > 0 ? 
(
+                <>
+                  <ActionButton
+                    actionName="Dag warnings/errors"
+                    colorPalette={Boolean(error) ? "red" : "orange"}
+                    icon={<LuFileWarning />}
+                    margin="2"
+                    marginBottom="-1"
+                    onClick={onOpen}
+                    rounded="full"
+                    text={String(warningData?.total_entries ?? 0 + 
Number(error))}
+                    variant="solid"
+                  />
+
+                  <DAGWarningsModal
+                    error={error}
+                    onClose={onClose}
+                    open={open}
+                    warnings={warningData?.dag_warnings}
+                  />
+                </>
+              ) : undefined}
               <ProgressBar size="xs" visibility={isLoading ? "visible" : 
"hidden"} />
               <NavTabs tabs={tabs} />
               <Box h="100%" overflow="auto" px={2}>

Reply via email to