diff --git a/changes/1136.fixed.md b/changes/1136.fixed.md new file mode 100644 index 000000000..71e600fda --- /dev/null +++ b/changes/1136.fixed.md @@ -0,0 +1 @@ +Fixed the "Execute" dropdown on the Golden Config list view not carrying the selected devices over to the Job run form. diff --git a/nautobot_golden_config/static/nautobot_golden_config/execute_with_selected.js b/nautobot_golden_config/static/nautobot_golden_config/execute_with_selected.js new file mode 100644 index 000000000..0a5801a56 --- /dev/null +++ b/nautobot_golden_config/static/nautobot_golden_config/execute_with_selected.js @@ -0,0 +1,49 @@ +/** + * Carries all the selected devices PKs in a list view over to a Job run form. + * + * On page load it binds every anchor tagged with the `execute-job-link` class + * (i.e. the entries in the "Execute" dropdown) so that, when clicked, the Device + * PKs of the currently-checked table rows are appended to the Job run URL as + * `?device=` query parameters. As a consequence Nautobot's Job run view + * populates the matching `MultiObjectVar(model=Device)` form field from those + * parameters. + * + * Each row-select checkbox must expose its Device PK via a `data-device-pk` + * attribute. The checkbox `value` itself is left alone (it stays the row PK used + * by bulk edit/delete). Rows without a Device PK are skipped. + * + * This is how the checkbox should look like: + * + * + * If no rows are selected the link is left at its pristine URL so the Job form + * simply opens unfiltered. + * + * Implemented in plain JavaScript: jQuery is deprecated as of Nautobot 3.0. + */ +function bindExecuteWithSelection() { + document.querySelectorAll("a.execute-job-link").forEach(function (link) { + // Store the base job /run URL (without query string) so repeated clicks (and + // back-forward cache restores) rebuild from a clean URL instead of stacking params. + const baseHref = link.getAttribute("href"); + link.addEventListener("click", function () { + const params = new URLSearchParams(); + document.querySelectorAll('input[name="pk"]:checked').forEach(function (checkbox) { + const devicePk = checkbox.getAttribute("data-device-pk"); + if (devicePk) { + params.append("device", devicePk); + } + }); + const query = params.toString(); + link.setAttribute("href", query ? `${baseHref}?${query}` : baseHref); + }); + }); +} + +// Self-initialize once the DOM is ready (no jQuery). +if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", bindExecuteWithSelection); +} else { + bindExecuteWithSelection(); +} diff --git a/nautobot_golden_config/tables.py b/nautobot_golden_config/tables.py index 03be49b30..7fe864f6a 100644 --- a/nautobot_golden_config/tables.py +++ b/nautobot_golden_config/tables.py @@ -263,7 +263,20 @@ class Meta(BaseTable.Meta): class GoldenConfigTable(BaseTable): """Table to display Config Management Status.""" - pk = ToggleColumn() + # Carry the Device PK on each row-select checkbox as data-device-pk so the "Execute" + # dropdown can pre-populate the Job form's device field (see execute_with_selected.js). + # The checkbox value stays the GoldenConfig PK, which bulk delete/edit relies on. + pk = ToggleColumn( + attrs={ + "input": { + # passing attrs to ToggleColumn overrides the defaults, + # so we need to re-supply ToggleColumn default classes + "class": "form-check-input nb-form-check-input-sm mt-2", + "data-device-pk": lambda record: str(record.device_id or ""), + }, + "td": {"class": "nb-w-0"}, + } + ) name = LinkColumn( "plugins:nautobot_golden_config:goldenconfig", args=[A("pk")], diff --git a/nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_list.html b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_list.html index d41ce6a46..998692c84 100644 --- a/nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_list.html +++ b/nautobot_golden_config/templates/nautobot_golden_config/goldenconfig_list.html @@ -39,21 +39,21 @@

{% block title %}Configuration Overview{% endblock title %}