We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Job Buttons do not honor the Job task_queue
<!--
    NOTE: IF YOUR ISSUE DOES NOT FOLLOW THIS TEMPLATE, IT WILL BE CLOSED.

    This form is only for reporting reproducible bugs. If you need assistance
    with Nautobot installation, or if you have a general question, please start a
    discussion instead: https://github.com/nautobot/nautobot/discussions

    Please describe the environment in which you are running Nautobot. Be sure
    that you are running an unmodified instance of the latest stable release
    before submitting a bug report, and that any plugins have been disabled.
-->
### Environment
* Nautobot version (Docker tag too if applicable): 1.6.11
* Python version: 3.11
* Database platform, version: NA
* Middleware(s): NA

<!--
    Describe in detail the exact steps that someone else can take to reproduce
    this bug using the current stable release of Nautobot. Begin with the
    creation of any necessary database objects and call out every operation
    being performed explicitly. If reporting a bug in the REST API, be sure to
    reconstruct the raw HTTP request(s) being made: Don't rely on a client
    library such as pynautobot.
-->
### Steps to Reproduce
1. Create a JobButtonReciever that uses a queue other than default
2. Create a Job Button that points to the JobButtonReciever and connect it to a contenttype (like dcim.devices)
3. Click the Job Button on the contenttype from above.

<!-- What did you expect to happen? -->
### Expected Behavior
The Job runs under the queue that is configured for JobButtonReceiver.

<!-- What happened instead? -->
### Observed Behavior
The Job runs under the default queue (which in my case causes an error, but may not in other use cases).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nautobot/extras/templatetags/job_buttons.py`
Content:
```
1 from collections import OrderedDict
2 
3 from django import template
4 from django.contrib.contenttypes.models import ContentType
5 from django.urls import reverse
6 from django.utils.html import format_html
7 from django.utils.safestring import mark_safe
8 
9 from nautobot.core.utils.data import render_jinja2
10 from nautobot.extras.models import Job, JobButton
11 
12 register = template.Library()
13 
14 GROUP_DROPDOWN = """
15 <div class="btn-group">
16   <button type="button" class="btn btn-sm btn-{group_button_class} dropdown-toggle" data-toggle="dropdown">
17     {group_name} <span class="caret"></span>
18   </button>
19   <ul class="dropdown-menu pull-right">
20     {grouped_buttons}
21   </ul>
22 </div>
23 """
24 
25 HIDDEN_INPUTS = """
26 <input type="hidden" name="csrfmiddlewaretoken" value="{csrf_token}">
27 <input type="hidden" name="object_pk" value="{object_pk}">
28 <input type="hidden" name="object_model_name" value="{object_model_name}">
29 <input type="hidden" name="_schedule_type" value="immediately">
30 <input type="hidden" name="_return_url" value="{redirect_path}">
31 """
32 
33 NO_CONFIRM_BUTTON = """
34 <button type="submit" form="form_id_{button_id}" class="btn btn-sm btn-{button_class}" {disabled}>{button_text}</button>
35 """
36 
37 NO_CONFIRM_FORM = """
38 <form id="form_id_{button_id}" action="{button_url}" method="post" class="form">
39   {hidden_inputs}
40 </form>
41 """
42 
43 CONFIRM_BUTTON = """
44 <button type="button" class="btn btn-sm btn-{button_class}" data-toggle="modal" data-target="#confirm_modal_id_{button_id}" {disabled}>
45   {button_text}
46 </button>
47 """
48 
49 CONFIRM_MODAL = """
50 <div class="modal fade" id="confirm_modal_id_{button_id}" tabindex="-1" role="dialog" aria-labelledby="confirm_modal_label_{button_id}">
51   <div class="modal-dialog" role="document">
52     <div class="modal-content">
53       <div class="modal-header">
54         <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
55         <h4 class="modal-title" id="confirm_modal_label_{button_id}">Confirmation</h4>
56       </div>
57       <form id="form_id_{button_id}" action="{button_url}" method="post" class="form">
58         <div class="modal-body">
59           {hidden_inputs}
60           Run Job <strong>'{job}'</strong> with object <strong>'{object}'</strong>?
61         </div>
62         <div class="modal-footer">
63           <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
64           <button type="submit" class="btn btn-primary">Confirm</button>
65         </div>
66       </form>
67     </div>
68   </div>
69 </div>
70 """
71 
72 SAFE_EMPTY_STR = mark_safe("")  # noqa: S308  # suspicious-mark-safe-usage -- this one is safe
73 
74 
75 def _render_job_button_for_obj(job_button, obj, context, content_type):
76     """
77     Helper method for job_buttons templatetag to reduce repetition of code.
78 
79     Returns:
80        (str, str): (button_html, form_html)
81     """
82     # Pass select context data when rendering the JobButton text as Jinja2
83     button_context = {
84         "obj": obj,
85         "debug": context.get("debug", False),  # django.template.context_processors.debug
86         "request": context["request"],  # django.template.context_processors.request
87         "user": context["user"],  # django.contrib.auth.context_processors.auth
88         "perms": context["perms"],  # django.contrib.auth.context_processors.auth
89     }
90     try:
91         text_rendered = render_jinja2(job_button.text, button_context)
92     except Exception as exc:
93         return (
94             format_html(
95                 '<a class="btn btn-sm btn-{}" disabled="disabled" title="{}"><i class="mdi mdi-alert"></i> {}</a>\n',
96                 "default" if not job_button.group_name else "link",
97                 exc,
98                 job_button.name,
99             ),
100             SAFE_EMPTY_STR,
101         )
102 
103     if not text_rendered:
104         return (SAFE_EMPTY_STR, SAFE_EMPTY_STR)
105 
106     # Disable buttons if the user doesn't have permission to run the underlying Job.
107     has_run_perm = Job.objects.check_perms(context["user"], instance=job_button.job, action="run")
108     hidden_inputs = format_html(
109         HIDDEN_INPUTS,
110         csrf_token=context["csrf_token"],
111         object_pk=obj.pk,
112         object_model_name=f"{content_type.app_label}.{content_type.model}",
113         redirect_path=context["request"].path,
114     )
115     template_args = {
116         "button_id": job_button.pk,
117         "button_text": text_rendered,
118         "button_class": job_button.button_class if not job_button.group_name else "link",
119         "button_url": reverse("extras:job_run", kwargs={"pk": job_button.job.pk}),
120         "object": obj,
121         "job": job_button.job,
122         "hidden_inputs": hidden_inputs,
123         "disabled": "" if has_run_perm else "disabled",
124     }
125 
126     if job_button.confirmation:
127         return (
128             format_html(CONFIRM_BUTTON, **template_args),
129             format_html(CONFIRM_MODAL, **template_args),
130         )
131     else:
132         return (
133             format_html(NO_CONFIRM_BUTTON, **template_args),
134             format_html(NO_CONFIRM_FORM, **template_args),
135         )
136 
137 
138 @register.simple_tag(takes_context=True)
139 def job_buttons(context, obj):
140     """
141     Render all applicable job buttons for the given object.
142     """
143     content_type = ContentType.objects.get_for_model(obj)
144     # We will enforce "run" permission later in deciding which buttons to show as disabled.
145     buttons = JobButton.objects.filter(content_types=content_type)
146     if not buttons:
147         return SAFE_EMPTY_STR
148 
149     buttons_html = forms_html = SAFE_EMPTY_STR
150     group_names = OrderedDict()
151 
152     for jb in buttons:
153         # Organize job buttons by group for later processing
154         if jb.group_name:
155             group_names.setdefault(jb.group_name, []).append(jb)
156 
157         # Render and add non-grouped buttons
158         else:
159             button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)
160             buttons_html += button_html
161             forms_html += form_html
162 
163     # Add grouped buttons to template
164     for group_name, buttons in group_names.items():
165         group_button_class = buttons[0].button_class
166 
167         buttons_rendered = SAFE_EMPTY_STR
168 
169         for jb in buttons:
170             # Render grouped buttons as list items
171             button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)
172             buttons_rendered += format_html("<li>{}</li>", button_html)
173             forms_html += form_html
174 
175         if buttons_rendered:
176             buttons_html += format_html(
177                 GROUP_DROPDOWN,
178                 group_button_class=group_button_class,
179                 group_name=group_name,
180                 grouped_buttons=buttons_rendered,
181             )
182 
183     # We want all of the buttons first and then any modals and forms so the buttons render properly
184     return buttons_html + forms_html
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/nautobot/extras/templatetags/job_buttons.py b/nautobot/extras/templatetags/job_buttons.py
--- a/nautobot/extras/templatetags/job_buttons.py
+++ b/nautobot/extras/templatetags/job_buttons.py
@@ -1,6 +1,7 @@
 from collections import OrderedDict
 
 from django import template
+from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 from django.urls import reverse
 from django.utils.html import format_html
@@ -27,6 +28,7 @@
 <input type="hidden" name="object_pk" value="{object_pk}">
 <input type="hidden" name="object_model_name" value="{object_model_name}">
 <input type="hidden" name="_schedule_type" value="immediately">
+<input type="hidden" name="_task_queue" value="{task_queue}">
 <input type="hidden" name="_return_url" value="{redirect_path}">
 """
 
@@ -105,12 +107,17 @@
 
     # Disable buttons if the user doesn't have permission to run the underlying Job.
     has_run_perm = Job.objects.check_perms(context["user"], instance=job_button.job, action="run")
+    try:
+        _task_queue = job_button.job.task_queues[0]
+    except IndexError:
+        _task_queue = settings.CELERY_TASK_DEFAULT_QUEUE
     hidden_inputs = format_html(
         HIDDEN_INPUTS,
         csrf_token=context["csrf_token"],
         object_pk=obj.pk,
         object_model_name=f"{content_type.app_label}.{content_type.model}",
         redirect_path=context["request"].path,
+        task_queue=_task_queue,
     )
     template_args = {
         "button_id": job_button.pk,

{"golden_diff": "diff --git a/nautobot/extras/templatetags/job_buttons.py b/nautobot/extras/templatetags/job_buttons.py\n--- a/nautobot/extras/templatetags/job_buttons.py\n+++ b/nautobot/extras/templatetags/job_buttons.py\n@@ -1,6 +1,7 @@\n from collections import OrderedDict\n \n from django import template\n+from django.conf import settings\n from django.contrib.contenttypes.models import ContentType\n from django.urls import reverse\n from django.utils.html import format_html\n@@ -27,6 +28,7 @@\n <input type=\"hidden\" name=\"object_pk\" value=\"{object_pk}\">\n <input type=\"hidden\" name=\"object_model_name\" value=\"{object_model_name}\">\n <input type=\"hidden\" name=\"_schedule_type\" value=\"immediately\">\n+<input type=\"hidden\" name=\"_task_queue\" value=\"{task_queue}\">\n <input type=\"hidden\" name=\"_return_url\" value=\"{redirect_path}\">\n \"\"\"\n \n@@ -105,12 +107,17 @@\n \n     # Disable buttons if the user doesn't have permission to run the underlying Job.\n     has_run_perm = Job.objects.check_perms(context[\"user\"], instance=job_button.job, action=\"run\")\n+    try:\n+        _task_queue = job_button.job.task_queues[0]\n+    except IndexError:\n+        _task_queue = settings.CELERY_TASK_DEFAULT_QUEUE\n     hidden_inputs = format_html(\n         HIDDEN_INPUTS,\n         csrf_token=context[\"csrf_token\"],\n         object_pk=obj.pk,\n         object_model_name=f\"{content_type.app_label}.{content_type.model}\",\n         redirect_path=context[\"request\"].path,\n+        task_queue=_task_queue,\n     )\n     template_args = {\n         \"button_id\": job_button.pk,\n", "issue": "Job Buttons do not honor the Job task_queue\n<!--\r\n    NOTE: IF YOUR ISSUE DOES NOT FOLLOW THIS TEMPLATE, IT WILL BE CLOSED.\r\n\r\n    This form is only for reporting reproducible bugs. If you need assistance\r\n    with Nautobot installation, or if you have a general question, please start a\r\n    discussion instead: https://github.com/nautobot/nautobot/discussions\r\n\r\n    Please describe the environment in which you are running Nautobot. Be sure\r\n    that you are running an unmodified instance of the latest stable release\r\n    before submitting a bug report, and that any plugins have been disabled.\r\n-->\r\n### Environment\r\n* Nautobot version (Docker tag too if applicable): 1.6.11\r\n* Python version: 3.11\r\n* Database platform, version: NA\r\n* Middleware(s): NA\r\n\r\n<!--\r\n    Describe in detail the exact steps that someone else can take to reproduce\r\n    this bug using the current stable release of Nautobot. Begin with the\r\n    creation of any necessary database objects and call out every operation\r\n    being performed explicitly. If reporting a bug in the REST API, be sure to\r\n    reconstruct the raw HTTP request(s) being made: Don't rely on a client\r\n    library such as pynautobot.\r\n-->\r\n### Steps to Reproduce\r\n1. Create a JobButtonReciever that uses a queue other than default\r\n2. Create a Job Button that points to the JobButtonReciever and connect it to a contenttype (like dcim.devices)\r\n3. Click the Job Button on the contenttype from above.\r\n\r\n<!-- What did you expect to happen? -->\r\n### Expected Behavior\r\nThe Job runs under the queue that is configured for JobButtonReceiver.\r\n\r\n<!-- What happened instead? -->\r\n### Observed Behavior\r\nThe Job runs under the default queue (which in my case causes an error, but may not in other use cases).\n", "before_files": [{"content": "from collections import OrderedDict\n\nfrom django import template\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.urls import reverse\nfrom django.utils.html import format_html\nfrom django.utils.safestring import mark_safe\n\nfrom nautobot.core.utils.data import render_jinja2\nfrom nautobot.extras.models import Job, JobButton\n\nregister = template.Library()\n\nGROUP_DROPDOWN = \"\"\"\n<div class=\"btn-group\">\n  <button type=\"button\" class=\"btn btn-sm btn-{group_button_class} dropdown-toggle\" data-toggle=\"dropdown\">\n    {group_name} <span class=\"caret\"></span>\n  </button>\n  <ul class=\"dropdown-menu pull-right\">\n    {grouped_buttons}\n  </ul>\n</div>\n\"\"\"\n\nHIDDEN_INPUTS = \"\"\"\n<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"{csrf_token}\">\n<input type=\"hidden\" name=\"object_pk\" value=\"{object_pk}\">\n<input type=\"hidden\" name=\"object_model_name\" value=\"{object_model_name}\">\n<input type=\"hidden\" name=\"_schedule_type\" value=\"immediately\">\n<input type=\"hidden\" name=\"_return_url\" value=\"{redirect_path}\">\n\"\"\"\n\nNO_CONFIRM_BUTTON = \"\"\"\n<button type=\"submit\" form=\"form_id_{button_id}\" class=\"btn btn-sm btn-{button_class}\" {disabled}>{button_text}</button>\n\"\"\"\n\nNO_CONFIRM_FORM = \"\"\"\n<form id=\"form_id_{button_id}\" action=\"{button_url}\" method=\"post\" class=\"form\">\n  {hidden_inputs}\n</form>\n\"\"\"\n\nCONFIRM_BUTTON = \"\"\"\n<button type=\"button\" class=\"btn btn-sm btn-{button_class}\" data-toggle=\"modal\" data-target=\"#confirm_modal_id_{button_id}\" {disabled}>\n  {button_text}\n</button>\n\"\"\"\n\nCONFIRM_MODAL = \"\"\"\n<div class=\"modal fade\" id=\"confirm_modal_id_{button_id}\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"confirm_modal_label_{button_id}\">\n  <div class=\"modal-dialog\" role=\"document\">\n    <div class=\"modal-content\">\n      <div class=\"modal-header\">\n        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n        <h4 class=\"modal-title\" id=\"confirm_modal_label_{button_id}\">Confirmation</h4>\n      </div>\n      <form id=\"form_id_{button_id}\" action=\"{button_url}\" method=\"post\" class=\"form\">\n        <div class=\"modal-body\">\n          {hidden_inputs}\n          Run Job <strong>'{job}'</strong> with object <strong>'{object}'</strong>?\n        </div>\n        <div class=\"modal-footer\">\n          <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Cancel</button>\n          <button type=\"submit\" class=\"btn btn-primary\">Confirm</button>\n        </div>\n      </form>\n    </div>\n  </div>\n</div>\n\"\"\"\n\nSAFE_EMPTY_STR = mark_safe(\"\")  # noqa: S308  # suspicious-mark-safe-usage -- this one is safe\n\n\ndef _render_job_button_for_obj(job_button, obj, context, content_type):\n    \"\"\"\n    Helper method for job_buttons templatetag to reduce repetition of code.\n\n    Returns:\n       (str, str): (button_html, form_html)\n    \"\"\"\n    # Pass select context data when rendering the JobButton text as Jinja2\n    button_context = {\n        \"obj\": obj,\n        \"debug\": context.get(\"debug\", False),  # django.template.context_processors.debug\n        \"request\": context[\"request\"],  # django.template.context_processors.request\n        \"user\": context[\"user\"],  # django.contrib.auth.context_processors.auth\n        \"perms\": context[\"perms\"],  # django.contrib.auth.context_processors.auth\n    }\n    try:\n        text_rendered = render_jinja2(job_button.text, button_context)\n    except Exception as exc:\n        return (\n            format_html(\n                '<a class=\"btn btn-sm btn-{}\" disabled=\"disabled\" title=\"{}\"><i class=\"mdi mdi-alert\"></i> {}</a>\\n',\n                \"default\" if not job_button.group_name else \"link\",\n                exc,\n                job_button.name,\n            ),\n            SAFE_EMPTY_STR,\n        )\n\n    if not text_rendered:\n        return (SAFE_EMPTY_STR, SAFE_EMPTY_STR)\n\n    # Disable buttons if the user doesn't have permission to run the underlying Job.\n    has_run_perm = Job.objects.check_perms(context[\"user\"], instance=job_button.job, action=\"run\")\n    hidden_inputs = format_html(\n        HIDDEN_INPUTS,\n        csrf_token=context[\"csrf_token\"],\n        object_pk=obj.pk,\n        object_model_name=f\"{content_type.app_label}.{content_type.model}\",\n        redirect_path=context[\"request\"].path,\n    )\n    template_args = {\n        \"button_id\": job_button.pk,\n        \"button_text\": text_rendered,\n        \"button_class\": job_button.button_class if not job_button.group_name else \"link\",\n        \"button_url\": reverse(\"extras:job_run\", kwargs={\"pk\": job_button.job.pk}),\n        \"object\": obj,\n        \"job\": job_button.job,\n        \"hidden_inputs\": hidden_inputs,\n        \"disabled\": \"\" if has_run_perm else \"disabled\",\n    }\n\n    if job_button.confirmation:\n        return (\n            format_html(CONFIRM_BUTTON, **template_args),\n            format_html(CONFIRM_MODAL, **template_args),\n        )\n    else:\n        return (\n            format_html(NO_CONFIRM_BUTTON, **template_args),\n            format_html(NO_CONFIRM_FORM, **template_args),\n        )\n\n\n@register.simple_tag(takes_context=True)\ndef job_buttons(context, obj):\n    \"\"\"\n    Render all applicable job buttons for the given object.\n    \"\"\"\n    content_type = ContentType.objects.get_for_model(obj)\n    # We will enforce \"run\" permission later in deciding which buttons to show as disabled.\n    buttons = JobButton.objects.filter(content_types=content_type)\n    if not buttons:\n        return SAFE_EMPTY_STR\n\n    buttons_html = forms_html = SAFE_EMPTY_STR\n    group_names = OrderedDict()\n\n    for jb in buttons:\n        # Organize job buttons by group for later processing\n        if jb.group_name:\n            group_names.setdefault(jb.group_name, []).append(jb)\n\n        # Render and add non-grouped buttons\n        else:\n            button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)\n            buttons_html += button_html\n            forms_html += form_html\n\n    # Add grouped buttons to template\n    for group_name, buttons in group_names.items():\n        group_button_class = buttons[0].button_class\n\n        buttons_rendered = SAFE_EMPTY_STR\n\n        for jb in buttons:\n            # Render grouped buttons as list items\n            button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)\n            buttons_rendered += format_html(\"<li>{}</li>\", button_html)\n            forms_html += form_html\n\n        if buttons_rendered:\n            buttons_html += format_html(\n                GROUP_DROPDOWN,\n                group_button_class=group_button_class,\n                group_name=group_name,\n                grouped_buttons=buttons_rendered,\n            )\n\n    # We want all of the buttons first and then any modals and forms so the buttons render properly\n    return buttons_html + forms_html\n", "path": "nautobot/extras/templatetags/job_buttons.py"}], "after_files": [{"content": "from collections import OrderedDict\n\nfrom django import template\nfrom django.conf import settings\nfrom django.contrib.contenttypes.models import ContentType\nfrom django.urls import reverse\nfrom django.utils.html import format_html\nfrom django.utils.safestring import mark_safe\n\nfrom nautobot.core.utils.data import render_jinja2\nfrom nautobot.extras.models import Job, JobButton\n\nregister = template.Library()\n\nGROUP_DROPDOWN = \"\"\"\n<div class=\"btn-group\">\n  <button type=\"button\" class=\"btn btn-sm btn-{group_button_class} dropdown-toggle\" data-toggle=\"dropdown\">\n    {group_name} <span class=\"caret\"></span>\n  </button>\n  <ul class=\"dropdown-menu pull-right\">\n    {grouped_buttons}\n  </ul>\n</div>\n\"\"\"\n\nHIDDEN_INPUTS = \"\"\"\n<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"{csrf_token}\">\n<input type=\"hidden\" name=\"object_pk\" value=\"{object_pk}\">\n<input type=\"hidden\" name=\"object_model_name\" value=\"{object_model_name}\">\n<input type=\"hidden\" name=\"_schedule_type\" value=\"immediately\">\n<input type=\"hidden\" name=\"_task_queue\" value=\"{task_queue}\">\n<input type=\"hidden\" name=\"_return_url\" value=\"{redirect_path}\">\n\"\"\"\n\nNO_CONFIRM_BUTTON = \"\"\"\n<button type=\"submit\" form=\"form_id_{button_id}\" class=\"btn btn-sm btn-{button_class}\" {disabled}>{button_text}</button>\n\"\"\"\n\nNO_CONFIRM_FORM = \"\"\"\n<form id=\"form_id_{button_id}\" action=\"{button_url}\" method=\"post\" class=\"form\">\n  {hidden_inputs}\n</form>\n\"\"\"\n\nCONFIRM_BUTTON = \"\"\"\n<button type=\"button\" class=\"btn btn-sm btn-{button_class}\" data-toggle=\"modal\" data-target=\"#confirm_modal_id_{button_id}\" {disabled}>\n  {button_text}\n</button>\n\"\"\"\n\nCONFIRM_MODAL = \"\"\"\n<div class=\"modal fade\" id=\"confirm_modal_id_{button_id}\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"confirm_modal_label_{button_id}\">\n  <div class=\"modal-dialog\" role=\"document\">\n    <div class=\"modal-content\">\n      <div class=\"modal-header\">\n        <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"><span aria-hidden=\"true\">&times;</span></button>\n        <h4 class=\"modal-title\" id=\"confirm_modal_label_{button_id}\">Confirmation</h4>\n      </div>\n      <form id=\"form_id_{button_id}\" action=\"{button_url}\" method=\"post\" class=\"form\">\n        <div class=\"modal-body\">\n          {hidden_inputs}\n          Run Job <strong>'{job}'</strong> with object <strong>'{object}'</strong>?\n        </div>\n        <div class=\"modal-footer\">\n          <button type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\">Cancel</button>\n          <button type=\"submit\" class=\"btn btn-primary\">Confirm</button>\n        </div>\n      </form>\n    </div>\n  </div>\n</div>\n\"\"\"\n\nSAFE_EMPTY_STR = mark_safe(\"\")  # noqa: S308  # suspicious-mark-safe-usage -- this one is safe\n\n\ndef _render_job_button_for_obj(job_button, obj, context, content_type):\n    \"\"\"\n    Helper method for job_buttons templatetag to reduce repetition of code.\n\n    Returns:\n       (str, str): (button_html, form_html)\n    \"\"\"\n    # Pass select context data when rendering the JobButton text as Jinja2\n    button_context = {\n        \"obj\": obj,\n        \"debug\": context.get(\"debug\", False),  # django.template.context_processors.debug\n        \"request\": context[\"request\"],  # django.template.context_processors.request\n        \"user\": context[\"user\"],  # django.contrib.auth.context_processors.auth\n        \"perms\": context[\"perms\"],  # django.contrib.auth.context_processors.auth\n    }\n    try:\n        text_rendered = render_jinja2(job_button.text, button_context)\n    except Exception as exc:\n        return (\n            format_html(\n                '<a class=\"btn btn-sm btn-{}\" disabled=\"disabled\" title=\"{}\"><i class=\"mdi mdi-alert\"></i> {}</a>\\n',\n                \"default\" if not job_button.group_name else \"link\",\n                exc,\n                job_button.name,\n            ),\n            SAFE_EMPTY_STR,\n        )\n\n    if not text_rendered:\n        return (SAFE_EMPTY_STR, SAFE_EMPTY_STR)\n\n    # Disable buttons if the user doesn't have permission to run the underlying Job.\n    has_run_perm = Job.objects.check_perms(context[\"user\"], instance=job_button.job, action=\"run\")\n    try:\n        _task_queue = job_button.job.task_queues[0]\n    except IndexError:\n        _task_queue = settings.CELERY_TASK_DEFAULT_QUEUE\n    hidden_inputs = format_html(\n        HIDDEN_INPUTS,\n        csrf_token=context[\"csrf_token\"],\n        object_pk=obj.pk,\n        object_model_name=f\"{content_type.app_label}.{content_type.model}\",\n        redirect_path=context[\"request\"].path,\n        task_queue=_task_queue,\n    )\n    template_args = {\n        \"button_id\": job_button.pk,\n        \"button_text\": text_rendered,\n        \"button_class\": job_button.button_class if not job_button.group_name else \"link\",\n        \"button_url\": reverse(\"extras:job_run\", kwargs={\"pk\": job_button.job.pk}),\n        \"object\": obj,\n        \"job\": job_button.job,\n        \"hidden_inputs\": hidden_inputs,\n        \"disabled\": \"\" if has_run_perm else \"disabled\",\n    }\n\n    if job_button.confirmation:\n        return (\n            format_html(CONFIRM_BUTTON, **template_args),\n            format_html(CONFIRM_MODAL, **template_args),\n        )\n    else:\n        return (\n            format_html(NO_CONFIRM_BUTTON, **template_args),\n            format_html(NO_CONFIRM_FORM, **template_args),\n        )\n\n\n@register.simple_tag(takes_context=True)\ndef job_buttons(context, obj):\n    \"\"\"\n    Render all applicable job buttons for the given object.\n    \"\"\"\n    content_type = ContentType.objects.get_for_model(obj)\n    # We will enforce \"run\" permission later in deciding which buttons to show as disabled.\n    buttons = JobButton.objects.filter(content_types=content_type)\n    if not buttons:\n        return SAFE_EMPTY_STR\n\n    buttons_html = forms_html = SAFE_EMPTY_STR\n    group_names = OrderedDict()\n\n    for jb in buttons:\n        # Organize job buttons by group for later processing\n        if jb.group_name:\n            group_names.setdefault(jb.group_name, []).append(jb)\n\n        # Render and add non-grouped buttons\n        else:\n            button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)\n            buttons_html += button_html\n            forms_html += form_html\n\n    # Add grouped buttons to template\n    for group_name, buttons in group_names.items():\n        group_button_class = buttons[0].button_class\n\n        buttons_rendered = SAFE_EMPTY_STR\n\n        for jb in buttons:\n            # Render grouped buttons as list items\n            button_html, form_html = _render_job_button_for_obj(jb, obj, context, content_type)\n            buttons_rendered += format_html(\"<li>{}</li>\", button_html)\n            forms_html += form_html\n\n        if buttons_rendered:\n            buttons_html += format_html(\n                GROUP_DROPDOWN,\n                group_button_class=group_button_class,\n                group_name=group_name,\n                grouped_buttons=buttons_rendered,\n            )\n\n    # We want all of the buttons first and then any modals and forms so the buttons render properly\n    return buttons_html + forms_html\n", "path": "nautobot/extras/templatetags/job_buttons.py"}]}