feat(ansible): dropdown playbook selection + auto-populated variable fields
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 8s
CI / integration (push) Successful in 2m17s
CI / publish (push) Successful in 43s

Stop making operators type playbook paths and guess extra-var names.

- Reusable infra: shared ansible/_playbook_vars.html (the discovered-variable
  fields) + ansible/_playbook_options.html; two HTMX endpoints —
  /ansible/playbook-options (a source's playbooks, optional ?selected for edit)
  and /ansible/playbook-vars (a playbook's vars:/vars_prompt: as fill-in
  fields). browse _run_form.html refactored to include the shared partial.
- Host "Run a playbook against this host": source dropdown → playbook dropdown
  → variable fields, all chained via HTMX. Handler reuses _parse_run_params so
  var__/secret__ fields flow through extra_vars_map + the unpersisted
  secret_vars channel.
- Schedules: playbook free-text+datalist → source-dependent dropdown; fixed the
  extra-vars edit pre-fill to read extra_vars_map (stale list key after the
  earlier JSON-extra-vars change).

Scribe #895.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-17 10:02:15 -04:00
parent bb90411f00
commit ad726e65f3
7 changed files with 114 additions and 69 deletions
+29
View File
@@ -143,6 +143,35 @@ def _parse_run_params(form) -> tuple[dict | None, dict | None, str | None]:
return (params or None), (secret_vars or None), None
@ansible_bp.get("/playbook-options")
@require_role(UserRole.operator)
async def playbook_options():
"""HTMX fragment: <option>s of playbooks in a source, to populate a playbook
dropdown when a source is chosen. `selected` pre-selects one (edit forms)."""
source_name = (request.args.get("source_name", "") or "").strip()
selected = (request.args.get("selected", "") or "").strip()
source = next((s for s in _get_sources() if s["name"] == source_name), None)
playbooks = src_module.discover_playbooks(source["path"]) if source else []
return await render_template(
"ansible/_playbook_options.html", playbooks=playbooks, selected=selected)
@ansible_bp.get("/playbook-vars")
@require_role(UserRole.operator)
async def playbook_vars():
"""HTMX fragment: fill-in fields for a playbook's declared variables
(vars/vars_prompt), loaded when a playbook is chosen from a dropdown."""
source_name = (request.args.get("source_name", "") or "").strip()
playbook_path = (request.args.get("playbook_path", "") or "").strip()
source = next((s for s in _get_sources() if s["name"] == source_name), None)
variables: list = []
if source and playbook_path:
contents = src_module.read_playbook(source["path"], playbook_path)
if contents is not None:
variables = src_module.discover_playbook_variables(contents)
return await render_template("ansible/_playbook_vars.html", variables=variables)
@ansible_bp.get("/run-form/<source_name>/<path:playbook_path>")
@require_role(UserRole.operator)
async def run_form(source_name: str, playbook_path: str):