This is an automated email from the ASF dual-hosted git repository.
bbovenzi 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 e5452b75bbb Add global runs and instances views (#46661)
e5452b75bbb is described below
commit e5452b75bbb4b40ed8f56b33d8f0413c73c3bcfc
Author: Brent Bovenzi <[email protected]>
AuthorDate: Wed Feb 12 12:34:14 2025 -0500
Add global runs and instances views (#46661)
* Add global runs and instances table views
* Remove old instances component
* Simplify Tabs component
* Rename Instance to Task Instance
* Fix runs url
---
.../Dag/Runs/index.ts => layouts/DagsLayout.tsx} | 17 +-
airflow/ui/src/layouts/Details/DetailsLayout.tsx | 31 +++-
airflow/ui/src/layouts/Details/NavTabs.tsx | 38 +----
.../src/pages/{Dag/Runs/Runs.tsx => DagRuns.tsx} | 39 +++--
airflow/ui/src/pages/DagsList/DagsList.tsx | 5 +-
airflow/ui/src/pages/Task/Instances.tsx | 186 ---------------------
airflow/ui/src/pages/Task/index.ts | 1 -
airflow/ui/src/pages/{Run => }/TaskInstances.tsx | 79 ++++++---
airflow/ui/src/router.tsx | 33 +++-
9 files changed, 169 insertions(+), 260 deletions(-)
diff --git a/airflow/ui/src/pages/Dag/Runs/index.ts
b/airflow/ui/src/layouts/DagsLayout.tsx
similarity index 66%
rename from airflow/ui/src/pages/Dag/Runs/index.ts
rename to airflow/ui/src/layouts/DagsLayout.tsx
index 04ea8727764..331fd77e68f 100644
--- a/airflow/ui/src/pages/Dag/Runs/index.ts
+++ b/airflow/ui/src/layouts/DagsLayout.tsx
@@ -16,5 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
+import { Box } from "@chakra-ui/react";
+import type { PropsWithChildren } from "react";
-export * from "./Runs";
+import { NavTabs } from "./Details/NavTabs";
+
+const tabs = [
+ { label: "Dags", value: "/dags" },
+ { label: "Runs", value: "/dag_runs" },
+ { label: "Task Instances", value: "/task_instances" },
+];
+
+export const DagsLayout = ({ children }: PropsWithChildren) => (
+ <Box>
+ <NavTabs tabs={tabs} />
+ {children}
+ </Box>
+);
diff --git a/airflow/ui/src/layouts/Details/DetailsLayout.tsx
b/airflow/ui/src/layouts/Details/DetailsLayout.tsx
index ec6cb3a5e8a..04402f5e35f 100644
--- a/airflow/ui/src/layouts/Details/DetailsLayout.tsx
+++ b/airflow/ui/src/layouts/Details/DetailsLayout.tsx
@@ -18,10 +18,12 @@
*/
import { Box, Button, HStack } from "@chakra-ui/react";
import type { PropsWithChildren } from "react";
-import { FiChevronsLeft } from "react-icons/fi";
+import { FaChartGantt } from "react-icons/fa6";
+import { FiChevronsLeft, FiGrid } from "react-icons/fi";
import { Outlet, Link as RouterLink, useParams, useSearchParams } from
"react-router-dom";
import type { DAGResponse } from "openapi/requests/types.gen";
+import { DagIcon } from "src/assets/DagIcon";
import { ErrorAlert } from "src/components/ErrorAlert";
import { SearchDagsButton } from "src/components/SearchDags";
import { ProgressBar } from "src/components/ui";
@@ -67,7 +69,32 @@ export const DetailsLayout = ({ children, dag, error,
isLoading, tabs }: Props)
{isModalOpen ? undefined : children}
<ErrorAlert error={error} />
<ProgressBar size="xs" visibility={isLoading ? "visible" : "hidden"} />
- <NavTabs tabs={tabs} />
+ <NavTabs
+ keepSearch
+ rightButtons={
+ <>
+ <Button asChild colorPalette="blue" variant="ghost">
+ <RouterLink to={{ search:
`${searchParams.toString()}&modal=gantt` }}>
+ <FaChartGantt height={5} width={5} />
+ Gantt
+ </RouterLink>
+ </Button>
+ <Button asChild colorPalette="blue" variant="ghost">
+ <RouterLink to={{ search:
`${searchParams.toString()}&modal=grid` }}>
+ <FiGrid height={5} width={5} />
+ Grid
+ </RouterLink>
+ </Button>
+ <Button asChild colorPalette="blue" variant="ghost">
+ <RouterLink to={{ search:
`${searchParams.toString()}&modal=graph` }}>
+ <DagIcon height={5} width={5} />
+ Graph
+ </RouterLink>
+ </Button>
+ </>
+ }
+ tabs={tabs}
+ />
<DagVizModal
dagDisplayName={dag?.dag_display_name}
dagId={dag?.dag_id}
diff --git a/airflow/ui/src/layouts/Details/NavTabs.tsx
b/airflow/ui/src/layouts/Details/NavTabs.tsx
index cb0234a31d3..55d62c72da5 100644
--- a/airflow/ui/src/layouts/Details/NavTabs.tsx
+++ b/airflow/ui/src/layouts/Details/NavTabs.tsx
@@ -16,22 +16,21 @@
* specific language governing permissions and limitations
* under the License.
*/
-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, useSearchParams } from
"react-router-dom";
-
-import { DagIcon } from "src/assets/DagIcon";
+import { Center, Flex } from "@chakra-ui/react";
+import type { ReactNode } from "react";
+import { NavLink, useSearchParams } from "react-router-dom";
type Props = {
+ readonly keepSearch?: boolean;
+ readonly rightButtons?: ReactNode;
readonly tabs: Array<{ label: string; value: string }>;
};
-export const NavTabs = ({ tabs }: Props) => {
+export const NavTabs = ({ keepSearch, rightButtons, tabs }: Props) => {
const [searchParams] = useSearchParams();
return (
- <Flex alignItems="center" borderBottomWidth={1}
justifyContent="space-between">
+ <Flex alignItems="center" borderBottomWidth={1}
justifyContent="space-between" mb={2}>
<Flex>
{tabs.map(({ label, value }) => (
<NavLink
@@ -40,7 +39,7 @@ export const NavTabs = ({ tabs }: Props) => {
to={{
pathname: value,
// Preserve search params when navigating
- search: searchParams.toString(),
+ search: keepSearch ? searchParams.toString() : undefined,
}}
>
{({ isActive }) => (
@@ -61,26 +60,7 @@ export const NavTabs = ({ tabs }: Props) => {
</NavLink>
))}
</Flex>
- <Flex alignSelf="flex-end">
- <Button asChild colorPalette="blue" variant="ghost">
- <RouterLink to={{ search: `${searchParams.toString()}&modal=gantt`
}}>
- <FaChartGantt height={5} width={5} />
- Gantt
- </RouterLink>
- </Button>
- <Button asChild colorPalette="blue" variant="ghost">
- <RouterLink to={{ search: `${searchParams.toString()}&modal=grid` }}>
- <FiGrid height={5} width={5} />
- Grid
- </RouterLink>
- </Button>
- <Button asChild colorPalette="blue" variant="ghost">
- <RouterLink to={{ search: `${searchParams.toString()}&modal=graph`
}}>
- <DagIcon height={5} width={5} />
- Graph
- </RouterLink>
- </Button>
- </Flex>
+ <Flex alignSelf="flex-end">{rightButtons}</Flex>
</Flex>
);
};
diff --git a/airflow/ui/src/pages/Dag/Runs/Runs.tsx
b/airflow/ui/src/pages/DagRuns.tsx
similarity index 85%
rename from airflow/ui/src/pages/Dag/Runs/Runs.tsx
rename to airflow/ui/src/pages/DagRuns.tsx
index 36b6195eeea..752d1de5e47 100644
--- a/airflow/ui/src/pages/Dag/Runs/Runs.tsx
+++ b/airflow/ui/src/pages/DagRuns.tsx
@@ -16,10 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Box, Flex, HStack, Link, type SelectValueChangeDetails, Text } from
"@chakra-ui/react";
+import { Flex, HStack, Link, type SelectValueChangeDetails, Text } from
"@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import { useCallback } from "react";
-import { useParams, Link as RouterLink, useSearchParams } from
"react-router-dom";
+import { Link as RouterLink, useParams, useSearchParams } from
"react-router-dom";
import { useDagRunServiceGetDagRuns } from "openapi/queries";
import type { DAGRunResponse, DagRunState } from "openapi/requests/types.gen";
@@ -32,13 +32,29 @@ import { RunTypeIcon } from "src/components/RunTypeIcon";
import { StateBadge } from "src/components/StateBadge";
import Time from "src/components/Time";
import { Select } from "src/components/ui";
-import { taskInstanceStateOptions as stateOptions } from
"src/constants/stateOptions";
+import { dagRunStateOptions as stateOptions } from
"src/constants/stateOptions";
import { capitalize, getDuration, useAutoRefresh, isStatePending } from
"src/utils";
-const columns: Array<ColumnDef<DAGRunResponse>> = [
+type DagRunRow = { row: { original: DAGRunResponse } };
+
+const runColumns = (dagId?: string): Array<ColumnDef<DAGRunResponse>> => [
+ ...(Boolean(dagId)
+ ? []
+ : [
+ {
+ accessorKey: "dag_id",
+ cell: ({ row: { original } }: DagRunRow) => (
+ <Link asChild color="fg.info" fontWeight="bold">
+ <RouterLink
to={`/dags/${original.dag_id}`}>{original.dag_id}</RouterLink>
+ </Link>
+ ),
+ enableSorting: false,
+ header: "Dag ID",
+ },
+ ]),
{
accessorKey: "run_id",
- cell: ({ row: { original } }) => (
+ cell: ({ row: { original } }: DagRunRow) => (
<Link asChild color="fg.info" fontWeight="bold">
<RouterLink
to={`/dags/${original.dag_id}/runs/${original.dag_run_id}`}>
{original.dag_run_id}
@@ -100,9 +116,8 @@ const columns: Array<ColumnDef<DAGRunResponse>> = [
const STATE_PARAM = "state";
-export const Runs = () => {
+export const DagRuns = () => {
const { dagId } = useParams();
-
const [searchParams, setSearchParams] = useSearchParams();
const { setTableURLState, tableURLState } = useTableURLState();
@@ -112,11 +127,11 @@ export const Runs = () => {
const filteredState = searchParams.get(STATE_PARAM);
- const refetchInterval = useAutoRefresh({ dagId });
+ const refetchInterval = useAutoRefresh({});
const { data, error, isLoading } = useDagRunServiceGetDagRuns(
{
- dagId: dagId ?? "~",
+ dagId: "~",
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
orderBy,
@@ -149,7 +164,7 @@ export const Runs = () => {
);
return (
- <Box pt={4}>
+ <>
<Flex>
<Select.Root
collection={stateOptions}
@@ -182,7 +197,7 @@ export const Runs = () => {
</Select.Root>
</Flex>
<DataTable
- columns={columns}
+ columns={runColumns(dagId)}
data={data?.dag_runs ?? []}
errorMessage={<ErrorAlert error={error} />}
initialState={tableURLState}
@@ -191,6 +206,6 @@ export const Runs = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
- </Box>
+ </>
);
};
diff --git a/airflow/ui/src/pages/DagsList/DagsList.tsx
b/airflow/ui/src/pages/DagsList/DagsList.tsx
index c8c32b74e8e..31b5eb04a46 100644
--- a/airflow/ui/src/pages/DagsList/DagsList.tsx
+++ b/airflow/ui/src/pages/DagsList/DagsList.tsx
@@ -41,6 +41,7 @@ import { SearchBar } from "src/components/SearchBar";
import { TogglePause } from "src/components/TogglePause";
import TriggerDAGButton from "src/components/TriggerDag/TriggerDAGButton";
import { SearchParamsKeys, type SearchParamsKeysType } from
"src/constants/searchParams";
+import { DagsLayout } from "src/layouts/DagsLayout";
import { useConfig } from "src/queries/useConfig";
import { useDags } from "src/queries/useDags";
import { pluralize } from "src/utils";
@@ -214,7 +215,7 @@ export const DagsList = () => {
);
return (
- <>
+ <DagsLayout>
<VStack alignItems="none">
<SearchBar
buttonProps={{ disabled: true }}
@@ -251,6 +252,6 @@ export const DagsList = () => {
total={data.total_entries}
/>
</Box>
- </>
+ </DagsLayout>
);
};
diff --git a/airflow/ui/src/pages/Task/Instances.tsx
b/airflow/ui/src/pages/Task/Instances.tsx
deleted file mode 100644
index 912c588c931..00000000000
--- a/airflow/ui/src/pages/Task/Instances.tsx
+++ /dev/null
@@ -1,186 +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, HStack, Link, type SelectValueChangeDetails } from
"@chakra-ui/react";
-import type { ColumnDef } from "@tanstack/react-table";
-import { useCallback } from "react";
-import { Link as RouterLink, useParams, useSearchParams } from
"react-router-dom";
-
-import { useTaskInstanceServiceGetTaskInstances, useTaskServiceGetTask } from
"openapi/queries";
-import type { TaskInstanceResponse, TaskInstanceState } from
"openapi/requests/types.gen";
-import { DataTable } from "src/components/DataTable";
-import { useTableURLState } from "src/components/DataTable/useTableUrlState";
-import { ErrorAlert } from "src/components/ErrorAlert";
-import { StateBadge } from "src/components/StateBadge";
-import Time from "src/components/Time";
-import { Select } from "src/components/ui";
-import { taskInstanceStateOptions as stateOptions } from
"src/constants/stateOptions";
-import { capitalize, getDuration } from "src/utils";
-import { getTaskInstanceLink } from "src/utils/links";
-
-const columns = (isMapped?: boolean): Array<ColumnDef<TaskInstanceResponse>>
=> [
- {
- accessorKey: "dag_run_id",
- cell: ({ row: { original } }) => (
- <Link asChild color="fg.info" fontWeight="bold">
- <RouterLink
to={getTaskInstanceLink(original)}>{original.dag_run_id}</RouterLink>
- </Link>
- ),
- enableSorting: false,
- header: "Dag Run ID",
- },
- {
- accessorKey: "state",
- cell: ({
- row: {
- original: { state },
- },
- }) => <StateBadge state={state}>{state}</StateBadge>,
- header: () => "State",
- },
- {
- accessorKey: "start_date",
- cell: ({ row: { original } }) => <Time datetime={original.start_date} />,
- header: "Start Date",
- },
- {
- accessorKey: "end_date",
- cell: ({ row: { original } }) => <Time datetime={original.end_date} />,
- header: "End Date",
- },
- ...(isMapped
- ? [
- {
- accessorFn: (row: TaskInstanceResponse) => row.rendered_map_index ??
row.map_index,
- header: "Map Index",
- },
- ]
- : []),
- {
- accessorKey: "try_number",
- enableSorting: false,
- header: "Try Number",
- },
- {
- cell: ({ row: { original } }) => `${getDuration(original.start_date,
original.end_date)}s`,
- header: "Duration",
- },
-];
-
-const STATE_PARAM = "state";
-
-export const Instances = () => {
- const { dagId = "", taskId } = useParams();
- const [searchParams, setSearchParams] = useSearchParams();
- const { setTableURLState, tableURLState } = useTableURLState();
- const { pagination, sorting } = tableURLState;
- const [sort] = sorting;
- const orderBy = sort ? `${sort.desc ? "-" : ""}${sort.id}` : "-start_date";
- const filteredState = searchParams.getAll(STATE_PARAM);
- const hasFilteredState = filteredState.length > 0;
-
- const { data: task, error: taskError, isLoading: isTaskLoading } =
useTaskServiceGetTask({ dagId, taskId });
-
- const handleStateChange = useCallback(
- ({ value }: SelectValueChangeDetails<string>) => {
- const [val, ...rest] = value;
-
- if ((val === undefined || val === "all") && rest.length === 0) {
- searchParams.delete(STATE_PARAM);
- } else {
- searchParams.delete(STATE_PARAM);
- value.filter((state) => state !== "all").map((state) =>
searchParams.append(STATE_PARAM, state));
- }
- setTableURLState({
- pagination: { ...pagination, pageIndex: 0 },
- sorting,
- });
- setSearchParams(searchParams);
- },
- [pagination, searchParams, setSearchParams, setTableURLState, sorting],
- );
-
- const { data, error, isFetching, isLoading } =
useTaskInstanceServiceGetTaskInstances({
- dagId,
- dagRunId: "~",
- limit: pagination.pageSize,
- offset: pagination.pageIndex * pagination.pageSize,
- orderBy,
- state: hasFilteredState ? filteredState : undefined,
- taskId,
- });
-
- return (
- <Box pt={4}>
- <Flex>
- <Select.Root
- collection={stateOptions}
- maxW="250px"
- multiple
- onValueChange={handleStateChange}
- value={hasFilteredState ? filteredState : ["all"]}
- >
- <Select.Trigger
- {...(hasFilteredState ? { clearable: true } : {})}
- colorPalette="blue"
- isActive={Boolean(filteredState)}
- >
- <Select.ValueText>
- {() =>
- hasFilteredState ? (
- <HStack gap="10px">
- {filteredState.map((state) => (
- <StateBadge key={state} state={state as
TaskInstanceState}>
- {state === "none" ? "No Status" : capitalize(state)}
- </StateBadge>
- ))}
- </HStack>
- ) : (
- "All States"
- )
- }
- </Select.ValueText>
- </Select.Trigger>
- <Select.Content>
- {stateOptions.items.map((option) => (
- <Select.Item item={option} key={option.label}>
- {option.value === "all" ? (
- option.label
- ) : (
- <StateBadge state={option.value as
TaskInstanceState}>{option.label}</StateBadge>
- )}
- </Select.Item>
- ))}
- </Select.Content>
- </Select.Root>
- </Flex>
-
- <DataTable
- columns={columns(Boolean(task?.is_mapped))}
- data={data?.task_instances ?? []}
- errorMessage={<ErrorAlert error={error ?? taskError} />}
- initialState={tableURLState}
- isFetching={isFetching}
- isLoading={isLoading || isTaskLoading}
- modelName="Task Instance"
- onStateChange={setTableURLState}
- total={data?.total_entries}
- />
- </Box>
- );
-};
diff --git a/airflow/ui/src/pages/Task/index.ts
b/airflow/ui/src/pages/Task/index.ts
index 99691b18e52..667b7b1d114 100644
--- a/airflow/ui/src/pages/Task/index.ts
+++ b/airflow/ui/src/pages/Task/index.ts
@@ -18,4 +18,3 @@
*/
export * from "./Task";
-export * from "./Instances";
diff --git a/airflow/ui/src/pages/Run/TaskInstances.tsx
b/airflow/ui/src/pages/TaskInstances.tsx
similarity index 80%
rename from airflow/ui/src/pages/Run/TaskInstances.tsx
rename to airflow/ui/src/pages/TaskInstances.tsx
index f05a83e8c56..2e67334f730 100644
--- a/airflow/ui/src/pages/Run/TaskInstances.tsx
+++ b/airflow/ui/src/pages/TaskInstances.tsx
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { Box, Flex, Link, HStack, type SelectValueChangeDetails } from
"@chakra-ui/react";
+import { Flex, Link, HStack, type SelectValueChangeDetails } from
"@chakra-ui/react";
import type { ColumnDef } from "@tanstack/react-table";
import { useCallback, useState } from "react";
import { Link as RouterLink, useParams, useSearchParams } from
"react-router-dom";
@@ -37,17 +37,57 @@ import { taskInstanceStateOptions as stateOptions } from
"src/constants/stateOpt
import { capitalize, getDuration, useAutoRefresh, isStatePending } from
"src/utils";
import { getTaskInstanceLink } from "src/utils/links";
-const columns: Array<ColumnDef<TaskInstanceResponse>> = [
- {
- accessorKey: "task_display_name",
- cell: ({ row: { original } }) => (
- <Link asChild color="fg.info" fontWeight="bold">
- <RouterLink
to={getTaskInstanceLink(original)}>{original.task_display_name}</RouterLink>
- </Link>
- ),
- enableSorting: false,
- header: "Task ID",
- },
+type TaskInstanceRow = { row: { original: TaskInstanceResponse } };
+
+const taskInstanceColumns = (
+ dagId?: string,
+ runId?: string,
+ taskId?: string,
+): Array<ColumnDef<TaskInstanceResponse>> => [
+ ...(Boolean(dagId)
+ ? []
+ : [
+ {
+ accessorKey: "dag_id",
+ cell: ({ row: { original } }: TaskInstanceRow) => (
+ <Link asChild color="fg.info" fontWeight="bold">
+ <RouterLink
to={`/dags/${original.dag_id}`}>{original.dag_id}</RouterLink>
+ </Link>
+ ),
+ enableSorting: false,
+ header: "Dag ID",
+ },
+ ]),
+ ...(Boolean(runId)
+ ? []
+ : [
+ {
+ accessorKey: "run_id",
+ cell: ({ row: { original } }: TaskInstanceRow) => (
+ <Link asChild color="fg.info" fontWeight="bold">
+ <RouterLink
to={`/dags/${original.dag_id}/runs/${original.dag_run_id}`}>
+ {original.dag_run_id}
+ </RouterLink>
+ </Link>
+ ),
+ enableSorting: false,
+ header: "Run ID",
+ },
+ ]),
+ ...(Boolean(taskId)
+ ? []
+ : [
+ {
+ accessorKey: "task_display_name",
+ cell: ({ row: { original } }: TaskInstanceRow) => (
+ <Link asChild color="fg.info" fontWeight="bold">
+ <RouterLink
to={getTaskInstanceLink(original)}>{original.task_display_name}</RouterLink>
+ </Link>
+ ),
+ enableSorting: false,
+ header: "Task ID",
+ },
+ ]),
{
accessorKey: "state",
cell: ({
@@ -106,7 +146,7 @@ const columns: Array<ColumnDef<TaskInstanceResponse>> = [
const STATE_PARAM = "state";
export const TaskInstances = () => {
- const { dagId = "", runId = "" } = useParams();
+ const { dagId, runId, taskId } = useParams();
const [searchParams, setSearchParams] = useSearchParams();
const { setTableURLState, tableURLState } = useTableURLState();
const { pagination, sorting } = tableURLState;
@@ -153,17 +193,18 @@ export const TaskInstances = () => {
setSearchParams(searchParams);
};
- const refetchInterval = useAutoRefresh({ dagId });
+ const refetchInterval = useAutoRefresh({});
const { data, error, isLoading } = useTaskInstanceServiceGetTaskInstances(
{
- dagId,
- dagRunId: runId,
+ dagId: dagId ?? "~",
+ dagRunId: runId ?? "~",
limit: pagination.pageSize,
offset: pagination.pageIndex * pagination.pageSize,
orderBy,
state: hasFilteredState ? filteredState : undefined,
taskDisplayNamePattern: Boolean(taskDisplayNamePattern) ?
taskDisplayNamePattern : undefined,
+ taskId: taskId ?? undefined,
},
undefined,
{
@@ -174,7 +215,7 @@ export const TaskInstances = () => {
);
return (
- <Box pt={4}>
+ <>
<HStack>
<Select.Root
collection={stateOptions}
@@ -225,7 +266,7 @@ export const TaskInstances = () => {
/>
</HStack>
<DataTable
- columns={columns}
+ columns={taskInstanceColumns(dagId, runId, taskId)}
data={data?.task_instances ?? []}
errorMessage={<ErrorAlert error={error} />}
initialState={tableURLState}
@@ -234,6 +275,6 @@ export const TaskInstances = () => {
onStateChange={setTableURLState}
total={data?.total_entries}
/>
- </Box>
+ </>
);
};
diff --git a/airflow/ui/src/router.tsx b/airflow/ui/src/router.tsx
index 0aa4b146c7b..bd18bca140d 100644
--- a/airflow/ui/src/router.tsx
+++ b/airflow/ui/src/router.tsx
@@ -22,27 +22,28 @@ import { createBrowserRouter } from "react-router-dom";
import { UseConfigServiceGetConfigsKeyFn } from "openapi/queries";
import { ConfigService } from "openapi/requests/services.gen";
import { BaseLayout } from "src/layouts/BaseLayout";
+import { DagsLayout } from "src/layouts/DagsLayout";
+import { AssetsList } from "src/pages/AssetsList";
import { Dag } from "src/pages/Dag";
import { Code } from "src/pages/Dag/Code";
import { Overview } from "src/pages/Dag/Overview";
-import { Runs } from "src/pages/Dag/Runs";
import { Tasks } from "src/pages/Dag/Tasks";
+import { DagRuns } from "src/pages/DagRuns";
import { DagsList } from "src/pages/DagsList";
import { Dashboard } from "src/pages/Dashboard";
import { ErrorPage } from "src/pages/Error";
import { Events } from "src/pages/Events";
+import { Pools } from "src/pages/Pools";
import { Providers } from "src/pages/Providers";
import { Run } from "src/pages/Run";
import { Details as DagRunDetails } from "src/pages/Run/Details";
-import { TaskInstances } from "src/pages/Run/TaskInstances";
-import { Task, Instances } from "src/pages/Task";
+import { Task } from "src/pages/Task";
import { TaskInstance, Logs } from "src/pages/TaskInstance";
import { Details } from "src/pages/TaskInstance/Details";
+import { TaskInstances } from "src/pages/TaskInstances";
+import { Variables } from "src/pages/Variables";
import { XCom } from "src/pages/XCom";
-import { AssetsList } from "./pages/AssetsList";
-import { Pools } from "./pages/Pools";
-import { Variables } from "./pages/Variables";
import { queryClient } from "./queryClient";
export const routerConfig = [
@@ -56,6 +57,22 @@ export const routerConfig = [
element: <DagsList />,
path: "dags",
},
+ {
+ element: (
+ <DagsLayout>
+ <DagRuns />
+ </DagsLayout>
+ ),
+ path: "dag_runs",
+ },
+ {
+ element: (
+ <DagsLayout>
+ <TaskInstances />
+ </DagsLayout>
+ ),
+ path: "task_instances",
+ },
{
element: <AssetsList />,
path: "assets",
@@ -83,7 +100,7 @@ export const routerConfig = [
{
children: [
{ element: <Overview />, index: true },
- { element: <Runs />, path: "runs" },
+ { element: <DagRuns />, path: "runs" },
{ element: <Tasks />, path: "tasks" },
{ element: <Events />, path: "events" },
{ element: <Code />, path: "code" },
@@ -114,7 +131,7 @@ export const routerConfig = [
},
{
children: [
- { element: <Instances />, index: true },
+ { element: <TaskInstances />, index: true },
{ element: <Events />, path: "events" },
],
element: <Task />,