diff --git a/airflow/ui/package.json b/airflow/ui/package.json index e2aeada97dd57..c2d28f6425e1b 100644 --- a/airflow/ui/package.json +++ b/airflow/ui/package.json @@ -37,7 +37,7 @@ "react-chartjs-2": "^5.2.0", "react-dom": "^18.3.1", "react-hook-form": "^7.20.0", - "react-icons": "^5.3.0", + "react-icons": "^5.4.0", "react-router-dom": "^6.26.2", "react-syntax-highlighter": "^15.5.6", "use-debounce": "^10.0.3", diff --git a/airflow/ui/pnpm-lock.yaml b/airflow/ui/pnpm-lock.yaml index 425192db8879e..b30275d9e41c4 100644 --- a/airflow/ui/pnpm-lock.yaml +++ b/airflow/ui/pnpm-lock.yaml @@ -72,8 +72,8 @@ importers: specifier: ^7.20.0 version: 7.53.1(react@18.3.1) react-icons: - specifier: ^5.3.0 - version: 5.3.0(react@18.3.1) + specifier: ^5.4.0 + version: 5.4.0(react@18.3.1) react-router-dom: specifier: ^6.26.2 version: 6.26.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -3014,8 +3014,8 @@ packages: peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-icons@5.3.0: - resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==} + react-icons@5.4.0: + resolution: {integrity: sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==} peerDependencies: react: '*' @@ -7208,7 +7208,7 @@ snapshots: dependencies: react: 18.3.1 - react-icons@5.3.0(react@18.3.1): + react-icons@5.4.0(react@18.3.1): dependencies: react: 18.3.1 diff --git a/airflow/ui/src/components/DagVizModal.tsx b/airflow/ui/src/components/DagVizModal.tsx deleted file mode 100644 index 846200eca330e..0000000000000 --- a/airflow/ui/src/components/DagVizModal.tsx +++ /dev/null @@ -1,52 +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 } from "@chakra-ui/react"; - -import type { DAGResponse } from "openapi/requests/types.gen"; -import { Dialog } from "src/components/ui"; - -import { Graph } from "../pages/DagsList/Dag/Graph"; - -type TriggerDAGModalProps = { - dagDisplayName?: DAGResponse["dag_display_name"]; - dagId?: DAGResponse["dag_id"]; - onClose: () => void; - open: boolean; -}; - -export const DagVizModal: React.FC = ({ - dagDisplayName, - dagId, - onClose, - open, -}) => ( - - - - - {Boolean(dagDisplayName) ? dagDisplayName : "Dag Undefined"} - - - - - {dagId === undefined ? undefined : } - - - -); diff --git a/airflow/ui/src/layouts/Details/DagVizModal.tsx b/airflow/ui/src/layouts/Details/DagVizModal.tsx new file mode 100644 index 0000000000000..86d5d94906eaf --- /dev/null +++ b/airflow/ui/src/layouts/Details/DagVizModal.tsx @@ -0,0 +1,92 @@ +/*! + * 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, Heading, HStack } from "@chakra-ui/react"; +import { FaChartGantt } from "react-icons/fa6"; +import { FiGrid } from "react-icons/fi"; +import { Link as RouterLink, useSearchParams } from "react-router-dom"; + +import type { DAGResponse } from "openapi/requests/types.gen"; +import { DagIcon } from "src/assets/DagIcon"; +import { Dialog } from "src/components/ui"; +import { Graph } from "src/pages/DagsList/Dag/Graph"; +import { Grid } from "src/pages/DagsList/Dag/Grid"; +import { capitalize } from "src/utils"; + +type TriggerDAGModalProps = { + dagDisplayName?: DAGResponse["dag_display_name"]; + dagId?: DAGResponse["dag_id"]; + onClose: () => void; + open: boolean; +}; + +const visualizationOptions = [ + { icon: , value: "gantt" }, + { icon: , value: "graph" }, + { icon: , value: "grid" }, +]; + +export const DagVizModal: React.FC = ({ + dagDisplayName, + dagId, + onClose, + open, +}) => { + const [searchParams] = useSearchParams(); + + const activeViz = searchParams.get("modal") ?? "graph"; + + return ( + + + + + + {Boolean(dagDisplayName) ? dagDisplayName : "Dag Undefined"} + + {visualizationOptions.map(({ icon, value }) => ( + + + + ))} + + + + + {activeViz === "graph" && dagId !== undefined ? ( + + ) : undefined} + {activeViz === "grid" && dagId !== undefined ? : undefined} + + + + ); +}; diff --git a/airflow/ui/src/layouts/Details/DetailsLayout.tsx b/airflow/ui/src/layouts/Details/DetailsLayout.tsx new file mode 100644 index 0000000000000..e1aa96190168e --- /dev/null +++ b/airflow/ui/src/layouts/Details/DetailsLayout.tsx @@ -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 { Box, Button } from "@chakra-ui/react"; +import type { PropsWithChildren } from "react"; +import { FiChevronsLeft } from "react-icons/fi"; +import { + Outlet, + Link as RouterLink, + useParams, + useSearchParams, +} from "react-router-dom"; + +import type { DAGResponse } from "openapi/requests/types.gen"; +import { ErrorAlert } from "src/components/ErrorAlert"; +import { ProgressBar } from "src/components/ui"; +import { OpenGroupsProvider } from "src/context/openGroups"; +import { DagVizModal } from "src/layouts/Details/DagVizModal"; +import { NavTabs } from "src/layouts/Details/NavTabs"; + +type Props = { + readonly dag?: DAGResponse; + readonly error?: unknown; + readonly isLoading?: boolean; + readonly tabs: Array<{ label: string; value: string }>; +} & PropsWithChildren; + +export const DetailsLayout = ({ + children, + dag, + error, + isLoading, + tabs, +}: Props) => { + const { dagId = "" } = useParams(); + + const [searchParams, setSearchParams] = useSearchParams(); + + const modal = searchParams.get("modal"); + + const isModalOpen = modal !== null; + const onClose = () => { + searchParams.delete("modal"); + setSearchParams(searchParams); + }; + + return ( + + + + {children} + + + + + + + + + + ); +}; diff --git a/airflow/ui/src/components/NavTabs.tsx b/airflow/ui/src/layouts/Details/NavTabs.tsx similarity index 62% rename from airflow/ui/src/components/NavTabs.tsx rename to airflow/ui/src/layouts/Details/NavTabs.tsx index 915b5c5d7feb4..093413e7a1aff 100644 --- a/airflow/ui/src/components/NavTabs.tsx +++ b/airflow/ui/src/layouts/Details/NavTabs.tsx @@ -16,16 +16,18 @@ * specific language governing permissions and limitations * under the License. */ -import { Center, Flex } from "@chakra-ui/react"; -import type { ReactNode } from "react"; -import { NavLink } from "react-router-dom"; +import { Button, Center, Flex } from "@chakra-ui/react"; +import { FaChartGantt } from "react-icons/fa6"; +import { FiGrid } from "react-icons/fi"; +import { NavLink, Link as RouterLink } from "react-router-dom"; + +import { DagIcon } from "src/assets/DagIcon"; type Props = { - readonly rightButtons?: ReactNode; readonly tabs: Array<{ label: string; value: string }>; }; -export const NavTabs = ({ rightButtons, tabs }: Props) => ( +export const NavTabs = ({ tabs }: Props) => ( ( ))} - {rightButtons} + + + + + ); diff --git a/airflow/ui/src/pages/DagsList/Dag/Dag.tsx b/airflow/ui/src/pages/DagsList/Dag/Dag.tsx index ac149d10b46e2..87283b077d1e6 100644 --- a/airflow/ui/src/pages/DagsList/Dag/Dag.tsx +++ b/airflow/ui/src/pages/DagsList/Dag/Dag.tsx @@ -16,30 +16,33 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Button } from "@chakra-ui/react"; -import { FiChevronsLeft } from "react-icons/fi"; -import { Outlet, Link as RouterLink, useParams } from "react-router-dom"; +import { useParams } from "react-router-dom"; import { useDagServiceGetDagDetails, useDagsServiceRecentDagRuns, } from "openapi/queries"; -import { ErrorAlert } from "src/components/ErrorAlert"; -import { ProgressBar } from "src/components/ui"; -import { OpenGroupsProvider } from "src/context/openGroups"; +import { DetailsLayout } from "src/layouts/Details/DetailsLayout"; import { Header } from "./Header"; -import { DagTabs } from "./Tabs"; + +const tabs = [ + { label: "Overview", value: "" }, + { label: "Runs", value: "runs" }, + { label: "Tasks", value: "tasks" }, + { label: "Events", value: "events" }, + { label: "Code", value: "code" }, +]; export const Dag = () => { - const { dagId } = useParams(); + const { dagId = "" } = useParams(); const { data: dag, error, isLoading, } = useDagServiceGetDagDetails({ - dagId: dagId ?? "", + dagId, }); // TODO: replace with with a list dag runs by dag id request @@ -47,7 +50,7 @@ export const Dag = () => { data: runsData, error: runsError, isLoading: isLoadingRuns, - } = useDagsServiceRecentDagRuns({ dagIdPattern: dagId ?? "" }, undefined, { + } = useDagsServiceRecentDagRuns({ dagIdPattern: dagId }, undefined, { enabled: Boolean(dagId), }); @@ -56,25 +59,13 @@ export const Dag = () => { ?.latest_dag_runs ?? []; return ( - - - -
- - - - - - - - + +
+ ); }; diff --git a/airflow/ui/src/pages/DagsList/Dag/Grid/Grid.tsx b/airflow/ui/src/pages/DagsList/Dag/Grid/Grid.tsx new file mode 100644 index 0000000000000..9d4b4bb9402fb --- /dev/null +++ b/airflow/ui/src/pages/DagsList/Dag/Grid/Grid.tsx @@ -0,0 +1,25 @@ +/*! + * 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 } from "@chakra-ui/react"; + +export const Grid = () => { + console.log("grid"); + + return grid; +}; diff --git a/airflow/ui/src/pages/DagsList/Dag/Grid/index.ts b/airflow/ui/src/pages/DagsList/Dag/Grid/index.ts new file mode 100644 index 0000000000000..dccae200d1c23 --- /dev/null +++ b/airflow/ui/src/pages/DagsList/Dag/Grid/index.ts @@ -0,0 +1,20 @@ +/*! + * 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. + */ + +export * from "./Grid"; diff --git a/airflow/ui/src/pages/DagsList/Dag/Header.tsx b/airflow/ui/src/pages/DagsList/Dag/Header.tsx index bc67142bd0317..3e118e97fde48 100644 --- a/airflow/ui/src/pages/DagsList/Dag/Header.tsx +++ b/airflow/ui/src/pages/DagsList/Dag/Header.tsx @@ -38,7 +38,7 @@ export const Header = ({ readonly dagId?: string; readonly latestRun?: DAGRunResponse; }) => ( - + diff --git a/airflow/ui/src/pages/DagsList/Dag/Tabs.tsx b/airflow/ui/src/pages/DagsList/Dag/Tabs.tsx deleted file mode 100644 index 9473b210e991a..0000000000000 --- a/airflow/ui/src/pages/DagsList/Dag/Tabs.tsx +++ /dev/null @@ -1,72 +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 { Button } from "@chakra-ui/react"; -import { useSearchParams } from "react-router-dom"; - -import type { DAGResponse } from "openapi/requests/types.gen"; -import { DagIcon } from "src/assets/DagIcon"; -import { DagVizModal } from "src/components/DagVizModal"; -import { NavTabs } from "src/components/NavTabs"; - -const tabs = [ - { label: "Overview", value: "" }, - { label: "Runs", value: "runs" }, - { label: "Tasks", value: "tasks" }, - { label: "Events", value: "events" }, - { label: "Code", value: "code" }, -]; - -const MODAL = "modal"; - -export const DagTabs = ({ dag }: { readonly dag?: DAGResponse }) => { - const [searchParams, setSearchParams] = useSearchParams(); - - const modal = searchParams.get(MODAL); - - const isGraphOpen = modal === "graph"; - const onClose = () => { - searchParams.delete(MODAL); - setSearchParams(searchParams); - }; - - const onOpen = () => { - searchParams.set(MODAL, "graph"); - setSearchParams(searchParams); - }; - - return ( - <> - - - Graph - - } - tabs={tabs} - /> - - - ); -}; diff --git a/airflow/ui/src/pages/DagsList/Run/Header.tsx b/airflow/ui/src/pages/DagsList/Run/Header.tsx index 6d5a5368e17f6..eeab7e73efa3f 100644 --- a/airflow/ui/src/pages/DagsList/Run/Header.tsx +++ b/airflow/ui/src/pages/DagsList/Run/Header.tsx @@ -28,50 +28,48 @@ import Time from "src/components/Time"; import { Status } from "src/components/ui"; export const Header = ({ dagRun }: { readonly dagRun: DAGRunResponse }) => ( - - - - - - - Run: - {dagRun.dag_run_id} - - {dagRun.state} - -
- - - - {dagRun.note === null || dagRun.note.length === 0 ? undefined : ( - - - - {dagRun.note} - + + + + + + Run: + {dagRun.dag_run_id} + + {dagRun.state} + +
- )} - - - - - {dagRun.run_type} - - - - - - - - {dayjs - .duration(dayjs(dagRun.end_date).diff(dagRun.start_date)) - .asSeconds() - .toFixed(2)} - s - - - + + + {dagRun.note === null || dagRun.note.length === 0 ? undefined : ( + + + + {dagRun.note} + + + )} + + + + + {dagRun.run_type} + + + + + + + + {dayjs + .duration(dayjs(dagRun.end_date).diff(dagRun.start_date)) + .asSeconds() + .toFixed(2)} + s + + ); diff --git a/airflow/ui/src/pages/DagsList/Run/Run.tsx b/airflow/ui/src/pages/DagsList/Run/Run.tsx index 5eb4034b4afad..cdc6b494a9bd8 100644 --- a/airflow/ui/src/pages/DagsList/Run/Run.tsx +++ b/airflow/ui/src/pages/DagsList/Run/Run.tsx @@ -16,32 +16,27 @@ * specific language governing permissions and limitations * under the License. */ -import { Box } from "@chakra-ui/react"; import { LiaSlashSolid } from "react-icons/lia"; -import { useParams, Link as RouterLink, Outlet } from "react-router-dom"; +import { useParams, Link as RouterLink } from "react-router-dom"; import { useDagRunServiceGetDagRun, useDagServiceGetDagDetails, } from "openapi/queries"; -import { ErrorAlert } from "src/components/ErrorAlert"; -import { Breadcrumb, ProgressBar } from "src/components/ui"; -import { OpenGroupsProvider } from "src/context/openGroups"; +import { Breadcrumb } from "src/components/ui"; +import { DetailsLayout } from "src/layouts/Details/DetailsLayout"; import { Header } from "./Header"; -import { RunTabs } from "./Tabs"; + +const tabs = [ + { label: "Task Instances", value: "" }, + { label: "Events", value: "events" }, + { label: "Code", value: "code" }, +]; export const Run = () => { const { dagId = "", runId = "" } = useParams(); - const { - data: dag, - error: dagError, - isLoading: isLoadingDag, - } = useDagServiceGetDagDetails({ - dagId, - }); - const { data: dagRun, error, @@ -51,29 +46,31 @@ export const Run = () => { dagRunId: runId, }); + const { + data: dag, + error: dagError, + isLoading: isLoadinDag, + } = useDagServiceGetDagDetails({ + dagId, + }); + return ( - - - }> - - Dags - - - {dagId} - - {runId} - - {dagRun === undefined ? undefined :
} - - - - - - - - + + }> + + Dags + + + {dagId} + + {runId} + + {dagRun === undefined ? undefined :
} + ); }; diff --git a/airflow/ui/src/pages/DagsList/Run/Tabs.tsx b/airflow/ui/src/pages/DagsList/Run/Tabs.tsx deleted file mode 100644 index d636a45190fd2..0000000000000 --- a/airflow/ui/src/pages/DagsList/Run/Tabs.tsx +++ /dev/null @@ -1,70 +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 { Button } from "@chakra-ui/react"; -import { useSearchParams } from "react-router-dom"; - -import type { DAGResponse } from "openapi/requests/types.gen"; -import { DagIcon } from "src/assets/DagIcon"; -import { DagVizModal } from "src/components/DagVizModal"; -import { NavTabs } from "src/components/NavTabs"; - -const tabs = [ - { label: "Task Instances", value: "" }, - { label: "Events", value: "events" }, - { label: "Code", value: "code" }, -]; - -const MODAL = "modal"; - -export const RunTabs = ({ dag }: { readonly dag?: DAGResponse }) => { - const [searchParams, setSearchParams] = useSearchParams(); - - const modal = searchParams.get(MODAL); - - const isGraphOpen = modal === "graph"; - const onClose = () => { - searchParams.delete(MODAL); - setSearchParams(searchParams); - }; - - const onOpen = () => { - searchParams.set(MODAL, "graph"); - setSearchParams(searchParams); - }; - - return ( - <> - - - Graph - - } - tabs={tabs} - /> - - - ); -}; diff --git a/airflow/ui/src/pages/DagsList/TaskInstance/Header.tsx b/airflow/ui/src/pages/DagsList/TaskInstance/Header.tsx new file mode 100644 index 0000000000000..ada029a85a9d6 --- /dev/null +++ b/airflow/ui/src/pages/DagsList/TaskInstance/Header.tsx @@ -0,0 +1,82 @@ +/*! + * 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, Heading, HStack, SimpleGrid, Text } from "@chakra-ui/react"; +import dayjs from "dayjs"; +import { MdOutlineModeComment, MdOutlineTask } from "react-icons/md"; + +import type { TaskInstanceResponse } from "openapi/requests/types.gen"; +import { Stat } from "src/components/Stat"; +import Time from "src/components/Time"; +import { Status } from "src/components/ui"; + +export const Header = ({ + taskInstance, +}: { + readonly taskInstance: TaskInstanceResponse; +}) => ( + + + + + + Task Instance: + {taskInstance.task_display_name}{" "} + + + {taskInstance.state} + + +
+ + + + {taskInstance.note === null || + taskInstance.note.length === 0 ? undefined : ( + + + + {taskInstance.note} + + + )} + + {taskInstance.operator} + {taskInstance.map_index > -1 ? ( + {taskInstance.map_index} + ) : undefined} + {taskInstance.try_number > 1 ? ( + {taskInstance.try_number} + ) : undefined} + + + + + + {dayjs + .duration(dayjs(taskInstance.end_date).diff(taskInstance.start_date)) + .asSeconds() + .toFixed(2)} + s + + + +); diff --git a/airflow/ui/src/pages/DagsList/TaskInstance/TaskInstance.tsx b/airflow/ui/src/pages/DagsList/TaskInstance/TaskInstance.tsx index eb45f9c48c0b9..bdaa4a4d95e7c 100644 --- a/airflow/ui/src/pages/DagsList/TaskInstance/TaskInstance.tsx +++ b/airflow/ui/src/pages/DagsList/TaskInstance/TaskInstance.tsx @@ -19,23 +19,66 @@ import { LiaSlashSolid } from "react-icons/lia"; import { useParams, Link as RouterLink } from "react-router-dom"; +import { + useDagServiceGetDagDetails, + useTaskInstanceServiceGetTaskInstance, +} from "openapi/queries"; import { Breadcrumb } from "src/components/ui"; +import { DetailsLayout } from "src/layouts/Details/DetailsLayout"; + +import { Header } from "./Header"; + +const tabs = [ + { label: "Logs", value: "" }, + { label: "Events", value: "events" }, + { label: "XCom", value: "xcom" }, + { label: "Code", value: "code" }, + { label: "Details", value: "details" }, +]; export const TaskInstance = () => { - const { dagId, runId, taskId } = useParams(); + const { dagId = "", runId = "", taskId = "" } = useParams(); + + const { + data: taskInstance, + error, + isLoading, + } = useTaskInstanceServiceGetTaskInstance({ + dagId, + dagRunId: runId, + taskId, + }); + + const { + data: dag, + error: dagError, + isLoading: isDagLoading, + } = useDagServiceGetDagDetails({ + dagId, + }); return ( - }> - - Dags - - - {dagId} - - - {runId} - - {taskId} - + + }> + + Dags + + + {dagId} + + + {runId} + + {taskId} + + {taskInstance === undefined ? undefined : ( +
+ )} + ); }; diff --git a/airflow/ui/src/pages/Events/Events.tsx b/airflow/ui/src/pages/Events/Events.tsx index 050ab9c7cd6bb..60663aefec7d1 100644 --- a/airflow/ui/src/pages/Events/Events.tsx +++ b/airflow/ui/src/pages/Events/Events.tsx @@ -28,8 +28,9 @@ import { ErrorAlert } from "src/components/ErrorAlert"; import Time from "src/components/Time"; const eventsColumn = ( - dagId: string | undefined, - runId: string | undefined, + dagId?: string, + runId?: string, + taskId?: string, ): Array> => [ { accessorKey: "when", @@ -64,14 +65,18 @@ const eventsColumn = ( }, }, ]), - { - accessorKey: "task_id", - enableSorting: true, - header: "Task ID", - meta: { - skeletonWidth: 10, - }, - }, + ...(Boolean(taskId) + ? [] + : [ + { + accessorKey: "task_id", + enableSorting: true, + header: "Task ID", + meta: { + skeletonWidth: 10, + }, + }, + ]), { accessorKey: "map_index", enableSorting: false, @@ -107,7 +112,7 @@ const eventsColumn = ( ]; export const Events = () => { - const { dagId, runId } = useParams(); + const { dagId, runId, taskId } = useParams(); const { setTableURLState, tableURLState } = useTableURLState({ sorting: [{ desc: true, id: "when" }], }); @@ -133,7 +138,7 @@ export const Events = () => { Logs
, index: true }, + { element: , path: "events" }, + { element:
Xcom
, path: "xcom" }, + { element: , path: "code" }, + { element:
Details
, path: "details" }, + ], element: , path: "dags/:dagId/runs/:runId/tasks/:taskId", },