diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskCard.tsx b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskCard.tsx deleted file mode 100644 index 83f1635cbc355..0000000000000 --- a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskCard.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/*! - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Heading, VStack, Box, SimpleGrid, Text, Link } from "@chakra-ui/react"; -import { useTranslation } from "react-i18next"; -import { Link as RouterLink } from "react-router-dom"; - -import { useTaskInstanceServiceGetTaskInstances } from "openapi/queries/queries.ts"; -import type { TaskResponse } from "openapi/requests/types.gen"; -import { StateBadge } from "src/components/StateBadge"; -import TaskInstanceTooltip from "src/components/TaskInstanceTooltip"; -import Time from "src/components/Time"; -import { isStatePending, useAutoRefresh } from "src/utils"; -import { getTaskInstanceLink } from "src/utils/links"; - -import { TaskRecentRuns } from "./TaskRecentRuns.tsx"; - -type Props = { - readonly dagId: string; - readonly task: TaskResponse; -}; - -export const TaskCard = ({ dagId, task }: Props) => { - const { t: translate } = useTranslation(); - const refetchInterval = useAutoRefresh({ dagId }); - - const { data } = useTaskInstanceServiceGetTaskInstances( - { - dagId, - dagRunId: "~", - limit: 14, - orderBy: ["-run_after"], - taskId: task.task_id ?? "", - }, - undefined, - { - enabled: Boolean(dagId) && Boolean(task.task_id), - refetchInterval: (query) => - query.state.data?.task_instances.some((ti) => isStatePending(ti.state)) ? refetchInterval : false, - }, - ); - - return ( - - - - {task.task_display_name ?? task.task_id} - {task.is_mapped ? "[]" : undefined} - - - - - - {translate("task.operator")} - - {task.operator_name} - - - - {translate("task.triggerRule")} - - {task.trigger_rule} - - - - {translate("task.lastInstance")} - - {data?.task_instances[0] ? ( - - - - - - - ) : undefined} - - {/* TODO: Handled mapped tasks to not plot each map index as a task instance */} - {!task.is_mapped && } - - - ); -}; diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskRecentRuns.tsx b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskRecentRuns.tsx deleted file mode 100644 index 8dd9e70ad8df3..0000000000000 --- a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/TaskRecentRuns.tsx +++ /dev/null @@ -1,71 +0,0 @@ -/*! - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import duration from "dayjs/plugin/duration"; -import { Link } from "react-router-dom"; - -import type { TaskInstanceResponse } from "openapi/requests/types.gen"; -import TaskInstanceTooltip from "src/components/TaskInstanceTooltip"; -import { getTaskInstanceLink } from "src/utils/links"; - -dayjs.extend(duration); - -const BAR_HEIGHT = 60; - -export const TaskRecentRuns = ({ - taskInstances, -}: { - readonly taskInstances: Array; -}) => { - if (!taskInstances.length) { - return undefined; - } - - const taskInstancesWithDuration = taskInstances.map((taskInstance) => ({ - ...taskInstance, - duration: - dayjs.duration(dayjs(taskInstance.end_date ?? dayjs()).diff(taskInstance.start_date)).asSeconds() || 0, - })); - - const max = Math.max.apply( - undefined, - taskInstancesWithDuration.map((taskInstance) => taskInstance.duration), - ); - - return ( - - {taskInstancesWithDuration.map((taskInstance) => ( - - - - - - - - ))} - - ); -}; diff --git a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx index c74723ce775c6..154e0394a2cb6 100644 --- a/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Dag/Tasks/Tasks.tsx @@ -16,25 +16,63 @@ * specific language governing permissions and limitations * under the License. */ -import { Skeleton, Box } from "@chakra-ui/react"; +import { Box, Link } from "@chakra-ui/react"; +import type { ColumnDef } from "@tanstack/react-table"; +import type { TFunction } from "i18next"; +import { useTranslation } from "react-i18next"; import { useParams, useSearchParams } from "react-router-dom"; +import { Link as RouterLink } from "react-router-dom"; import { useTaskServiceGetTasks } from "openapi/queries"; import type { TaskResponse } from "openapi/requests/types.gen"; import { DataTable } from "src/components/DataTable"; -import type { CardDef } from "src/components/DataTable/types"; import { ErrorAlert } from "src/components/ErrorAlert"; +import { TruncatedText } from "src/components/TruncatedText"; import { SearchParamsKeys } from "src/constants/searchParams.ts"; import { TaskFilters } from "src/pages/Dag/Tasks/TaskFilters/TaskFilters.tsx"; -import { TaskCard } from "./TaskCard"; +type TaskRow = { row: { original: TaskResponse } }; -const cardDef = (dagId: string): CardDef => ({ - card: ({ row }) => , - meta: { - customSkeleton: , +const createColumns = ({ + dagId, + translate, +}: { + dagId: string; + translate: TFunction; +}): Array> => [ + { + accessorKey: "task_display_name", + cell: ({ row: { original } }: TaskRow) => ( + + + + + + ), + enableSorting: false, + header: translate("common:taskId"), }, -}); + { + accessorKey: "trigger_rule", + enableSorting: false, + header: translate("common:task.triggerRule"), + }, + { + accessorKey: "operator_name", + enableSorting: false, + header: translate("common:task.operator"), + }, + { + accessorKey: "retries", + enableSorting: false, + header: translate("tasks:retries"), + }, + { + accessorKey: "is_mapped", + enableSorting: false, + header: translate("tasks:mapped"), + }, +]; export const Tasks = () => { const { dagId = "" } = useParams(); @@ -46,6 +84,10 @@ export const Tasks = () => { const selectedMapped = searchParams.get(MAPPED) ?? undefined; const namePattern = searchParams.get(NAME_PATTERN) ?? undefined; + const { t: translate } = useTranslation(["tasks", "common"]); + + const columns = createColumns({ dagId, translate }); + const { data, error: tasksError, @@ -92,8 +134,7 @@ export const Tasks = () => { > => [ { accessorKey: "task_instance_state", - cell: ({ row: { original } }: TaskInstanceRow) => ( + cell: ({ row: { original } }: HITLRow) => ( {getHITLState(translate, original)} ), header: translate("requiredActionState"), }, { accessorKey: "subject", - cell: ({ row: { original } }: TaskInstanceRow) => ( + cell: ({ row: { original } }: HITLRow) => ( @@ -90,9 +90,7 @@ const taskInstanceColumns = ({ : [ { accessorKey: "run_after", - cell: ({ row: { original } }: TaskInstanceRow) => ( -