This is an automated email from the ASF dual-hosted git repository.
guanmingchiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 6c853ff385d Fix UI build error (#58545)
6c853ff385d is described below
commit 6c853ff385de3ebcb24ce8d3ccd627a2e4a9a484
Author: LI,JHE-CHEN <[email protected]>
AuthorDate: Thu Nov 20 22:35:25 2025 -0500
Fix UI build error (#58545)
* fix(ui): fix build failures in clear task instances
* fix: resolve lint errors
---
.../airflow/ui/public/i18n/locales/en/dags.json | 12 +-
.../ClearTaskInstanceConfirmationDialog.tsx | 39 +++--
.../Clear/TaskInstance/ClearTaskInstanceDialog.tsx | 168 +++++++++++----------
.../ui/src/queries/useClearTaskInstances.ts | 35 ++---
.../src/airflow/ui/src/utils/datetimeUtils.ts | 2 +-
5 files changed, 126 insertions(+), 130 deletions(-)
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
b/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
index aef5d3f65ee..5ea7f9c74f4 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/en/dags.json
@@ -34,6 +34,10 @@
"error": "Failed to clear {{type}}",
"title": "Clear {{type}}"
},
+ "confirmationDialog": {
+ "description": "Task is currently in a {{state}} state started by user
{{user}} at {{time}}. \nThe user is unable to clear this task until it is done
running or a user unchecks the \"Prevent rerun of running tasks\" option in the
clear task dialog.",
+ "title": "Cannot Clear Task Instance"
+ },
"delete": {
"button": "Delete {{type}}",
"dialog": {
@@ -61,14 +65,10 @@
"future": "Future",
"onlyFailed": "Clear only failed tasks",
"past": "Past",
+ "preventRunningTasks": "Prevent rerun if task is running",
"queueNew": "Queue up new tasks",
"runOnLatestVersion": "Run with latest bundle version",
- "upstream": "Upstream",
- "preventRunningTasks": "Prevent rerun if task is running"
- },
- "confirmationDialog": {
- "title": "Cannot Clear Task Instance",
- "description": "Task is currently in a {{state}} state started by user
{{user}} at {{time}}. \nThe user is unable to clear this task until it is done
running or a user unchecks the \"Prevent rerun of running tasks\" option in the
clear task dialog."
+ "upstream": "Upstream"
}
},
"search": {
diff --git
a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceConfirmationDialog.tsx
b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceConfirmationDialog.tsx
index a76a2ae778f..0a34c7335b1 100644
---
a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceConfirmationDialog.tsx
+++
b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceConfirmationDialog.tsx
@@ -16,10 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { useEffect, useState, useCallback } from "react";
import { VStack, Icon, Text, Spinner } from "@chakra-ui/react";
-import { GoAlertFill } from "react-icons/go";
+import { useEffect, useState, useCallback } from "react";
import { useTranslation } from "react-i18next";
+import { GoAlertFill } from "react-icons/go";
+
import { Button, Dialog } from "src/components/ui";
import { useClearTaskInstancesDryRun } from
"src/queries/useClearTaskInstancesDryRun";
import { getRelativeTime } from "src/utils/datetimeUtils";
@@ -73,7 +74,9 @@ const ClearTaskInstanceConfirmationDialog = ({
const [isReady, setIsReady] = useState(false);
const handleConfirm = useCallback(() => {
- if (onConfirm) onConfirm();
+ if (onConfirm) {
+ onConfirm();
+ }
onClose();
}, [onConfirm, onClose]);
@@ -83,8 +86,7 @@ const ClearTaskInstanceConfirmationDialog = ({
useEffect(() => {
if (!isFetching && open && data) {
- const isInTriggeringState =
- taskCurrentState === "queued" || taskCurrentState === "scheduled";
+ const isInTriggeringState = taskCurrentState === "queued" ||
taskCurrentState === "scheduled";
if (!preventRunningTask || !isInTriggeringState) {
handleConfirm();
@@ -109,7 +111,7 @@ const ClearTaskInstanceConfirmationDialog = ({
<Dialog.Header>
<VStack align="start" gap={4}>
<Dialog.Title>
- <Icon color="tomato" size="lg" pr="2">
+ <Icon color="tomato" pr="2" size="lg">
<GoAlertFill />
</Icon>
{translate("dags:runAndTaskActions.confirmationDialog.title")}
@@ -117,20 +119,17 @@ const ClearTaskInstanceConfirmationDialog = ({
<Dialog.Description>
{taskInstances.length > 0 && (
<>
- {translate(
-
"dags:runAndTaskActions.confirmationDialog.description",
- {
- state: taskCurrentState,
- time:
- firstInstance?.start_date !== null &&
firstInstance?.start_date !== undefined
- ? getRelativeTime(firstInstance.start_date)
- : undefined,
- user:
- (firstInstance?.unixname?.trim().length ?? 0) > 0
- ? firstInstance?.unixname
- : "unknown user",
- }
- )}
+
{translate("dags:runAndTaskActions.confirmationDialog.description", {
+ state: taskCurrentState,
+ time:
+ firstInstance?.start_date !== null &&
firstInstance?.start_date !== undefined
+ ? getRelativeTime(firstInstance.start_date)
+ : undefined,
+ user:
+ (firstInstance?.unixname?.trim().length ?? 0) > 0
+ ? firstInstance?.unixname
+ : "unknown user",
+ })}
</>
)}
</Dialog.Description>
diff --git
a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx
b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx
index fa4e85a3bf0..a2d5bc4b05a 100644
---
a/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx
+++
b/airflow-core/src/airflow/ui/src/components/Clear/TaskInstance/ClearTaskInstanceDialog.tsx
@@ -30,6 +30,7 @@ import SegmentedControl from
"src/components/ui/SegmentedControl";
import { useClearTaskInstances } from "src/queries/useClearTaskInstances";
import { useClearTaskInstancesDryRun } from
"src/queries/useClearTaskInstancesDryRun";
import { usePatchTaskInstance } from "src/queries/usePatchTaskInstance";
+
import ClearTaskInstanceConfirmationDialog from
"./ClearTaskInstanceConfirmationDialog";
type Props = {
@@ -44,7 +45,6 @@ const ClearTaskInstanceDialog = ({ onClose: onCloseDialog,
open: openDialog, tas
const { t: translate } = useTranslation();
const { onClose, onOpen, open } = useDisclosure();
-
const dagId = taskInstance.dag_id;
const dagRunId = taskInstance.dag_run_id;
@@ -111,90 +111,91 @@ const ClearTaskInstanceDialog = ({ onClose:
onCloseDialog, open: openDialog, tas
return (
<>
- <Dialog.Root lazyMount onOpenChange={onCloseDialog} open={openDialog ?
!open : false} size="xl">
- <Dialog.Content backdrop>
- <Dialog.Header>
- <VStack align="start" gap={4}>
- <Heading size="xl">
- <strong>
- {translate("dags:runAndTaskActions.clear.title", {
- type: translate("taskInstance_one"),
- })}
- :
- </strong>{" "}
- {taskInstance.task_display_name} <Time
datetime={taskInstance.start_date} />
- </Heading>
- </VStack>
- </Dialog.Header>
-
- <Dialog.CloseTrigger />
-
- <Dialog.Body width="full">
- <Flex justifyContent="center">
- <SegmentedControl
- defaultValues={["downstream"]}
- multiple
- onChange={setSelectedOptions}
- options={[
- {
- disabled: taskInstance.logical_date === null,
- label: translate("dags:runAndTaskActions.options.past"),
- value: "past",
- },
- {
- disabled: taskInstance.logical_date === null,
- label: translate("dags:runAndTaskActions.options.future"),
- value: "future",
- },
- {
- label: translate("dags:runAndTaskActions.options.upstream"),
- value: "upstream",
- },
- {
- label:
translate("dags:runAndTaskActions.options.downstream"),
- value: "downstream",
- },
- {
- label:
translate("dags:runAndTaskActions.options.onlyFailed"),
- value: "onlyFailed",
- },
- ]}
- />
- </Flex>
- <ActionAccordion affectedTasks={affectedTasks} note={note}
setNote={setNote} />
- <Flex
- {...(shouldShowBundleVersionOption ? { alignItems: "center" } :
{})}
- justifyContent={shouldShowBundleVersionOption ? "space-between" :
"end"}
- mt={3}
- >
- {shouldShowBundleVersionOption ? (
+ <Dialog.Root lazyMount onOpenChange={onCloseDialog} open={openDialog ?
!open : false} size="xl">
+ <Dialog.Content backdrop>
+ <Dialog.Header>
+ <VStack align="start" gap={4}>
+ <Heading size="xl">
+ <strong>
+ {translate("dags:runAndTaskActions.clear.title", {
+ type: translate("taskInstance_one"),
+ })}
+ :
+ </strong>{" "}
+ {taskInstance.task_display_name} <Time
datetime={taskInstance.start_date} />
+ </Heading>
+ </VStack>
+ </Dialog.Header>
+
+ <Dialog.CloseTrigger />
+
+ <Dialog.Body width="full">
+ <Flex justifyContent="center">
+ <SegmentedControl
+ defaultValues={["downstream"]}
+ multiple
+ onChange={setSelectedOptions}
+ options={[
+ {
+ disabled: taskInstance.logical_date === null,
+ label: translate("dags:runAndTaskActions.options.past"),
+ value: "past",
+ },
+ {
+ disabled: taskInstance.logical_date === null,
+ label: translate("dags:runAndTaskActions.options.future"),
+ value: "future",
+ },
+ {
+ label:
translate("dags:runAndTaskActions.options.upstream"),
+ value: "upstream",
+ },
+ {
+ label:
translate("dags:runAndTaskActions.options.downstream"),
+ value: "downstream",
+ },
+ {
+ label:
translate("dags:runAndTaskActions.options.onlyFailed"),
+ value: "onlyFailed",
+ },
+ ]}
+ />
+ </Flex>
+ <ActionAccordion affectedTasks={affectedTasks} note={note}
setNote={setNote} />
+ <Flex
+ {...(shouldShowBundleVersionOption ? { alignItems: "center" } :
{})}
+ justifyContent={shouldShowBundleVersionOption ? "space-between"
: "end"}
+ mt={3}
+ >
+ {shouldShowBundleVersionOption ? (
+ <Checkbox
+ checked={runOnLatestVersion}
+ onCheckedChange={(event) =>
setRunOnLatestVersion(Boolean(event.checked))}
+ >
+
{translate("dags:runAndTaskActions.options.runOnLatestVersion")}
+ </Checkbox>
+ ) : undefined}
<Checkbox
- checked={runOnLatestVersion}
- onCheckedChange={(event) =>
setRunOnLatestVersion(Boolean(event.checked))}
+ checked={preventRunningTask}
+ onCheckedChange={(event) =>
setPreventRunningTask(Boolean(event.checked))}
+ style={{ marginRight: "auto" }}
>
-
{translate("dags:runAndTaskActions.options.runOnLatestVersion")}
+
{translate("dags:runAndTaskActions.options.preventRunningTasks")}
</Checkbox>
- ) : undefined}
- <Checkbox
- checked={preventRunningTask}
- onCheckedChange={(event) =>
setPreventRunningTask(Boolean(event.checked))}
- style={{ marginRight: "auto"}}
- >
- {translate("dags:runAndTaskActions.options.preventRunningTasks")}
- </Checkbox>
- <Button
- colorPalette="brand"
- disabled={affectedTasks.total_entries === 0}
- loading={isPending || isPendingPatchDagRun}
- onClick={onOpen}
- >
- <CgRedo /> {translate("modal.confirm")}
- </Button>
- </Flex>
- </Dialog.Body>
- </Dialog.Content>
- </Dialog.Root>
- {open ? <ClearTaskInstanceConfirmationDialog
+ <Button
+ colorPalette="brand"
+ disabled={affectedTasks.total_entries === 0}
+ loading={isPending || isPendingPatchDagRun}
+ onClick={onOpen}
+ >
+ <CgRedo /> {translate("modal.confirm")}
+ </Button>
+ </Flex>
+ </Dialog.Body>
+ </Dialog.Content>
+ </Dialog.Root>
+ {open ? (
+ <ClearTaskInstanceConfirmationDialog
dagDetails={{
dagId,
dagRunId,
@@ -236,7 +237,8 @@ const ClearTaskInstanceDialog = ({ onClose: onCloseDialog,
open: openDialog, tas
}}
open={open}
preventRunningTask={preventRunningTask}
- /> : null}
+ />
+ ) : null}
</>
);
};
diff --git a/airflow-core/src/airflow/ui/src/queries/useClearTaskInstances.ts
b/airflow-core/src/airflow/ui/src/queries/useClearTaskInstances.ts
index a04db2fb31d..ce9822a63ef 100644
--- a/airflow-core/src/airflow/ui/src/queries/useClearTaskInstances.ts
+++ b/airflow-core/src/airflow/ui/src/queries/useClearTaskInstances.ts
@@ -19,7 +19,6 @@
import { useQueryClient } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
-
import {
UseDagRunServiceGetDagRunKeyFn,
useDagRunServiceGetDagRunsKey,
@@ -29,12 +28,12 @@ import {
UseGridServiceGetGridTiSummariesKeyFn,
useGridServiceGetGridTiSummariesKey,
} from "openapi/queries";
+import type { ApiError } from "openapi/requests";
import type { ClearTaskInstancesBody, TaskInstanceCollectionResponse } from
"openapi/requests/types.gen";
import { toaster } from "src/components/ui";
import { useClearTaskInstancesDryRunKey } from "./useClearTaskInstancesDryRun";
import { usePatchTaskInstanceDryRunKey } from "./usePatchTaskInstanceDryRun";
-import type { ApiError } from "openapi/requests";
export const useClearTaskInstances = ({
dagId,
@@ -57,31 +56,27 @@ export const useClearTaskInstances = ({
const apiError = error as ApiError;
description = typeof apiError.message === "string" ? apiError.message :
"";
- const apiErrorWithDetail = apiError as unknown as { detail?: unknown };
- detail =
- typeof apiErrorWithDetail.body.detail === "string"
- ? apiErrorWithDetail.body.detail
- : "";
-
- if ( detail.includes("AirflowClearRunningTaskException") === true ) {
- description = detail
- }
+ const apiErrorWithDetail = apiError as unknown as { body?: { detail?:
unknown } };
+ detail = typeof apiErrorWithDetail.body?.detail === "string" ?
apiErrorWithDetail.body.detail : "";
+
+ if (detail.includes("AirflowClearRunningTaskException")) {
+ description = detail;
+ }
} else {
// Fallback for completely unknown errors
- description = translate("common:error.defaultMessage")
+ description = translate("common:error.defaultMessage");
}
toaster.create({
- description: description,
- title: translate("dags:runAndTaskActions.clear.error", {
- type: translate("common:taskInstance_one"),
- }),
- type: "error",
- });
+ description,
+ title: translate("dags:runAndTaskActions.clear.error", {
+ type: translate("common:taskInstance_one"),
+ }),
+ type: "error",
+ });
};
-
const onSuccess = async (
_: TaskInstanceCollectionResponse,
variables: { dagId: string; requestBody: ClearTaskInstancesBody },
@@ -133,6 +128,6 @@ export const useClearTaskInstances = ({
onSuccess,
// This function uses the mutation function of React
// For showing the error toast immediately, set retry to 0
- retry: 0
+ retry: 0,
});
};
diff --git a/airflow-core/src/airflow/ui/src/utils/datetimeUtils.ts
b/airflow-core/src/airflow/ui/src/utils/datetimeUtils.ts
index dc4eea6731f..14d357b9a57 100644
--- a/airflow-core/src/airflow/ui/src/utils/datetimeUtils.ts
+++ b/airflow-core/src/airflow/ui/src/utils/datetimeUtils.ts
@@ -18,8 +18,8 @@
*/
import dayjs from "dayjs";
import dayjsDuration from "dayjs/plugin/duration";
-import tz from "dayjs/plugin/timezone";
import relativeTime from "dayjs/plugin/relativeTime";
+import tz from "dayjs/plugin/timezone";
dayjs.extend(dayjsDuration);
dayjs.extend(relativeTime);