From e8abe05d0334f85f966feab940233d6fdfae4997 Mon Sep 17 00:00:00 2001 From: Brent Bovenzi Date: Tue, 9 Apr 2024 12:34:40 -0400 Subject: [PATCH 1/3] Fix dag run link params --- airflow/www/static/js/dag/useFilters.tsx | 1 + airflow/www/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/airflow/www/static/js/dag/useFilters.tsx b/airflow/www/static/js/dag/useFilters.tsx index a83598beb84da..5a1a49b68655f 100644 --- a/airflow/www/static/js/dag/useFilters.tsx +++ b/airflow/www/static/js/dag/useFilters.tsx @@ -182,6 +182,7 @@ const useFilters = (): FilterHookReturn => { searchParams.delete(BASE_DATE_PARAM); searchParams.delete(RUN_TYPE_PARAM); searchParams.delete(RUN_STATE_PARAM); + searchParams.delete(EXECUTION_DATE_PARAM); setSearchParams(searchParams); }; diff --git a/airflow/www/utils.py b/airflow/www/utils.py index d73bff9a64bb0..995833d6d651d 100644 --- a/airflow/www/utils.py +++ b/airflow/www/utils.py @@ -532,8 +532,8 @@ def dag_run_link(attr): """Generate a URL to the Graph view for a DagRun.""" dag_id = attr.get("dag_id") run_id = attr.get("run_id") - execution_date = attr.get("dag_run.execution_date") or attr.get("execution_date") - url = url_for("Airflow.graph", dag_id=dag_id, run_id=run_id, execution_date=execution_date) + + url = url_for("Airflow.graph", dag_id=dag_id, dag_run_id=run_id) return Markup('{run_id}').format(url=url, run_id=run_id) From 2a315775fd6b98d6b41b4033d9734f0177cf5dd5 Mon Sep 17 00:00:00 2001 From: Brent Bovenzi Date: Thu, 11 Apr 2024 13:46:29 -0400 Subject: [PATCH 2/3] Do run_id checks inside of the grid_data hook --- airflow/www/static/js/api/useGridData.ts | 33 +++++++++++++++++--- airflow/www/static/js/dag/details/Header.tsx | 11 +++---- airflow/www/templates/airflow/dag.html | 1 + airflow/www/views.py | 27 +++------------- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/airflow/www/static/js/api/useGridData.ts b/airflow/www/static/js/api/useGridData.ts index ee9325e852944..fc48f4303b7d2 100644 --- a/airflow/www/static/js/api/useGridData.ts +++ b/airflow/www/static/js/api/useGridData.ts @@ -33,9 +33,9 @@ import useFilters, { FILTER_UPSTREAM_PARAM, ROOT_PARAM, } from "src/dag/useFilters"; -import type { Task, DagRun, RunOrdering } from "src/types"; +import type { Task, DagRun, RunOrdering, API } from "src/types"; import { camelCase } from "lodash"; -import useSelection, { RUN_ID } from "src/dag/useSelection"; +import useSelection from "src/dag/useSelection"; const DAG_ID_PARAM = "dag_id"; @@ -80,9 +80,13 @@ const useGridData = () => { filterDownstream, filterUpstream, }, + onBaseDateChange, } = useFilters(); - const { firstRunIdSetByUrl } = useSelection(); - + const { + firstRunIdSetByUrl, + onSelect, + selected: { taskId }, + } = useSelection(); const query = useQuery( [ "gridData", @@ -105,11 +109,30 @@ const useGridData = () => { [NUM_RUNS_PARAM]: numRuns, [RUN_TYPE_PARAM]: runType, [RUN_STATE_PARAM]: runState, - [RUN_ID]: firstRunIdSetByUrl || "", }; const response = await axios.get(gridDataUrl, { params, }); + if ( + firstRunIdSetByUrl && + !response.dagRuns.find((dr) => dr.runId === firstRunIdSetByUrl) + ) { + const dagRunUrl = getMetaValue("dag_run_url") + .replace("__DAG_ID__", dagId) + .replace("__DAG_RUN_ID__", firstRunIdSetByUrl); + + // If the run id cannot be found in the response, try fetching it to see if its real and then adjust the base date filter + try { + const selectedRun = await axios.get( + dagRunUrl + ); + if (selectedRun?.executionDate) { + onBaseDateChange(selectedRun.executionDate); + } + } catch (e) { + onSelect({ taskId }); + } + } // turn off auto refresh if there are no active runs if (!areActiveRuns(response.dagRuns)) stopRefresh(); return response; diff --git a/airflow/www/static/js/dag/details/Header.tsx b/airflow/www/static/js/dag/details/Header.tsx index e1222270d4580..d13dfa6c8153f 100644 --- a/airflow/www/static/js/dag/details/Header.tsx +++ b/airflow/www/static/js/dag/details/Header.tsx @@ -51,17 +51,14 @@ const Header = ({ mapIndex }: Props) => { } = useSelection(); const dagRun = dagRuns.find((r) => r.runId === runId); - const group = getTask({ taskId, task: groups }); - // If runId and/or taskId can't be found remove the selection + // If taskId can't be found remove the selection useEffect(() => { - if (runId && !dagRun && taskId && !group) { - clearSelection(); - } else if (runId && !dagRun) { - onSelect({ taskId }); + if (taskId && !group) { + onSelect({ runId }); } - }, [dagRun, taskId, group, runId, onSelect, clearSelection]); + }, [taskId, group, onSelect, runId]); let runLabel; if (dagRun && runId) { diff --git a/airflow/www/templates/airflow/dag.html b/airflow/www/templates/airflow/dag.html index 56bfc27070300..d9ef3c139a161 100644 --- a/airflow/www/templates/airflow/dag.html +++ b/airflow/www/templates/airflow/dag.html @@ -84,6 +84,7 @@ + diff --git a/airflow/www/views.py b/airflow/www/views.py index 8a5ea382705da..e14a5ca45cc58 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -3170,7 +3170,6 @@ def task_instances(self): def grid_data(self): """Return grid data.""" dag_id = request.args.get("dag_id") - run_id = request.args.get("dag_run_id") dag = get_airflow_app().dag_bag.get_dag(dag_id) if not dag: @@ -3188,43 +3187,25 @@ def grid_data(self): if num_runs is None: num_runs = conf.getint("webserver", "default_dag_run_display_number") - dagrun = None - if run_id: - with create_session() as session: - dagrun = dag.get_dagrun(run_id=run_id, session=session) - if not dagrun: - return {"error": f"can't find dag_run_id={run_id}"}, 404 - base_date = dagrun.execution_date - else: - try: - base_date = timezone.parse(request.args["base_date"], strict=True) - except (KeyError, ValueError): - base_date = dag.get_latest_execution_date() or timezone.utcnow() + try: + base_date = timezone.parse(request.args["base_date"], strict=True) + except (KeyError, ValueError): + base_date = dag.get_latest_execution_date() or timezone.utcnow() with create_session() as session: query = select(DagRun).where(DagRun.dag_id == dag.dag_id, DagRun.execution_date <= base_date) run_types = request.args.getlist("run_type") if run_types: - if run_id: - return {"error": "Can not provide filters when dag_run_id filter is selected."}, 400 query = query.where(DagRun.run_type.in_(run_types)) run_states = request.args.getlist("run_state") if run_states: - if run_id: - return {"error": "Can not provide filters when dag_run_id filter is selected."}, 400 query = query.where(DagRun.state.in_(run_states)) dag_runs = wwwutils.sorted_dag_runs( query, ordering=dag.timetable.run_ordering, limit=num_runs, session=session ) - if dagrun: - found_requested_run_id = any(True for d in dag_runs if d.run_id == run_id) - if not found_requested_run_id: - return { - "error": f"Dag with dag_run_id={run_id} found, but not in selected time range or filters." - }, 404 encoded_runs = [wwwutils.encode_dag_run(dr, json_encoder=utils_json.WebEncoder) for dr in dag_runs] data = { From 5739b59a6af8ff6b4bca2d73e9ee56eca725d9a8 Mon Sep 17 00:00:00 2001 From: Brent Bovenzi Date: Thu, 11 Apr 2024 13:55:39 -0400 Subject: [PATCH 3/3] remove firstRunId context --- airflow/www/static/js/api/useGridData.ts | 13 +++++-------- airflow/www/static/js/dag/Main.tsx | 14 +------------- airflow/www/static/js/dag/useSelection.ts | 7 ------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/airflow/www/static/js/api/useGridData.ts b/airflow/www/static/js/api/useGridData.ts index fc48f4303b7d2..1a633acea3b50 100644 --- a/airflow/www/static/js/api/useGridData.ts +++ b/airflow/www/static/js/api/useGridData.ts @@ -83,9 +83,8 @@ const useGridData = () => { onBaseDateChange, } = useFilters(); const { - firstRunIdSetByUrl, onSelect, - selected: { taskId }, + selected: { taskId, runId }, } = useSelection(); const query = useQuery( [ @@ -97,7 +96,7 @@ const useGridData = () => { root, filterUpstream, filterDownstream, - firstRunIdSetByUrl, + runId, ], async () => { const params = { @@ -113,13 +112,10 @@ const useGridData = () => { const response = await axios.get(gridDataUrl, { params, }); - if ( - firstRunIdSetByUrl && - !response.dagRuns.find((dr) => dr.runId === firstRunIdSetByUrl) - ) { + if (runId && !response.dagRuns.find((dr) => dr.runId === runId)) { const dagRunUrl = getMetaValue("dag_run_url") .replace("__DAG_ID__", dagId) - .replace("__DAG_RUN_ID__", firstRunIdSetByUrl); + .replace("__DAG_RUN_ID__", runId); // If the run id cannot be found in the response, try fetching it to see if its real and then adjust the base date filter try { @@ -129,6 +125,7 @@ const useGridData = () => { if (selectedRun?.executionDate) { onBaseDateChange(selectedRun.executionDate); } + // otherwise the run_id isn't valid and we should unselect it } catch (e) { onSelect({ taskId }); } diff --git a/airflow/www/static/js/dag/Main.tsx b/airflow/www/static/js/dag/Main.tsx index 2d70b452d5ab2..144aba94a9031 100644 --- a/airflow/www/static/js/dag/Main.tsx +++ b/airflow/www/static/js/dag/Main.tsx @@ -47,7 +47,6 @@ import FilterBar from "./nav/FilterBar"; import LegendRow from "./nav/LegendRow"; import useToggleGroups from "./useToggleGroups"; import keyboardShortcutIdentifier from "./keyboardShortcutIdentifier"; -import { DagRunSelectionContext, RUN_ID } from "./useSelection"; const detailsPanelKey = "hideDetailsPanel"; const minPanelWidth = 300; @@ -74,7 +73,7 @@ const headerHeight = 10 ) || 0; -const MainInContext = () => { +const Main = () => { const { data: { groups }, isLoading, @@ -319,15 +318,4 @@ const MainInContext = () => { ); }; -const Main = () => { - const [searchParams] = useSearchParams(); - const [firstRunIdSetByUrl] = useState(searchParams.get(RUN_ID)); - - return ( - - - - ); -}; - export default Main; diff --git a/airflow/www/static/js/dag/useSelection.ts b/airflow/www/static/js/dag/useSelection.ts index 00ead40c52814..04113a870c552 100644 --- a/airflow/www/static/js/dag/useSelection.ts +++ b/airflow/www/static/js/dag/useSelection.ts @@ -17,7 +17,6 @@ * under the License. */ -import { createContext, useContext } from "react"; import { useSearchParams } from "react-router-dom"; import { LIMIT_PARAM, @@ -35,13 +34,8 @@ export interface SelectionProps { mapIndex?: number; } -// The first run_id need to be treated differently from the selection, because it is used in backend to -// calculate the base_date, which we don't want jumping around when user is clicking in the grid. -export const DagRunSelectionContext = createContext(null); - const useSelection = () => { const [searchParams, setSearchParams] = useSearchParams(); - const firstRunIdSetByUrl = useContext(DagRunSelectionContext); // Clear selection, but keep other search params const clearSelection = () => { @@ -99,7 +93,6 @@ const useSelection = () => { }, clearSelection, onSelect, - firstRunIdSetByUrl, }; };