Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3764196031 I think splitting this into several PRs is a better approach. I’ll figure out the remaining gaps and open targeted PRs accordingly. I’m also happy to help review other open PRs for this feature to avoid overlapping work. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3764185146 Apologies for the delay. This PR has become stale, and I noticed there are other active PRs addressing the same issue. To avoid redundancy, I’ll go ahead and close this one. Thank you everyone for your time and reviews. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming closed pull request #51564: Add bulk TI deletion UI URL: https://github.com/apache/airflow/pull/51564 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
Lee-W commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3727697293 I'm now making it a draft. Feel free to mark it as ready -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
Lee-W commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3727695211 @guan404ming would like to follow up whehter wer're still working on this one? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2607004503
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,110 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
Review Comment:
Grid is not updated after a successful delete. We should probably do that
too. cf video. (clearing tasks from the same run)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2607029557
##
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstances/MarkTaskInstancesAsDialog.tsx:
##
@@ -0,0 +1,109 @@
+/*!
+ * 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 { Button, Flex, Heading, VStack } from "@chakra-ui/react";
+import type {
+ TaskInstanceCollectionResponse,
+ TaskInstanceResponse,
+ TaskInstanceState,
+} from "openapi-gen/requests/types.gen";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import { ActionAccordion } from "src/components/ActionAccordion";
+import { StateBadge } from "src/components/StateBadge";
+import { Dialog } from "src/components/ui/Dialog";
+import { useBulkPatchTaskInstances } from
"src/queries/useBulkPatchTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly onClose: () => void;
+ readonly open: boolean;
+ readonly patchKeys: Array;
+ readonly selectedState: TaskInstanceState;
+};
+
+const MarkTaskInstancesAsDialog = ({
+ clearSelections,
+ dagId,
+ dagRunId,
+ onClose,
+ open,
+ patchKeys,
+ selectedState,
+}: Props) => {
+ const [note, setNote] = useState();
+
+ const { isPending, patchTaskInstances } = useBulkPatchTaskInstances({
+dagId,
+dagRunId,
+onSuccessConfirm: () => {
+ clearSelections();
+ onClose();
+},
+ });
+ const { t: translate } = useTranslation();
+
+ const affectedTasks = {
+task_instances: patchKeys,
+total_entries: patchKeys.length,
+ } as TaskInstanceCollectionResponse;
+
+ const handlePatch = (state: TaskInstanceState) => {
+const actionValue = state === "failed" ? "set_failed" : "set_success";
+
+patchTaskInstances(patchKeys, actionValue, { note });
+onClose();
+ };
+
+ return (
+
+
+
+
+
+
+{translate("dags:runAndTaskActions.markAs.title", {
+ state: selectedState,
+ type: translate("common:taskInstance_other"),
+})}
+:
+ {" "}
+
+
+
+
+
+
+
+
+
+
+
handlePatch(selectedState)}>
+ {translate("modal.confirm")}
+
+
+
Review Comment:
I guess it's fine for now since we use the 'bulk' endpoint.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2607005409
##
airflow-core/src/airflow/ui/src/queries/useBulkPatchTaskInstances.ts:
##
@@ -0,0 +1,136 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+export const useBulkPatchTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+
+ const onSuccess = async (responseData: { patch?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
Review Comment:
Same here
##
airflow-core/src/airflow/ui/src/components/MarkAs/TaskInstances/MarkTaskInstancesAsDialog.tsx:
##
@@ -0,0 +1,109 @@
+/*!
+ * 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 { Button, Flex, Heading, VStack } from "@chakra-ui/react";
+import type {
+ TaskInstanceCollectionResponse,
+ TaskInstanceResponse,
+ TaskInstanceState,
+} from "openapi-gen/requests/types.gen";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import { ActionAccordion } from "src/components/ActionAccordion";
+import { StateBadge } from "src/components/StateBadge";
+import { Dialog } from "src/components/ui/Dialog";
+import { useBulkPatchTaskInstances } from
"src/queries/useBulkPatchTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly onClose: () => void;
+ readonly open: boolean;
+ readonly patchKeys: Array;
+ readonly selectedState: TaskInstanceState;
+};
+
+const MarkTaskInstancesAsDialog = ({
+ clearSelections,
+ dagId,
+ dagRunId,
+ onClose,
+ open,
+ patchKeys,
+ selectedState,
+}: Props) => {
+ const [note, setNote] = useState();
+
+ const { isPending, patchTaskInstances } = useBulkPatchTaskInstances({
+dagId,
+dagRunId,
+onSuccessConfirm: () => {
+ clearSelections();
+ onClose();
+},
+ });
+ const { t: translate } = useTranslation();
+
+ const affectedTasks = {
+task_instances: patchKeys,
+total_entries: patchKeys.length,
+ } as TaskInstanceCollectionResponse;
+
+ const handlePatch = (state: TaskInstanceState) => {
+const actionValue = state === "failed" ? "set_failed" : "set_success";
+
+patchTaskInstances(patchKeys, actionValue, { note });
+onClose();
+ };
+
+ return (
+
+
+
+
+
+
+{translate("dags:runAndTaskActions.markAs.title", {
+ state: selectedState,
+ type: translate("common:taskInstance_other"),
+})}
+:
+ {" "}
+
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3636339394 I've updated to work with new endpoint. Please take another look, thanks! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2445300548
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2426829138
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3352657538 @guan404ming any progress on this one ? I think a UI warning could suffice as mentioned by Brent, and unblock this. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2426832459
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2431608351
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATOR);
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2426802121
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2426829138
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2426802121
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,156 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState, useRef } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import type { TaskInstanceResponse } from "openapi/requests";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId?: string;
+ readonly dagRunId?: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+const SEPARATOR = "SEPARATOR";
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+ const pendingOperationsRef = useRef(0);
+ const allSuccessesRef = useRef>([]);
+ const hasErrorsRef = useRef(false);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ dagId === undefined || dagRunId === undefined
+? []
+: [UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId })],
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+hasErrorsRef.current = true;
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+allSuccessesRef.current = [...allSuccessesRef.current, ...success];
+ }
+}
+
+pendingOperationsRef.current -= 1;
+
+if (pendingOperationsRef.current === 0 && !hasErrorsRef.current) {
+ // All operations completed successfully
+ if (allSuccessesRef.current.length > 0) {
+toaster.create({
+ description:
translate("bulkAction.delete.taskInstance.success.description", {
+count: allSuccessesRef.current.length,
+keys: allSuccessesRef.current.join(", "),
+ }),
+ title: translate("bulkAction.delete.taskInstance.success.title"),
+ type: "success",
+});
+onSuccessConfirm();
+ }
+ // Reset state for next operation
+ allSuccessesRef.current = [];
+ hasErrorsRef.current = false;
+}
+ };
+
+ const onError = (_error: unknown) => {
+setError(_error);
+hasErrorsRef.current = true;
+pendingOperationsRef.current -= 1;
+ };
+
+ const { isPending, mutate } = useTaskInstanceServiceBulkTaskInstances({
+onError,
+onSuccess,
+ });
+
+ const deleteTaskInstances = (entities: Array) => {
+// Reset state for new operation
+allSuccessesRef.current = [];
+hasErrorsRef.current = false;
+setError(undefined);
+
+if (Boolean(dagId) && Boolean(dagRunId) && dagId !== undefined && dagRunId
!== undefined) {
+ pendingOperationsRef.current = 1;
+ mutate({
+dagId,
+dagRunId,
+requestBody: {
+ actions: [
+{
+ action: "delete",
+ entities: entities.map((ti) => ({ map_index: ti.map_index,
task_id: ti.task_id })),
+},
+ ],
+},
+ });
+} else {
+ // cross dag run
+ const groupedByDagRunTIs: Record> =
{};
+
+ entities.forEach((ti) => {
+(groupedByDagRunTIs[`${ti.dag_id}${SEPARATOR}${ti.dag_run_id}`] ??=
[]).push(ti);
+ });
+
+ pendingOperationsRef.current = Object.keys(groupedByDagRunTIs).length;
+
+ Object.entries(groupedByDagRunTIs).forEach(([key, groupTIs]) => {
+const [groupDagId, groupDagRunId] = key.split(SEPARATO
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3362005222 > @guan404ming any progress on this one ? I think a UI warning could suffice as mentioned by Brent, and unblock this. Sure! I'm also agree with this solution. I've update the warning to a more detailed version, please let me if it could be better. Thanks! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
FrankPortman commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-613011 Not being able to easily sort/search-by-params/delete runs/TIs in bulk is a **big** con of AF3 for our use case. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3299833731 > I guess it's up to users if they want to do it, but we should probably make it 100% clear it will delete all history and audit records of the TI. > > I don't _personally_ like it, but now I think about it more I'm not sure that we should stop users from being able to do this if they want to. > > Maybe a future change to add a config option to disable deleteing them at the deploy level How about we update the copy "This will remove all metadata related" and spell out what will be deleted? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
ashb commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3299464136 I guess it's up to users if they want to do it, but we should probably make it 100% clear it will delete all history and audit records of the TI. I don't _personally_ like it, but now I think about it more I'm not sure that we should stop users from being able to do this if they want to. Maybe a future change to add a config option to disable deleteing them at the deploy level -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3242877602 This is actual deletion - we issue DELETE on the TI row. The `TaskInstanceHistory` table has CASCADE delete, so all history records are permanently lost when the TI is deleted. When the scheduler recreates the TI, it gets a new UUID and try_number resets to 0, losing all previous execution history. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
ashb commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2313704208
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3243539026 > -1. We should never delete TIs and TIH. This shouldn't even be a feature in the API! It seems like the singular TI deletion is already in our UI and API. Should we need to also remove those related features? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
ashb commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3242939972 -1. We should never delete TIs and TIH. This shouldn't even be a feature in the API! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2314272971
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+ No, we don't have bulk clear currently in UI. It still needs to
update API to support the feature.
- want? -> Some users may want to clear multiple TI. It would take lots of
time to clear one by one. So I think this is optional one but it would be
useful in some cases.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
ashb commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3242014593 Hang on. With the TI history, I'm not sure we want to _ever_ delete TIs. Is this just a wording, or are we actually issuing a delete request on the TI row? (If so what happens to the history/tries table when the scheduler goes and recreates these rows? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2312399144
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+https://github.com/user-attachments/assets/1f24c725-45a8-4477-a3b8-0a5592b123b0
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2312399144
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2310702206
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2310023033
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -51,17 +60,55 @@ const {
STATE: STATE_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;
-const taskInstanceColumns = ({
+const getColumns = ({
+ allRowsSelected,
dagId,
+ onRowSelect,
+ onSelectAll,
runId,
+ selectedRows,
taskId,
translate,
}: {
dagId?: string;
runId?: string;
taskId?: string;
translate: TFunction;
-}): Array> => [
+} & GetColumnsParams): Array> => [
+ ...(Boolean(dagId)
Review Comment:
> I feel like people would want to perform bulk actions on the main task
instance list page too?
You're right. I initially disable it since cross dag deletion is not
literally supported by our backend and need a great refactor for bulk service.
But I think we could handle it in our hook now and refactor our backend after
then. I've updated!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2309903871
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2305243650
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,87 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState } from "react";
+import { useTranslation } from "react-i18next";
+
+import {
+ useTaskInstanceServiceGetTaskInstancesKey,
+ useTaskInstanceServiceBulkTaskInstances,
+ UseGridServiceGetGridTiSummariesKeyFn,
+} from "openapi/queries";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+export const useBulkDeleteTaskInstances = ({ dagId, dagRunId, onSuccessConfirm
}: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+ const { t: translate } = useTranslation("common");
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ UseGridServiceGetGridTiSummariesKeyFn({ dagId, runId: dagRunId }),
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+toaster.create({
+ description: translate("bulkAction.success.description", {
Review Comment:
https://github.com/user-attachments/assets/eefec485-1be7-4364-9d50-dbbc1e39dde5";
/>
We should probably write up separate translation descriptions for each
action instead of relying on so many variable inputs.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2305237454
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -249,6 +323,41 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+ 1 ? "taskInstance_other" :
"taskInstance_one"}`,
+)}`}
+disabled={selectedRows.size === 0}
+ >
+
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2305233420
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -51,17 +60,55 @@ const {
STATE: STATE_PARAM,
}: SearchParamsKeysType = SearchParamsKeys;
-const taskInstanceColumns = ({
+const getColumns = ({
+ allRowsSelected,
dagId,
+ onRowSelect,
+ onSelectAll,
runId,
+ selectedRows,
taskId,
translate,
}: {
dagId?: string;
runId?: string;
taskId?: string;
translate: TFunction;
-}): Array> => [
+} & GetColumnsParams): Array> => [
+ ...(Boolean(dagId)
Review Comment:
Why put a boolean on the select? I feel like people would want to perform
bulk actions on the main task instance list page too?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3211562768 > Backend PR has been merged, I think we can proceed forward with this when we have time. I think frontend part is almost done but I encounter some issues when deleting mapped ti and has submitted [pr](#54791) to fix it. I think I could mark this one as ready to review and would rebase after the fix got merged -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3210583927 Backend PR has been merged, I think we can proceed forward with this. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
phanikumv commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3150361699 Waiting on the backend PR https://github.com/apache/airflow/pull/51850 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
github-actions[bot] commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-3146046538 This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 5 days if no further activity occurs. Thank you for your contributions. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-2981219260 Thanks for the suggestion, I've implemented the backend part of this PR in https://github.com/apache/airflow/pull/51850. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-2977165577 > The api needs some modification for handling ti with map_index as well. Let me mark this as draft. Thanks @guan404ming, do not hesitate to create a different PR for the backend part so it's easier to review and merge. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-2970702831 > For mapped task instance the confirmation table is not correct, cf screenshot, actually 4 TIs are selected (3 mapped TI and 1 non mapped TI), and the modal only show 2 TIs) The api needs some modification for handling ti with map_index as well. Let me mark this as draft. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
pierrejeambrun commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2145141381
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,83 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState } from "react";
+
+import {
+ UseDagRunServiceGetDagRunKeyFn,
+ useDagRunServiceGetDagRunsKey,
+ UseGridServiceGridDataKeyFn,
+ useTaskInstanceServiceBulkTaskInstances,
+ useTaskInstanceServiceGetTaskInstancesKey,
+} from "openapi/queries";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly clearSelections: VoidFunction;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+export const useBulkDeleteTaskInstances = ({ clearSelections, dagId, dagRunId,
onSuccessConfirm }: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }),
+ [useDagRunServiceGetDagRunsKey],
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ UseGridServiceGridDataKeyFn({ dagId }, [{ dagId }]),
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+toaster.create({
+ description: `${success.length} task instances deleted successfully.
Keys: ${success.join(", ")}`,
+ title: "Delete Task Instances Request Successful",
+ type: "success",
+});
+clearSelections();
+onSuccessConfirm();
Review Comment:
Maybe those two could be merged into 1 `onSuccessConfirm` and it's up to the
caller to pass a fn that will both clear selection + close modal, this way we
avoid passing one extra prop to achieve that.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143532666
##
airflow-core/src/airflow/ui/src/queries/useBulkDeleteTaskInstances.ts:
##
@@ -0,0 +1,83 @@
+/*!
+ * 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 { useQueryClient } from "@tanstack/react-query";
+import { useState } from "react";
+
+import {
+ UseDagRunServiceGetDagRunKeyFn,
+ useDagRunServiceGetDagRunsKey,
+ UseGridServiceGridDataKeyFn,
+ useTaskInstanceServiceBulkTaskInstances,
+ useTaskInstanceServiceGetTaskInstancesKey,
+} from "openapi/queries";
+import { toaster } from "src/components/ui";
+
+type Props = {
+ readonly clearSelections: VoidFunction;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly onSuccessConfirm: VoidFunction;
+};
+
+export const useBulkDeleteTaskInstances = ({ clearSelections, dagId, dagRunId,
onSuccessConfirm }: Props) => {
+ const queryClient = useQueryClient();
+ const [error, setError] = useState(undefined);
+
+ const onSuccess = async (responseData: { delete?: { errors: Array;
success: Array } }) => {
+const queryKeys = [
+ UseDagRunServiceGetDagRunKeyFn({ dagId, dagRunId }),
+ [useDagRunServiceGetDagRunsKey],
+ [useTaskInstanceServiceGetTaskInstancesKey],
+ UseGridServiceGridDataKeyFn({ dagId }, [{ dagId }]),
+];
+
+await Promise.all(queryKeys.map((key) => queryClient.invalidateQueries({
queryKey: key })));
+
+if (responseData.delete) {
+ const { errors, success } = responseData.delete;
+
+ if (Array.isArray(errors) && errors.length > 0) {
+const apiError = errors[0] as { error: string };
+
+setError({
+ body: { detail: apiError.error },
+});
+ } else if (Array.isArray(success) && success.length > 0) {
+toaster.create({
+ description: `${success.length} task instances deleted successfully.
Keys: ${success.join(", ")}`,
+ title: "Delete Task Instances Request Successful",
Review Comment:
translations needed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143532306
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/TaskInstances.tsx:
##
@@ -246,6 +310,33 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
+
+
+
+{selectedRows.size} {translate("common:selected")}
+
+
+
Review Comment:
Translation needed
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143530839
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,124 @@
+/*!
+ * 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 { Button, Flex, Heading, Text } from "@chakra-ui/react";
+import type { TaskInstanceCollectionResponse, TaskInstanceResponse } from
"openapi-gen/requests/types.gen";
+import { useTranslation } from "react-i18next";
+import { FiTrash2 } from "react-icons/fi";
+
+import { ActionAccordion } from "src/components/ActionAccordion";
+import ActionButton from "src/components/ui/ActionButton";
+import { Dialog } from "src/components/ui/Dialog";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+ const { t: translate } = useTranslation();
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((ti) => ti.task_id);
+ const type = translate("common:taskInstance_other");
+ const title = translate("dags:runAndTaskActions.delete.dialog.title", { type
});
+ const warningText =
translate("dags:runAndTaskActions.delete.dialog.warning", { type });
+ const deleteButtonText = translate("dags:runAndTaskActions.delete.button", {
type });
+
+ const handleDelete = () => {
+if (dagId && dagRunId) {
+ mutate({
+dagId,
+dagRunId,
+requestBody: { actions: [{ action: "delete", entities: taskIds }] },
+ });
+} else {
+ // cross dag run
+ const grouped: Record> = {};
+
+ deleteKeys.forEach((ti) => {
+(grouped[ti.dag_run_id] ??= []).push(ti.task_id);
+ });
+ Object.entries(grouped).forEach(([groupDagRunId, groupTaskIds]) => {
+if (dagId && groupDagRunId) {
+ mutate({
+dagId,
+dagRunId: groupDagRunId,
+requestBody: { actions: [{ action: "delete", entities:
groupTaskIds }] },
+ });
+}
+ });
+}
+ };
+
+ const affectedTasks = {
+task_instances: deleteKeys,
+total_entries: deleteKeys.length,
+ } as TaskInstanceCollectionResponse;
+
+ return (
+<>
+ }
+onClick={onOpen}
+text={deleteButtonText}
+variant="outline"
+withText
+ />
+
+
+
+
+{title}
+
Review Comment:
```suggestion
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on PR #51564: URL: https://github.com/apache/airflow/pull/51564#issuecomment-2967857005 I have updated the translation and try reuse `AffectedTasks` Current ui looks like: https://github.com/user-attachments/assets/ed3a2b4d-b800-4443-81d5-664547bafe74 -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143324096
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
+
+
+
+
+
+
+
+ You are about to delete{" "}
+
+{deleteKeys.length} task instance{deleteKeys.length > 1 ? "s"
: ""}.
+
+
+
+{taskIds.join(", ")}
Review Comment:
Or if the table makes it obvious enough. Let's just summarize "X task
instances across Y dag runs will be deleted permanently"
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143322092
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
+
+
+
+
+
+
+
+ You are about to delete{" "}
+
+{deleteKeys.length} task instance{deleteKeys.length > 1 ? "s"
: ""}.
+
+
+
+{taskIds.join(", ")}
Review Comment:
Let's reuse the `AffectedTasks` we use in clearing and marking task
instances. It'll be much easier to read what you're about to delete
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
bbovenzi commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2143320288
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
You should be able to rebase now and get all the english translations.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2140347820
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
Thanks for the review.
Sure, I consider to update translation patch after #51558 got merged since
it covers part of translation which would be used here and seems almost done.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2140347820
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
Sure, I consider to update translation patch after #51558 since it cover
part of translation which would be used here and almost done.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
Re: [PR] Add bulk TI deletion UI [airflow]
guan404ming commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2140347820
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
Sure, I consider to update translation patch after #51558 got merged since
it cover part of translation which would be used here and seems almost done.
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
Sure, I consider to update translation patch after #51558 got merged since
it cover part of translation which would be used here and seems almost done.
Don't want to block that one or create conflict. Thanks!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please co
Re: [PR] Add bulk TI deletion UI [airflow]
jscheffl commented on code in PR #51564:
URL: https://github.com/apache/airflow/pull/51564#discussion_r2138651333
##
airflow-core/src/airflow/ui/src/pages/TaskInstances/DeleteTaskInstancesButton.tsx:
##
@@ -0,0 +1,123 @@
+/*!
+ * 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 { Code, Flex, Heading, Text, VStack, useDisclosure } from
"@chakra-ui/react";
+import { FiTrash, FiTrash2 } from "react-icons/fi";
+
+import { ErrorAlert } from "src/components/ErrorAlert";
+import { Button, Dialog } from "src/components/ui";
+import { useBulkDeleteTaskInstances } from
"src/queries/useBulkDeleteTaskInstances";
+
+type Props = {
+ readonly clearSelections: () => void;
+ readonly dagId: string;
+ readonly dagRunId: string;
+ readonly deleteKeys: Array<{
+dagRunId: string;
+taskId: string;
+ }>;
+};
+
+const DeleteTaskInstancesButton = ({ clearSelections, dagId, dagRunId,
deleteKeys }: Props) => {
+ const { onClose, onOpen, open } = useDisclosure();
+ const { error, isPending, mutate } = useBulkDeleteTaskInstances({
+clearSelections,
+dagId,
+dagRunId,
+onSuccessConfirm: onClose,
+ });
+
+ if (deleteKeys.length === 0) {
+return undefined;
+ }
+
+ const taskIds = deleteKeys.map((key) => key.taskId);
+
+ return (
+<>
+
+ Delete
+
+
+
+
+
+
+ Delete Task Instance{deleteKeys.length > 1 ?
"s" : ""}
Review Comment:
As we are in the process of translation of UI, can you please add i18n to
the new UI so that we do not merge new "gaps"?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
[PR] Add bulk TI deletion UI [airflow]
guan404ming opened a new pull request, #51564:
URL: https://github.com/apache/airflow/pull/51564
## Related PR
- this one is the follow up pr of #50443 to implement bulk TI deletion ui
## How
- add multi-select in ti table
- minor fix in bulk TI deletion endpoint
https://github.com/user-attachments/assets/ed9455dd-ed94-44a0-a913-2641db5663dd
---
**^ Add meaningful description above**
Read the **[Pull Request
Guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#pull-request-guidelines)**
for more information.
In case of fundamental code changes, an Airflow Improvement Proposal
([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvement+Proposals))
is needed.
In case of a new dependency, check compliance with the [ASF 3rd Party
License Policy](https://www.apache.org/legal/resolved.html#category-x).
In case of backwards incompatible changes please leave a note in a
newsfragment file, named `{pr_number}.significant.rst` or
`{issue_number}.significant.rst`, in
[airflow-core/newsfragments](https://github.com/apache/airflow/tree/main/airflow-core/newsfragments).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
