You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by ka...@apache.org on 2025/09/18 01:03:50 UTC
(airflow) 11/19: Fix mapIndex type validation error (#55794)
This is an automated email from the ASF dual-hosted git repository.
kaxilnaik pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
commit a524ff8eeec8c0bca40a7d78964448d180ff1365
Author: Guan Ming(Wesley) Chiu <10...@users.noreply.github.com>
AuthorDate: Thu Sep 18 06:30:19 2025 +0800
Fix mapIndex type validation error (#55794)
(cherry picked from commit 7f9a96aa54327729c0bc737ac20cf43cad624a84)
---
.../src/airflow/ui/src/hooks/useSelectedVersion.ts | 6 ++++--
.../airflow/ui/src/layouts/Details/DagBreadcrumb.tsx | 5 +++--
.../ui/src/pages/TaskInstance/AssetEvents.tsx | 20 ++++++++++++++------
.../airflow/ui/src/pages/TaskInstance/Details.tsx | 19 +++++++++++++------
.../airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx | 19 +++++++++++++------
.../ui/src/pages/TaskInstance/TaskInstance.tsx | 13 ++++++++++---
6 files changed, 57 insertions(+), 25 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/hooks/useSelectedVersion.ts b/airflow-core/src/airflow/ui/src/hooks/useSelectedVersion.ts
index fb33fca1719..a5c33c981bc 100644
--- a/airflow-core/src/airflow/ui/src/hooks/useSelectedVersion.ts
+++ b/airflow-core/src/airflow/ui/src/hooks/useSelectedVersion.ts
@@ -65,18 +65,20 @@ const useSelectedVersion = (): number | undefined => {
const taskNode = structureData?.nodes.find((node) => node.id === taskId);
const isMapped = taskNode?.is_mapped;
+ const parsedMapIndex = parseInt(mapIndex, 10);
const { data: mappedTaskInstanceData } = useTaskInstanceServiceGetMappedTaskInstance(
{
dagId,
dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
+ mapIndex: parsedMapIndex,
taskId,
},
undefined,
// Do not enable on a task instance summary. (mapped task but no mapIndex defined)
{
- enabled: taskNode !== undefined && !Boolean(mapIndex === "-1" && isMapped),
+ enabled:
+ taskNode !== undefined && !Boolean(parsedMapIndex === -1 && isMapped) && !isNaN(parsedMapIndex),
},
);
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx b/airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx
index b9d144944b6..c93475ecbfd 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/DagBreadcrumb.tsx
@@ -36,6 +36,7 @@ export const DagBreadcrumb = () => {
const { t: translate } = useTranslation();
const { dagId = "", groupId, mapIndex = "-1", runId, taskId } = useParams();
const refetchInterval = useAutoRefresh({ dagId });
+ const parsedMapIndex = parseInt(mapIndex, 10);
const { data: dag } = useDagServiceGetDagDetails({
dagId,
@@ -56,9 +57,9 @@ export const DagBreadcrumb = () => {
const { data: task } = useTaskServiceGetTask({ dagId, taskId }, undefined, { enabled: Boolean(taskId) });
const { data: mappedTaskInstance } = useTaskInstanceServiceGetMappedTaskInstance(
- { dagId, dagRunId: runId ?? "", mapIndex: parseInt(mapIndex, 10), taskId: taskId ?? "" },
+ { dagId, dagRunId: runId ?? "", mapIndex: parsedMapIndex, taskId: taskId ?? "" },
undefined,
- { enabled: Boolean(runId) && Boolean(taskId) && mapIndex !== "-1" },
+ { enabled: Boolean(runId) && Boolean(taskId) && mapIndex !== "-1" && !isNaN(parsedMapIndex) },
);
const links: Array<{ label: ReactNode | string; labelExtra?: ReactNode; title?: string; value?: string }> =
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx b/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
index 56081790d32..7e2fd720863 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/AssetEvents.tsx
@@ -25,12 +25,20 @@ import { isStatePending, useAutoRefresh } from "src/utils";
export const AssetEvents = () => {
const { dagId = "", mapIndex = "-1", runId = "", taskId = "" } = useParams();
- const { data: taskInstance } = useTaskInstanceServiceGetMappedTaskInstance({
- dagId,
- dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
- taskId,
- });
+ const parsedMapIndex = parseInt(mapIndex, 10);
+
+ const { data: taskInstance } = useTaskInstanceServiceGetMappedTaskInstance(
+ {
+ dagId,
+ dagRunId: runId,
+ mapIndex: parsedMapIndex,
+ taskId,
+ },
+ undefined,
+ {
+ enabled: !isNaN(parsedMapIndex),
+ },
+ );
const refetchInterval = useAutoRefresh({ dagId });
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
index 15b35e4b5b4..400846d1e2a 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Details.tsx
@@ -42,13 +42,20 @@ export const Details = () => {
const [searchParams, setSearchParams] = useSearchParams();
const tryNumberParam = searchParams.get(SearchParamsKeys.TRY_NUMBER);
+ const parsedMapIndex = parseInt(mapIndex, 10);
- const { data: taskInstance } = useTaskInstanceServiceGetMappedTaskInstance({
- dagId,
- dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
- taskId,
- });
+ const { data: taskInstance } = useTaskInstanceServiceGetMappedTaskInstance(
+ {
+ dagId,
+ dagRunId: runId,
+ mapIndex: parsedMapIndex,
+ taskId,
+ },
+ undefined,
+ {
+ enabled: !isNaN(parsedMapIndex),
+ },
+ );
const onSelectTryNumber = (newTryNumber: number) => {
if (newTryNumber === taskInstance?.try_number) {
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx
index c03ec5c49cb..86678a308c6 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/Logs/Logs.tsx
@@ -41,17 +41,24 @@ export const Logs = () => {
const tryNumberParam = searchParams.get(SearchParamsKeys.TRY_NUMBER);
const logLevelFilters = searchParams.getAll(SearchParamsKeys.LOG_LEVEL);
const sourceFilters = searchParams.getAll(SearchParamsKeys.SOURCE);
+ const parsedMapIndex = parseInt(mapIndex, 10);
const {
data: taskInstance,
error,
isLoading,
- } = useTaskInstanceServiceGetMappedTaskInstance({
- dagId,
- dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
- taskId,
- });
+ } = useTaskInstanceServiceGetMappedTaskInstance(
+ {
+ dagId,
+ dagRunId: runId,
+ mapIndex: parsedMapIndex,
+ taskId,
+ },
+ undefined,
+ {
+ enabled: !isNaN(parsedMapIndex),
+ },
+ );
const onSelectTryNumber = (newTryNumber: number) => {
if (newTryNumber === taskInstance?.try_number) {
diff --git a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
index 0eb684f0d89..11f67d3df18 100644
--- a/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
+++ b/airflow-core/src/airflow/ui/src/pages/TaskInstance/TaskInstance.tsx
@@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { Heading } from "@chakra-ui/react";
import { ReactFlowProvider } from "@xyflow/react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
@@ -34,7 +35,7 @@ import { isStatePending, useAutoRefresh } from "src/utils";
import { Header } from "./Header";
export const TaskInstance = () => {
- const { t: translate } = useTranslation(["dag", "hitl"]);
+ const { t: translate } = useTranslation(["dag", "common", "hitl"]);
const { dagId = "", mapIndex = "-1", runId = "", taskId = "" } = useParams();
// Get external views with task_instance destination
const externalTabs = usePluginTabs("task_instance");
@@ -56,6 +57,7 @@ export const TaskInstance = () => {
];
const refetchInterval = useAutoRefresh({ dagId });
+ const parsedMapIndex = parseInt(mapIndex, 10);
const {
data: taskInstance,
@@ -65,11 +67,12 @@ export const TaskInstance = () => {
{
dagId,
dagRunId: runId,
- mapIndex: parseInt(mapIndex, 10),
+ mapIndex: parsedMapIndex,
taskId,
},
undefined,
{
+ enabled: !isNaN(parsedMapIndex),
refetchInterval: (query) => (isStatePending(query.state.data?.state) ? refetchInterval : false),
},
);
@@ -108,7 +111,11 @@ export const TaskInstance = () => {
return (
<ReactFlowProvider>
<DetailsLayout error={error} isLoading={isLoading} tabs={displayTabs}>
- {taskInstance === undefined ? undefined : (
+ {taskInstance === undefined ? (
+ <Heading p={2} size="lg">
+ {translate("common:noItemsFound", { modelName: translate("common:taskInstance_one") })}
+ </Heading>
+ ) : (
<Header
isRefreshing={Boolean(isStatePending(taskInstance.state) && Boolean(refetchInterval))}
taskInstance={taskInstance}