This is an automated email from the ASF dual-hosted git repository. ephraimanierobi pushed a commit to branch v2-6-test in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 4ac3be81d2f636afd7a5a5f4196f8d32555da413 Author: Pierre Jeambrun <[email protected]> AuthorDate: Fri Apr 14 21:27:40 2023 +0200 Present affected task instances as table (#30633) (cherry picked from commit 90ee7639478bc8534164c4bbb05a1ccfb04272dd) --- airflow/www/static/js/api/useClearTaskDryRun.ts | 15 ++++++---- airflow/www/static/js/api/useMarkTaskDryRun.ts | 6 ++-- .../taskInstance/taskActions/ActionModal.tsx | 32 +++++++++++++++++----- airflow/www/static/js/types/index.ts | 17 +++++++----- airflow/www/views.py | 19 +++++++++---- 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/airflow/www/static/js/api/useClearTaskDryRun.ts b/airflow/www/static/js/api/useClearTaskDryRun.ts index cea46723f4..7f068a001f 100644 --- a/airflow/www/static/js/api/useClearTaskDryRun.ts +++ b/airflow/www/static/js/api/useClearTaskDryRun.ts @@ -19,6 +19,7 @@ import axios, { AxiosResponse } from "axios"; import { useQuery } from "react-query"; +import type { MinimalTaskInstance } from "src/types"; import URLSearchParamsWrapper from "src/utils/URLSearchParamWrapper"; import { getMetaValue } from "../utils"; @@ -91,11 +92,15 @@ const useClearTaskDryRun = ({ params.append("map_index", mi.toString()); }); - return axios.post<AxiosResponse, string[]>(clearUrl, params.toString(), { - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }); + return axios.post<AxiosResponse, MinimalTaskInstance[]>( + clearUrl, + params.toString(), + { + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + } + ); } ); diff --git a/airflow/www/static/js/api/useMarkTaskDryRun.ts b/airflow/www/static/js/api/useMarkTaskDryRun.ts index 8e872ed8ea..31bc278644 100644 --- a/airflow/www/static/js/api/useMarkTaskDryRun.ts +++ b/airflow/www/static/js/api/useMarkTaskDryRun.ts @@ -19,7 +19,7 @@ import axios, { AxiosResponse } from "axios"; import { useQuery } from "react-query"; -import type { TaskState } from "src/types"; +import type { TaskState, MinimalTaskInstance } from "src/types"; import URLSearchParamsWrapper from "src/utils/URLSearchParamWrapper"; import { getMetaValue } from "../utils"; @@ -74,7 +74,9 @@ const useMarkTaskDryRun = ({ mapIndexes.forEach((mi: number) => { params.append("map_index", mi.toString()); }); - return axios.get<AxiosResponse, string[]>(confirmUrl, { params }); + return axios.get<AxiosResponse, MinimalTaskInstance[]>(confirmUrl, { + params, + }); } ); diff --git a/airflow/www/static/js/dag/details/taskInstance/taskActions/ActionModal.tsx b/airflow/www/static/js/dag/details/taskInstance/taskActions/ActionModal.tsx index ef89681150..57128bacd1 100644 --- a/airflow/www/static/js/dag/details/taskInstance/taskActions/ActionModal.tsx +++ b/airflow/www/static/js/dag/details/taskInstance/taskActions/ActionModal.tsx @@ -35,18 +35,40 @@ import { AccordionPanel, AccordionItem, AccordionIcon, - Code, } from "@chakra-ui/react"; import { useContainerRef } from "src/context/containerRef"; +import { Table } from "src/components/Table"; +import type { MinimalTaskInstance } from "src/types"; interface Props extends ModalProps { - affectedTasks?: string[]; + affectedTasks?: MinimalTaskInstance[]; header: ReactNode | string; subheader?: ReactNode | string; submitButton: ReactNode; } +const columns = [ + { + Header: "Task name", + accessor: "taskId", + }, + { + Header: "Map Index", + accessor: "mapIndex", + }, + { + Header: "Run Id", + accessor: "runId", + }, +]; + +const AffectedTasksTable = ({ + affectedTasks, +}: { + affectedTasks: MinimalTaskInstance[]; +}) => <Table data={affectedTasks} columns={columns} />; + const ActionModal = ({ isOpen, onClose, @@ -87,11 +109,7 @@ const ActionModal = ({ </AccordionButton> <AccordionPanel> <Box maxHeight="400px" overflowY="auto"> - {(affectedTasks || []).map((ti) => ( - <Code width="100%" key={ti} fontSize="lg"> - {ti} - </Code> - ))} + <AffectedTasksTable affectedTasks={affectedTasks} /> </Box> </AccordionPanel> </AccordionItem> diff --git a/airflow/www/static/js/types/index.ts b/airflow/www/static/js/types/index.ts index 94e0e60526..8f4eb7d450 100644 --- a/airflow/www/static/js/types/index.ts +++ b/airflow/www/static/js/types/index.ts @@ -130,16 +130,19 @@ interface DatasetListItem extends API.Dataset { totalUpdates: number; } +type MinimalTaskInstance = Pick<TaskInstance, "taskId" | "mapIndex" | "runId">; + export type { + API, + MinimalTaskInstance, Dag, DagRun, - RunState, - TaskState, - TaskInstance, - Task, - DepNode, + DatasetListItem, DepEdge, - API, + DepNode, RunOrdering, - DatasetListItem, + RunState, + Task, + TaskInstance, + TaskState, }; diff --git a/airflow/www/views.py b/airflow/www/views.py index 62bde217ee..c6d1b612b3 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -1050,7 +1050,6 @@ class Airflow(AirflowBaseView): ) if conf.getboolean("webserver", "SHOW_RECENT_STATS_FOR_COMPLETED_RUNS", fallback=True): - last_dag_run = ( session.query(DagRun.dag_id, sqla.func.max(DagRun.execution_date).label("execution_date")) .join(DagModel, DagModel.dag_id == DagRun.dag_id) @@ -2122,7 +2121,12 @@ class Airflow(AirflowBaseView): if not details: return redirect_or_json(origin, "No task instances to clear", status="error", status_code=404) elif request.headers.get("Accept") == "application/json": - return htmlsafe_json_dumps(details, separators=(",", ":")) + if confirmed: + return htmlsafe_json_dumps(details, separators=(",", ":")) + return htmlsafe_json_dumps( + [{"task_id": ti.task_id, "map_index": ti.map_index, "run_id": ti.run_id} for ti in tis], + separators=(",", ":"), + ) return self.render_template( "airflow/confirm.html", endpoint=None, @@ -2528,8 +2532,13 @@ class Airflow(AirflowBaseView): ) if request.headers.get("Accept") == "application/json": - details = [str(t) for t in to_be_altered] - return htmlsafe_json_dumps(details, separators=(",", ":")) + return htmlsafe_json_dumps( + [ + {"task_id": ti.task_id, "map_index": ti.map_index, "run_id": ti.run_id} + for ti in to_be_altered + ], + separators=(",", ":"), + ) details = "\n".join(str(t) for t in to_be_altered) @@ -4475,7 +4484,6 @@ class ConnectionModelView(AirflowModelView): "warning", ) else: - dup_conn = Connection( new_conn_id, selected_conn.conn_type, @@ -5689,7 +5697,6 @@ class DagDependenciesView(AirflowBaseView): ) def _calculate_graph(self): - nodes_dict: dict[str, Any] = {} edge_tuples: set[dict[str, str]] = set()
