diff --git a/airflow-core/src/airflow/ui/src/components/ActionErrors.tsx b/airflow-core/src/airflow/ui/src/components/ActionErrors.tsx new file mode 100644 index 0000000000000..2b2f46d446b70 --- /dev/null +++ b/airflow-core/src/airflow/ui/src/components/ActionErrors.tsx @@ -0,0 +1,46 @@ +/*! + * 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 { Stack } from "@chakra-ui/react"; + +import type { BulkActionResponse } from "openapi/requests/types.gen"; +import { ErrorAlert } from "src/components/ErrorAlert"; +import { Alert } from "src/components/ui"; + +type Props = { + readonly actionResponse?: BulkActionResponse | null; + readonly error: unknown; +}; + +export const ActionErrors = ({ actionResponse, error }: Props) => { + const actionErrors = (actionResponse?.errors ?? []) as Array<{ error: string; status_code?: number }>; + + return ( + <> + + {actionErrors.length > 0 ? ( + + {actionErrors.map((actionError, index) => ( + // eslint-disable-next-line react/no-array-index-key -- per-entity errors have no stable id + + ))} + + ) : undefined} + + ); +}; diff --git a/airflow-core/src/airflow/ui/src/components/DataTable/useRowSelection.ts b/airflow-core/src/airflow/ui/src/components/DataTable/useRowSelection.ts index 174aa5548ba45..fb6842747f7b8 100644 --- a/airflow-core/src/airflow/ui/src/components/DataTable/useRowSelection.ts +++ b/airflow-core/src/airflow/ui/src/components/DataTable/useRowSelection.ts @@ -72,9 +72,23 @@ export const useRowSelection = ({ data = [], getKey }: UseRowSelectionProps) => { + if (keys.length === 0) { + return; + } + setSelectedRows((prev) => { + const newMap = new Map(prev); + + keys.forEach((key) => newMap.delete(key)); + + return newMap; + }); + }; + return { allRowsSelected, clearSelections, + deselectKeys, handleRowSelect, handleSelectAll, selectedRows, diff --git a/airflow-core/src/airflow/ui/src/pages/DagRuns/BulkDeleteDagRunsButton.tsx b/airflow-core/src/airflow/ui/src/pages/DagRuns/BulkDeleteDagRunsButton.tsx index e1a4b9c5c35ff..bedd0739e6b42 100644 --- a/airflow-core/src/airflow/ui/src/pages/DagRuns/BulkDeleteDagRunsButton.tsx +++ b/airflow-core/src/airflow/ui/src/pages/DagRuns/BulkDeleteDagRunsButton.tsx @@ -23,15 +23,15 @@ import { useTranslation } from "react-i18next"; import { FiTrash2 } from "react-icons/fi"; import type { DAGRunResponse } from "openapi/requests/types.gen"; +import { ActionErrors } from "src/components/ActionErrors"; import { DataTable } from "src/components/DataTable"; -import { ErrorAlert } from "src/components/ErrorAlert"; import { StateBadge } from "src/components/StateBadge"; import Time from "src/components/Time"; import { Accordion, Dialog } from "src/components/ui"; import { useBulkDeleteDagRuns } from "src/queries/useBulkDeleteDagRuns"; type Props = { - readonly clearSelections: VoidFunction; + readonly deselectKeys: (keys: Array) => void; readonly selectedDagRuns: Array; }; @@ -58,11 +58,11 @@ const getColumns = (translate: TFunction): Array> => [ }, ]; -const BulkDeleteDagRunsButton = ({ clearSelections, selectedDagRuns }: Props) => { +const BulkDeleteDagRunsButton = ({ deselectKeys, selectedDagRuns }: Props) => { const { t: translate } = useTranslation(["common", "dags"]); const { onClose, onOpen, open } = useDisclosure(); - const { bulkAction, error, isPending } = useBulkDeleteDagRuns({ - clearSelections, + const { bulkAction, data, error, isPending } = useBulkDeleteDagRuns({ + deselectKeys, onSuccessConfirm: onClose, }); @@ -142,7 +142,7 @@ const BulkDeleteDagRunsButton = ({ clearSelections, selectedDagRuns }: Props) => )} - +