From 09bb7d52214547f17224c21f566e7c553f6ee2b2 Mon Sep 17 00:00:00 2001 From: linh Date: Mon, 16 Dec 2024 14:50:05 -0800 Subject: [PATCH 1/7] init Details.tsx. add try number selector --- airflow/ui/package.json | 3 +- airflow/ui/src/pages/Run/Details.tsx | 59 ++++++++++++++++++++++++++++ airflow/ui/src/router.tsx | 3 +- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 airflow/ui/src/pages/Run/Details.tsx diff --git a/airflow/ui/package.json b/airflow/ui/package.json index 728babb74f6a3..819b808ff8839 100644 --- a/airflow/ui/package.json +++ b/airflow/ui/package.json @@ -77,5 +77,6 @@ "vite-plugin-css-injected-by-js": "^3.5.2", "vitest": "^2.1.1", "web-worker": "^1.3.0" - } + }, + "packageManager": "pnpm@9.15.0+sha512.76e2379760a4328ec4415815bcd6628dee727af3779aaa4c914e3944156c4299921a89f976381ee107d41f12cfa4b66681ca9c718f0668fa0831ed4c6d8ba56c" } diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx new file mode 100644 index 0000000000000..32740e748f3e4 --- /dev/null +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -0,0 +1,59 @@ +/*! + * 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 dayjs from "dayjs"; +import { useParams } from "react-router-dom"; + +import { + useTaskInstanceServiceGetTaskInstance, + useTaskInstanceServiceGetTaskInstanceTryDetails, +} from "openapi/queries"; +import type { TaskInstanceResponse } from "openapi/requests/types.gen"; +import { ErrorAlert } from "src/components/ErrorAlert"; +import Time from "src/components/Time"; +import { Button, Status } from "src/components/ui"; + + +export const Details = () => { + const { dagId = "", runId = "", taskId = "" } = useParams(); + + const { data: taskInstance } = useTaskInstanceServiceGetTaskInstance({ + dagId, + dagRunId: runId, + taskId, + }); + + const finalTryNumber = taskInstance?.try_number ?? 1; + const tries = Array(finalTryNumber) + .fill(undefined) + .map((_, count) => count + 1); + + return ( + <> + Task Tries + {tries.map((key) => ( + + ))} + + ); +}; diff --git a/airflow/ui/src/router.tsx b/airflow/ui/src/router.tsx index d1f66c15e4cd6..95f2aa514b7a8 100644 --- a/airflow/ui/src/router.tsx +++ b/airflow/ui/src/router.tsx @@ -29,6 +29,7 @@ import { Dashboard } from "src/pages/Dashboard"; import { ErrorPage } from "src/pages/Error"; import { Events } from "src/pages/Events"; import { Run } from "src/pages/Run"; +import { Details } from "src/pages/Run/Details"; import { TaskInstances } from "src/pages/Run/TaskInstances"; import { Task, Instances } from "src/pages/Task"; import { TaskInstance } from "src/pages/TaskInstance"; @@ -86,7 +87,7 @@ export const router = createBrowserRouter( { element: , path: "events" }, { element: , path: "xcom" }, { element: , path: "code" }, - { element:
Details
, path: "details" }, + { element:
, path: "details" }, ], element: , path: "dags/:dagId/runs/:runId/tasks/:taskId", From 2515b0cf3e2facc79da3cc7dc47c1d06c069b1ba Mon Sep 17 00:00:00 2001 From: linh Date: Mon, 16 Dec 2024 15:56:18 -0800 Subject: [PATCH 2/7] render try selector with latest try --- airflow/ui/src/components/TrySelector.tsx | 0 airflow/ui/src/pages/Run/Details.tsx | 61 +++++++++++++++++------ 2 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 airflow/ui/src/components/TrySelector.tsx diff --git a/airflow/ui/src/components/TrySelector.tsx b/airflow/ui/src/components/TrySelector.tsx new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index 32740e748f3e4..d2d5503238165 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -16,19 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -import { Heading } from "@chakra-ui/react"; +import { Box, Flex, Heading } from "@chakra-ui/react"; import dayjs from "dayjs"; +import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; import { useTaskInstanceServiceGetTaskInstance, - useTaskInstanceServiceGetTaskInstanceTryDetails, + useTaskInstanceServiceGetTaskInstanceTries, } from "openapi/queries"; -import type { TaskInstanceResponse } from "openapi/requests/types.gen"; import { ErrorAlert } from "src/components/ErrorAlert"; import Time from "src/components/Time"; import { Button, Status } from "src/components/ui"; +// import TrySelector from "src/components/TrySelector"; export const Details = () => { const { dagId = "", runId = "", taskId = "" } = useParams(); @@ -40,20 +41,50 @@ export const Details = () => { }); const finalTryNumber = taskInstance?.try_number ?? 1; - const tries = Array(finalTryNumber) - .fill(undefined) - .map((_, count) => count + 1); + + const { data: taskInstanceTries } = + useTaskInstanceServiceGetTaskInstanceTries({ + dagId, + dagRunId: runId, + mapIndex: taskInstance?.map_index ?? -1, + taskId, + }); + + const [selectedTryNumber, setSelectedTryNumber] = useState( + finalTryNumber || 1, + ); + + // update state if the final try number changes + useEffect(() => { + if (finalTryNumber) { + setSelectedTryNumber(finalTryNumber); + } + }, [finalTryNumber]); + + const tryInstance = taskInstanceTries?.task_instances.find( + (ti) => ti.try_number === selectedTryNumber, + ); + + const instance = + selectedTryNumber !== finalTryNumber && finalTryNumber && finalTryNumber > 1 + ? tryInstance + : taskInstance; return ( - <> + Task Tries - {tries.map((key) => ( - - ))} - + + {taskInstanceTries?.task_instances.map((ti) => ( + + ))} + + ); }; From 584ae1ec6721a335d6a1d62e27d734dbea42188c Mon Sep 17 00:00:00 2001 From: linh Date: Mon, 16 Dec 2024 16:26:25 -0800 Subject: [PATCH 3/7] refactor to TrySelector.tsx --- airflow/ui/src/components/TrySelector.tsx | 71 +++++++++++++++++++++++ airflow/ui/src/pages/Run/Details.tsx | 25 ++++---- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/airflow/ui/src/components/TrySelector.tsx b/airflow/ui/src/components/TrySelector.tsx index e69de29bb2d1d..0bdc68e3b8028 100644 --- a/airflow/ui/src/components/TrySelector.tsx +++ b/airflow/ui/src/components/TrySelector.tsx @@ -0,0 +1,71 @@ +/*! + * 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 } from "@chakra-ui/react"; + +import { useTaskInstanceServiceGetTaskInstanceTries } from "openapi/queries"; +import type { TaskInstanceResponse } from "openapi/requests/types.gen"; +import { Button, Status } from "src/components/ui"; + +type Props = { + readonly onSelectTryNumber?: (tryNumber: number) => void; + readonly selectedTryNumber?: number; + readonly taskInstance?: TaskInstanceResponse; +}; + +export const TrySelector = ({ + onSelectTryNumber, + selectedTryNumber, + taskInstance, +}: Props) => { + const { + dag_id: dagId, + dag_run_id: dagRunId, + map_index: mapIndex, + task_id: taskId, + try_number: finalTryNumber, + } = taskInstance; + + const { data: taskInstanceTries } = + useTaskInstanceServiceGetTaskInstanceTries({ + dagId, + dagRunId, + mapIndex, + taskId, + }); + + return ( + + + Task Tries + + + {taskInstanceTries?.task_instances.map((ti) => ( + + ))} + + + ); +}; diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index d2d5503238165..f10f9c301333e 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -27,10 +27,9 @@ import { } from "openapi/queries"; import { ErrorAlert } from "src/components/ErrorAlert"; import Time from "src/components/Time"; +import { TrySelector } from "src/components/TrySelector"; import { Button, Status } from "src/components/ui"; -// import TrySelector from "src/components/TrySelector"; - export const Details = () => { const { dagId = "", runId = "", taskId = "" } = useParams(); @@ -70,21 +69,17 @@ export const Details = () => { ? tryInstance : taskInstance; + console.log(instance); + return ( - Task Tries - - {taskInstanceTries?.task_instances.map((ti) => ( - - ))} - + {Boolean(taskInstance) && ( + + )} ); }; From 5c638d7795cc569261b5ccec3aeea5887d31a384 Mon Sep 17 00:00:00 2001 From: linh Date: Wed, 18 Dec 2024 14:16:21 -0600 Subject: [PATCH 4/7] add tooltip to try selector --- airflow/ui/src/components/TrySelector.tsx | 35 +++++++++++++++++------ airflow/ui/src/pages/Run/Details.tsx | 5 +--- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/airflow/ui/src/components/TrySelector.tsx b/airflow/ui/src/components/TrySelector.tsx index 0bdc68e3b8028..5170c47f279d8 100644 --- a/airflow/ui/src/components/TrySelector.tsx +++ b/airflow/ui/src/components/TrySelector.tsx @@ -16,11 +16,12 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Flex, Heading } from "@chakra-ui/react"; +import { Box, Flex, Heading, Text } from "@chakra-ui/react"; +import dayjs from "dayjs"; import { useTaskInstanceServiceGetTaskInstanceTries } from "openapi/queries"; import type { TaskInstanceResponse } from "openapi/requests/types.gen"; -import { Button, Status } from "src/components/ui"; +import { Button, Status, Tooltip } from "src/components/ui"; type Props = { readonly onSelectTryNumber?: (tryNumber: number) => void; @@ -38,7 +39,6 @@ export const TrySelector = ({ dag_run_id: dagRunId, map_index: mapIndex, task_id: taskId, - try_number: finalTryNumber, } = taskInstance; const { data: taskInstanceTries } = @@ -56,14 +56,31 @@ export const TrySelector = ({ {taskInstanceTries?.task_instances.map((ti) => ( - + + ))} diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index f10f9c301333e..653c9f6fcbe51 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -25,10 +25,9 @@ import { useTaskInstanceServiceGetTaskInstance, useTaskInstanceServiceGetTaskInstanceTries, } from "openapi/queries"; -import { ErrorAlert } from "src/components/ErrorAlert"; import Time from "src/components/Time"; import { TrySelector } from "src/components/TrySelector"; -import { Button, Status } from "src/components/ui"; +import { Status } from "src/components/ui"; export const Details = () => { const { dagId = "", runId = "", taskId = "" } = useParams(); @@ -69,8 +68,6 @@ export const Details = () => { ? tryInstance : taskInstance; - console.log(instance); - return ( {Boolean(taskInstance) && ( From dd20303954a71204c9d78bcda66931c4c317f915 Mon Sep 17 00:00:00 2001 From: linh Date: Sun, 29 Dec 2024 18:02:23 -0600 Subject: [PATCH 5/7] update with TaskTrySelect.tsx --- airflow/ui/src/components/TrySelector.tsx | 88 ---------------------- airflow/ui/src/pages/Run/Details.tsx | 90 +++++++++++++++-------- 2 files changed, 59 insertions(+), 119 deletions(-) delete mode 100644 airflow/ui/src/components/TrySelector.tsx diff --git a/airflow/ui/src/components/TrySelector.tsx b/airflow/ui/src/components/TrySelector.tsx deleted file mode 100644 index 5170c47f279d8..0000000000000 --- a/airflow/ui/src/components/TrySelector.tsx +++ /dev/null @@ -1,88 +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, Heading, Text } from "@chakra-ui/react"; -import dayjs from "dayjs"; - -import { useTaskInstanceServiceGetTaskInstanceTries } from "openapi/queries"; -import type { TaskInstanceResponse } from "openapi/requests/types.gen"; -import { Button, Status, Tooltip } from "src/components/ui"; - -type Props = { - readonly onSelectTryNumber?: (tryNumber: number) => void; - readonly selectedTryNumber?: number; - readonly taskInstance?: TaskInstanceResponse; -}; - -export const TrySelector = ({ - onSelectTryNumber, - selectedTryNumber, - taskInstance, -}: Props) => { - const { - dag_id: dagId, - dag_run_id: dagRunId, - map_index: mapIndex, - task_id: taskId, - } = taskInstance; - - const { data: taskInstanceTries } = - useTaskInstanceServiceGetTaskInstanceTries({ - dagId, - dagRunId, - mapIndex, - taskId, - }); - - return ( - - - Task Tries - - - {taskInstanceTries?.task_instances.map((ti) => ( - - Status: {ti.state} - - Duration:{" "} - {`${dayjs.duration(dayjs(ti.end_date).diff(ti.start_date)).asSeconds().toFixed(2)}s`} - - - } - key={ti.try_number} - > - - - ))} - - - ); -}; diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index 653c9f6fcbe51..1ca2d565e75f9 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -16,67 +16,95 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Flex, Heading } from "@chakra-ui/react"; +import { Box, Button, Flex, Heading, HStack } from "@chakra-ui/react"; import dayjs from "dayjs"; import { useEffect, useState } from "react"; -import { useParams } from "react-router-dom"; +import { useParams, useSearchParams } from "react-router-dom"; import { + useTaskInstanceServiceGetMappedTaskInstance, useTaskInstanceServiceGetTaskInstance, useTaskInstanceServiceGetTaskInstanceTries, } from "openapi/queries"; +import { TaskTrySelect } from "src/components/TaskTrySelect"; import Time from "src/components/Time"; -import { TrySelector } from "src/components/TrySelector"; import { Status } from "src/components/ui"; +import { useConfig } from "src/queries/useConfig"; export const Details = () => { const { dagId = "", runId = "", taskId = "" } = useParams(); + const [searchParams, setSearchParams] = useSearchParams(); - const { data: taskInstance } = useTaskInstanceServiceGetTaskInstance({ + const mapIndexParam = searchParams.get("map_index"); + const tryNumberParam = searchParams.get("try_number"); + const mapIndex = parseInt(mapIndexParam ?? "-1", 10); + + const { + data: taskInstance, + error, + isLoading, + } = useTaskInstanceServiceGetMappedTaskInstance({ dagId, dagRunId: runId, + mapIndex, taskId, }); - const finalTryNumber = taskInstance?.try_number ?? 1; + const onSelectTryNumber = (newTryNumber: number) => { + if (newTryNumber === taskInstance?.try_number) { + searchParams.delete("try_number"); + } else { + searchParams.set("try_number", newTryNumber.toString()); + } + setSearchParams(searchParams); + }; + + const tryNumber = + tryNumberParam === null + ? taskInstance?.try_number + : parseInt(tryNumberParam, 10); + + const defaultWrap = Boolean(useConfig("default_wrap")); + + const [wrap, setWrap] = useState(defaultWrap); + + const toggleWrap = () => setWrap(!wrap); const { data: taskInstanceTries } = useTaskInstanceServiceGetTaskInstanceTries({ dagId, dagRunId: runId, - mapIndex: taskInstance?.map_index ?? -1, + mapIndex, taskId, }); - const [selectedTryNumber, setSelectedTryNumber] = useState( - finalTryNumber || 1, - ); - - // update state if the final try number changes - useEffect(() => { - if (finalTryNumber) { - setSelectedTryNumber(finalTryNumber); - } - }, [finalTryNumber]); - const tryInstance = taskInstanceTries?.task_instances.find( - (ti) => ti.try_number === selectedTryNumber, + (ti) => ti.try_number === tryNumber, ); - const instance = - selectedTryNumber !== finalTryNumber && finalTryNumber && finalTryNumber > 1 - ? tryInstance - : taskInstance; - return ( - - {Boolean(taskInstance) && ( - - )} + + + {taskInstance === undefined || + tryNumber === undefined || + taskInstance.try_number <= 1 ? ( +
+ ) : ( + + )} + + ); }; From 6644df7b3e196f43f6774390e2eb09374aec7ce2 Mon Sep 17 00:00:00 2001 From: linh Date: Sun, 29 Dec 2024 20:21:05 -0600 Subject: [PATCH 6/7] add table and populate fields --- airflow/ui/src/pages/Run/Details.tsx | 128 +++++++++++++++++++++++++-- 1 file changed, 123 insertions(+), 5 deletions(-) diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index 1ca2d565e75f9..82b181daa0eca 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -16,20 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Button, Flex, Heading, HStack } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import { useEffect, useState } from "react"; +import { Box, Button, Flex, HStack, Table } from "@chakra-ui/react"; +import { useState } from "react"; import { useParams, useSearchParams } from "react-router-dom"; import { useTaskInstanceServiceGetMappedTaskInstance, - useTaskInstanceServiceGetTaskInstance, useTaskInstanceServiceGetTaskInstanceTries, } from "openapi/queries"; import { TaskTrySelect } from "src/components/TaskTrySelect"; import Time from "src/components/Time"; -import { Status } from "src/components/ui"; +import { ClipboardRoot, ClipboardIconButton, Status } from "src/components/ui"; import { useConfig } from "src/queries/useConfig"; +import { getDuration } from "src/utils"; export const Details = () => { const { dagId = "", runId = "", taskId = "" } = useParams(); @@ -105,6 +104,125 @@ export const Details = () => { {wrap ? "Unwrap" : "Wrap"} + + + + Status + + + + {tryInstance?.state ?? "no status"} + + + + + Task ID + + + {tryInstance?.task_id} + + + + + + + + Run ID + + + {tryInstance?.dag_run_id} + + + + + + + + Map Index + {tryInstance?.map_index} + + + Operator + {tryInstance?.operator} + + + Duration + + {getDuration( + tryInstance?.start_date ?? null, + tryInstance?.end_date ?? null, + )} + s + + + + Started + + + + + Ended + + + + + Process ID (PID) + + + {tryInstance?.pid} + + + + + + + + Hostname + + + {tryInstance?.hostname} + + + + + + + + Pool + {tryInstance?.pool} + + + Pool Slots + {tryInstance?.pool_slots} + + + Executor + {tryInstance?.executor} + + + Executor Config + {tryInstance?.executor_config} + + + Unix Name + {tryInstance?.unixname} + + + Max Tries + {tryInstance?.max_tries} + + + Queue + {tryInstance?.queue} + + + Priority Weight + {tryInstance?.priority_weight} + + + ); }; From f56980ad3a44b4a5ed7449e3c6d4ec5a278bd677 Mon Sep 17 00:00:00 2001 From: linh Date: Thu, 2 Jan 2025 17:43:21 -0600 Subject: [PATCH 7/7] rebasing. remove wrap button. change query for fetching task instance try details. --- airflow/ui/src/pages/Run/Details.tsx | 71 ++++++++-------------------- 1 file changed, 20 insertions(+), 51 deletions(-) diff --git a/airflow/ui/src/pages/Run/Details.tsx b/airflow/ui/src/pages/Run/Details.tsx index 82b181daa0eca..441a1f1377dae 100644 --- a/airflow/ui/src/pages/Run/Details.tsx +++ b/airflow/ui/src/pages/Run/Details.tsx @@ -16,18 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import { Box, Button, Flex, HStack, Table } from "@chakra-ui/react"; -import { useState } from "react"; +import { Box, Flex, HStack, Table } from "@chakra-ui/react"; import { useParams, useSearchParams } from "react-router-dom"; import { useTaskInstanceServiceGetMappedTaskInstance, - useTaskInstanceServiceGetTaskInstanceTries, + useTaskInstanceServiceGetTaskInstanceTryDetails, } from "openapi/queries"; import { TaskTrySelect } from "src/components/TaskTrySelect"; import Time from "src/components/Time"; import { ClipboardRoot, ClipboardIconButton, Status } from "src/components/ui"; -import { useConfig } from "src/queries/useConfig"; import { getDuration } from "src/utils"; export const Details = () => { @@ -58,52 +56,27 @@ export const Details = () => { setSearchParams(searchParams); }; - const tryNumber = - tryNumberParam === null - ? taskInstance?.try_number - : parseInt(tryNumberParam, 10); + const tryNumber = tryNumberParam === null ? taskInstance?.try_number : parseInt(tryNumberParam, 10); - const defaultWrap = Boolean(useConfig("default_wrap")); - - const [wrap, setWrap] = useState(defaultWrap); - - const toggleWrap = () => setWrap(!wrap); - - const { data: taskInstanceTries } = - useTaskInstanceServiceGetTaskInstanceTries({ - dagId, - dagRunId: runId, - mapIndex, - taskId, - }); - - const tryInstance = taskInstanceTries?.task_instances.find( - (ti) => ti.try_number === tryNumber, - ); + const { data: tryInstance } = useTaskInstanceServiceGetTaskInstanceTryDetails({ + dagId, + dagRunId: runId, + mapIndex, + taskId, + taskTryNumber: tryNumber, + }); return ( - - {taskInstance === undefined || - tryNumber === undefined || - taskInstance.try_number <= 1 ? ( -
- ) : ( - - )} - - + {taskInstance === undefined || tryNumber === undefined || taskInstance.try_number <= 1 ? ( +
+ ) : ( + + )} @@ -148,11 +121,7 @@ export const Details = () => { Duration - {getDuration( - tryInstance?.start_date ?? null, - tryInstance?.end_date ?? null, - )} - s + {getDuration(tryInstance?.start_date ?? null, tryInstance?.end_date ?? null)}s