diff --git a/airflow/ui/src/pages/DagsList/DagCard.tsx b/airflow/ui/src/pages/DagsList/DagCard.tsx index a2c67b4eb8c4f..13f15735991a9 100644 --- a/airflow/ui/src/pages/DagsList/DagCard.tsx +++ b/airflow/ui/src/pages/DagsList/DagCard.tsx @@ -79,13 +79,13 @@ export const DagCard = ({ dag }: Props) => { - + Schedule - + Latest Run {latestRun ? ( @@ -99,7 +99,7 @@ export const DagCard = ({ dag }: Props) => { ) : undefined} - + Next Run {Boolean(dag.next_dagrun) ? ( diff --git a/airflow/ui/src/pages/Dashboard/Dashboard.tsx b/airflow/ui/src/pages/Dashboard/Dashboard.tsx index 38727b0809e33..39131f1969ca6 100644 --- a/airflow/ui/src/pages/Dashboard/Dashboard.tsx +++ b/airflow/ui/src/pages/Dashboard/Dashboard.tsx @@ -20,6 +20,7 @@ import { Box, Heading } from "@chakra-ui/react"; import { Health } from "./Health"; import { HistoricalMetrics } from "./HistoricalMetrics"; +import { Stats } from "./Stats"; export const Dashboard = () => ( @@ -27,6 +28,9 @@ export const Dashboard = () => ( + + + diff --git a/airflow/ui/src/pages/Dashboard/Health.tsx b/airflow/ui/src/pages/Dashboard/Health/Health.tsx similarity index 94% rename from airflow/ui/src/pages/Dashboard/Health.tsx rename to airflow/ui/src/pages/Dashboard/Health/Health.tsx index d105b7035a832..6697d6e7d0d56 100644 --- a/airflow/ui/src/pages/Dashboard/Health.tsx +++ b/airflow/ui/src/pages/Dashboard/Health/Health.tsx @@ -17,7 +17,7 @@ * under the License. */ import { Box, Flex, Heading, HStack } from "@chakra-ui/react"; -import { FiClipboard } from "react-icons/fi"; +import { MdOutlineHealthAndSafety } from "react-icons/md"; import { useMonitorServiceGetHealth } from "openapi/queries"; import { ErrorAlert } from "src/components/ErrorAlert"; @@ -29,8 +29,8 @@ export const Health = () => { return ( - - + + Health diff --git a/airflow/ui/src/pages/Dashboard/HealthSection.tsx b/airflow/ui/src/pages/Dashboard/Health/HealthSection.tsx similarity index 100% rename from airflow/ui/src/pages/Dashboard/HealthSection.tsx rename to airflow/ui/src/pages/Dashboard/Health/HealthSection.tsx diff --git a/airflow/ui/src/pages/Dashboard/HealthTag.tsx b/airflow/ui/src/pages/Dashboard/Health/HealthTag.tsx similarity index 100% rename from airflow/ui/src/pages/Dashboard/HealthTag.tsx rename to airflow/ui/src/pages/Dashboard/Health/HealthTag.tsx diff --git a/airflow/ui/src/pages/Dashboard/Health/index.ts b/airflow/ui/src/pages/Dashboard/Health/index.ts new file mode 100644 index 0000000000000..e738024b04700 --- /dev/null +++ b/airflow/ui/src/pages/Dashboard/Health/index.ts @@ -0,0 +1,20 @@ +/*! + * 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. + */ + +export { Health } from "./Health"; diff --git a/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx b/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx new file mode 100644 index 0000000000000..3d62b08d3c6bc --- /dev/null +++ b/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrors.tsx @@ -0,0 +1,78 @@ +/*! + * 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 { + Box, + Badge, + Text, + Button, + useDisclosure, + Skeleton, +} from "@chakra-ui/react"; +import { FiChevronRight } from "react-icons/fi"; + +import { useImportErrorServiceGetImportErrors } from "openapi/queries"; +import { ErrorAlert } from "src/components/ErrorAlert"; + +import { DAGImportErrorsModal } from "./DAGImportErrorsModal"; + +export const DAGImportErrors = () => { + const { onClose, onOpen, open } = useDisclosure(); + + const { data, error, isLoading } = useImportErrorServiceGetImportErrors(); + const importErrorsCount = data?.total_entries ?? 0; + const importErrors = data?.import_errors ?? []; + + if (isLoading) { + return ; + } + + return ( + + + {importErrorsCount > 0 && ( + + )} + + + ); +}; diff --git a/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrorsModal.tsx b/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrorsModal.tsx new file mode 100644 index 0000000000000..2735864112e84 --- /dev/null +++ b/airflow/ui/src/pages/Dashboard/Stats/DAGImportErrorsModal.tsx @@ -0,0 +1,125 @@ +/*! + * 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, Text, HStack, Input } from "@chakra-ui/react"; +import { useEffect, useState } from "react"; +import { PiFilePy } from "react-icons/pi"; + +import type { ImportErrorResponse } from "openapi/requests/types.gen"; +import Time from "src/components/Time"; +import { Accordion, Dialog } from "src/components/ui"; +import { Pagination } from "src/components/ui/Pagination"; + +type ImportDAGErrorModalProps = { + importErrors: Array; + onClose: () => void; + open: boolean; +}; + +const PAGE_LIMIT = 15; + +export const DAGImportErrorsModal: React.FC = ({ + importErrors, + onClose, + open, +}) => { + const [page, setPage] = useState(1); + const [searchQuery, setSearchQuery] = useState(""); + const [filteredErrors, setFilteredErrors] = useState(importErrors); + + const startRange = (page - 1) * PAGE_LIMIT; + const endRange = startRange + PAGE_LIMIT; + const visibleItems = filteredErrors.slice(startRange, endRange); + + const onOpenChange = () => { + setSearchQuery(""); + setPage(1); + onClose(); + }; + + useEffect(() => { + const query = searchQuery.toLowerCase(); + const filtered = importErrors.filter((error) => + error.filename.toLowerCase().includes(query), + ); + + setFilteredErrors(filtered); + setPage(1); + }, [searchQuery, importErrors]); + + return ( + + + + Dag Import Errors + setSearchQuery(event.target.value)} + placeholder="Search by file" + value={searchQuery} + /> + + + + + + + {visibleItems.map((importError) => ( + + + + {importError.filename} + + + + Timestamp: + + {importError.stack_trace} + + + + ))} + + + + setPage(event.page)} + p={4} + page={page} + pageSize={PAGE_LIMIT} + > + + + + + + + + + ); +}; diff --git a/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx b/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx new file mode 100644 index 0000000000000..6921136717274 --- /dev/null +++ b/airflow/ui/src/pages/Dashboard/Stats/Stats.tsx @@ -0,0 +1,34 @@ +/*! + * 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 { Box, Flex, Heading } from "@chakra-ui/react"; +import { FiClipboard } from "react-icons/fi"; + +import { DAGImportErrors } from "./DAGImportErrors"; + +export const Stats = () => ( + + + + + Stats + + + + +); diff --git a/airflow/ui/src/pages/Dashboard/Stats/index.ts b/airflow/ui/src/pages/Dashboard/Stats/index.ts new file mode 100644 index 0000000000000..bda3388ef6448 --- /dev/null +++ b/airflow/ui/src/pages/Dashboard/Stats/index.ts @@ -0,0 +1,20 @@ +/*! + * 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. + */ + +export { Stats } from "./Stats";