Skip to content

Conversation

@viiccwen
Copy link
Contributor

@viiccwen viiccwen commented Sep 4, 2025

Description

This PR introduces a new feature that allows calling DAG trigger modals with Single/Backfill mode to be opened directly via URL using the query string parameter.

The feature also supports pre-populating form fields from URL parameters, improving automation and integration with external tools.

Changes

1. Trigger Modal Opening/Closing

  • When visiting a DAG page with /dags/{dag_id}/trigger/single or /dags/{dag_id}/trigger/backfill, the Trigger Modal automatically opens with correspond mode.
  • When closing the trigger modal, the pathname will turn to /dags/{dag_id} automatically.

2. URL Parameter Pre-Population

Trigger form supports (you can check its functionality on UI):

  • conf
  • run_id
  • logical_date
  • note

Backfill form supports (you can check its functionality on UI):

  • start_date
  • end_date
  • run_backwards
  • reprocess_behavior
  • max_active_runs
  • conf

conf supports 2 type:

Form Usage Example
JSON (explicit) Provide the entire configuration as a JSON object.
Has higher priority if present.
/dags/{dag_id}/trigger/single?conf={"foo":"bar","x":123}
Key-value (implicit) If conf is not specified, any query parameter that is not a reserved keyword will be collected into conf. /dags/{dag_id}/trigger/single?run_id=myrun&foo=bar&x=123conf={"foo":"bar","x":"123"}

3. Utilities Added

New helper file in src/utils/trigger.ts:

  1. put preloaded function (getPreloadTriggerFormData, getPreloadBackfillFormData)
  2. getRunModeFromPathname
  3. normalize the trigger path by params normalizeTriggerPath, i.e. (/trigger/single, /trigger/backfill)

4. Advanced Options

  • The Advanced Options section is expanded automatically when pre-filled values are detected from URL parameters.

Examples

1. Single mode

/trigger/single&mode=single?conf={"environment":"production","debug":true,"user":"admin"}&run_id=test_run_001&logical_date=2024-01-15T10:30:00.000&note=testing note

2. Backfill mode

/trigger/backfill?start_date=2024-01-01&end_date=2024-01-31&run_backwards=true&reprocess_behavior=missing_runs&max_active_runs=3&conf={"environment":"staging","batch_size":1000}

Snapshot

  1. single mode with /dag/{dag_id}/trigger/single?run_id=run%20dag&logical_date=2025-09-06T12:34:56.789&conf={%22foo%22:%22bar%22,%22ping%22:%22pong%22}&note=Nothing%20beats%20a%20jet2%20holiday
single.mode.mov
  1. backfill mode with /dags/{dag_id}/trigger/backfill?start_date=2025-09-01T12:34:56&end_date=2025-09-02T12:34:56&conf={%22foo%22:%22bar%22,%22ping%22:%22pong%22}&reprocess_behavior=completed&max_active_runs=3&run_backwards=1
backfill.mode.mov
  1. key=value type of conf with /dags/{dag_id}/trigger/single?run_id=run%20dag&logical_date=2025-09-06T12:34:56.789&foo=bar&ping=pong&note=Nothing%20beats%20a%20jet2%20holiday
key.value.type.of.conf.mov

Documentation

I edited the /core-concepts/params.html file for this change, I added trigger params, conf usage table, examples for 2 mode.

Related Issue

resolves #54800

@boring-cyborg boring-cyborg bot added the area:UI Related to UI/UX. For Frontend Developers. label Sep 4, 2025
@viiccwen viiccwen changed the title Feat: add support for opening single/backfill modal via URL pre-populated Feat: add support for opening trigger modal via URL pre-populated Sep 4, 2025
Copy link
Contributor

@jscheffl jscheffl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. Some comments as general code review. Did not test myself (yet) as I assume it will need a bit of adjustments. Code is mainly looking good.

Regarding your questions:

  • I (personally, other opinions welcome) would favor using /trigger and not a URL parameter for this. Also the mode could be directly encoded as part of the URL like /trigger/single (and would propose to have single as default because this would be for 90% of calls I assume).

General feedback to the PR:

  • In PR #54783 we also had a discussion about passing form values as JSON dict. In my view this makes it complex because a user who constructs a URL must make a proper JSON and encode the data in the URL properly. Finally we came to the point in passing individual key/vale pairs and not a JSON dict. See also #54783 (comment) - I'd wish to make it consistent here as well.
  • Please also add documentation back to airflow-core/docs/core-concepts/params.rst as it was removed in #54799 and describe how users can use it (would be bad if users need to read source to discover such cool features!)

@viiccwen viiccwen requested a review from jscheffl September 6, 2025 06:40
@viiccwen
Copy link
Contributor Author

viiccwen commented Sep 6, 2025

Hello @jscheffl
I just updated all the work and PR description, could you review it again, thx!

@guan404ming, @RoyLee1224 since last time of your review, colud you also help me to review with this PR, thx!

@viiccwen viiccwen force-pushed the feature/ui-trigger-form-url-params branch from 2b8bc23 to 827c6c3 Compare September 6, 2025 07:29
@viiccwen viiccwen changed the title Feat: add support for opening trigger modal via URL pre-populated Add support for opening trigger modal via URL pre-populated Sep 6, 2025
Added support for `?trigger=true` or `?trigger=1` query parameter to automatically open TriggerDAGModal
- Added `decodeParam` for safe URL decoding
- Added `parseJsonSafe` for safe JSON.parse with fallback
- Added `getUrlParam` to unify parameter extraction and optional JSON parsing
- Pre-populate fields (conf, dag_run_id, logical_date, note) from URL parameters
- URL conf is validated and pretty-printed if valid JSON
- add openAdvanced that supports open automatically
- Added parsing of backfill-specific parameters (start_date, end_date, reset_dagruns, rerun_failed_tasks, etc.)
- Connected URL param values into Backfill form default state
- add mapped helper function with ReprocessBehavior
1. add `/trigger/single` and `/trigger/backfill` pathname to fit the correct mode.
2. add trigger.ts: encapsulate params getter function to new file
3. refactor TriggerDAGModal, TrggerDAGForm, TrggerDAGButton, RunBackfillForm

* RunBackfillForm is almost closed to the maximum line, we may need to refactor it.
@viiccwen viiccwen force-pushed the feature/ui-trigger-form-url-params branch from 827c6c3 to 969a418 Compare September 6, 2025 08:23
@jscheffl
Copy link
Contributor

jscheffl commented Sep 7, 2025

Hello @jscheffl I just updated all the work and PR description, could you review it again, thx!

@guan404ming, @RoyLee1224 since last time of your review, colud you also help me to review with this PR, thx!

I see no change in regards to - was this missed-out? Or do you have a strong preperence to the proposed PR solution with a JSON? Then I'd need some arguments to convince me.

@viiccwen
Copy link
Contributor Author

viiccwen commented Sep 7, 2025

Key-value (implicit) If conf is not specified, any query parameter that is not a reserved keyword will be collected into conf. /dags/{dag_id}/trigger/single?run_id=myrun&foo=bar&x=123conf={"foo":"bar","x":"123"}

Didn't the PR description solve the problem? 🤔

After I read all the PRs you mentioned, I realized we need to add key=value to let user to fill the conf parameter. (in commit: feat: supports conf key=value key in method if not provided explici…)
and I also updated the docs (in commit: docs(params): add conf params usage table between JSON and key=value)

Now conf supports 2 types: JSON & key=value (I think we could keep JSON type for devs), you can check out the table on my PR description, and with the video to present it.

If I still misunderstood the meaning, sorry for my poor understanding... 🤡

Copy link
Member

@guan404ming guan404ming left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

I think the implementation could be simpler by just get search param via hook and preload them in FlexiableForm

- ``conf`` – JSON configuration.
- ``run_id`` – run identifier.
- ``logical_date`` – execution date in ``YYYY-MM-DDTHH:mm:ss.SSS`` format. Defaults to the current timestamp if not provided.
- ``note`` – note attached to the DAG run.
Copy link
Member

@guan404ming guan404ming Sep 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fields in the form would dynamically change based on user's config. Thus, we may not only need to handle these specific fields but we should handle all fields passed. The implementation is quite like #54783

Copy link
Member

@pierrejeambrun pierrejeambrun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, a few suggestion in addition to @guan404ming comments.

Comment on lines +61 to +69
const params = new URLSearchParams(search);
const {
conf: urlConf,
from_date: urlFromDate,
max_active_runs: urlMaxActiveRuns,
reprocess_behavior: urlReprocessBehavior,
run_backwards: urlRunBackwards,
to_date: urlToDate,
} = getPreloadBackfillFormData(params);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use the searchParam hook there.

Comment on lines +77 to +88
// Only sync URL when already within trigger route to avoid interfering with close navigation
if (!open || !/\/trigger(\/(single|backfill))?$/u.test(pathname)) {
return;
}

const targetPath = normalizeTriggerPath(pathname, runMode);

if (pathname !== targetPath) {
navigate({ pathname: targetPath, search }, { replace: true });
}
}, [runMode, pathname, search, navigate, open]);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably add router entries on ..../trigger/{mode} that also maps to the same page, and handle the path param mode if in the URL.

Comment on lines +76 to +80
from_date: searchParams.get("start_date") ?? "",
max_active_runs: parseInt(searchParams.get("max_active_runs") ?? "1", 10),
reprocess_behavior: (searchParams.get("reprocess_behavior") ?? "none") as ReprocessBehavior,
run_backwards: ["1", "true"].includes(searchParams.get("run_backwards") ?? ""),
to_date: searchParams.get("end_date") ?? "",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you change the url name of the param vs the one used for the form?

Suggested change
from_date: searchParams.get("start_date") ?? "",
max_active_runs: parseInt(searchParams.get("max_active_runs") ?? "1", 10),
reprocess_behavior: (searchParams.get("reprocess_behavior") ?? "none") as ReprocessBehavior,
run_backwards: ["1", "true"].includes(searchParams.get("run_backwards") ?? ""),
to_date: searchParams.get("end_date") ?? "",
from_date: searchParams.get("from_date") ?? "",
max_active_runs: parseInt(searchParams.get("max_active_runs") ?? "1", 10),
reprocess_behavior: (searchParams.get("reprocess_behavior") ?? "none") as ReprocessBehavior,
run_backwards: ["1", "true"].includes(searchParams.get("run_backwards") ?? ""),
to_date: searchParams.get("to_date") ?? "",

Also you should probably use the PARAMS constants from SearchParamsKeys and update that enum if some keys are missing.

@bbovenzi bbovenzi added this to the Airflow 3.2.0 milestone Sep 15, 2025
Comment on lines +179 to +180
{ element: <Overview />, path: "single" },
{ element: <Overview />, path: "backfill" },
Copy link
Contributor

@bbovenzi bbovenzi Sep 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should pass trigger={"single" | "backfill" | undefined} as props from here instead of trying to manually parse the url string?

</Dialog.Header>

<Dialog.CloseTrigger />
<Dialog.CloseTrigger onClick={onClose} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this change

@github-actions
Copy link

github-actions bot commented Nov 9, 2025

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed in 5 days if no further activity occurs. Thank you for your contributions.

@github-actions github-actions bot added the stale Stale PRs per the .github/workflows/stale.yml policy file label Nov 9, 2025
@github-actions github-actions bot closed this Nov 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:UI Related to UI/UX. For Frontend Developers. stale Stale PRs per the .github/workflows/stale.yml policy file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Trigger form can be called via URL with fields pre-populated.

5 participants