Explorar o código

Adapt custom actions panel for declarative layout system

Convert the ObjectPermission detail view to use the new panel-based
layout from #21568. Add ObjectPermissionCustomActionsPanel that
cross-references assigned object types with the model_actions registry
to display which models each custom action applies to.

Also fix dark-mode visibility of disabled action checkboxes in the
permission form by overriding Bootstrap's disabled opacity.
Jason Novinger hai 23 horas
pai
achega
2db5976184

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
netbox/project-static/dist/netbox.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 10 - 3
netbox/project-static/src/forms/registeredActions.ts

@@ -30,13 +30,20 @@ export function initRegisteredActions(): void {
       const enabled = modelKey !== null && selectedModels.has(modelKey);
       const enabled = modelKey !== null && selectedModels.has(modelKey);
       const el = group as HTMLElement;
       const el = group as HTMLElement;
 
 
-      el.style.opacity = enabled ? '1' : '0.4';
-
-      // Toggle disabled on checkboxes within the group
+      // Toggle disabled on checkboxes, overriding Bootstrap's disabled opacity
+      // to keep them visible in dark mode
       for (const checkbox of Array.from(
       for (const checkbox of Array.from(
         el.querySelectorAll<HTMLInputElement>('input[type="checkbox"]'),
         el.querySelectorAll<HTMLInputElement>('input[type="checkbox"]'),
       )) {
       )) {
         checkbox.disabled = !enabled;
         checkbox.disabled = !enabled;
+        checkbox.style.opacity = enabled ? '' : '0.75';
+      }
+
+      // Fade text for disabled groups
+      for (const label of Array.from(
+        el.querySelectorAll<HTMLElement>('small, .form-check-label'),
+      )) {
+        label.style.opacity = enabled ? '' : '0.5';
       }
       }
     });
     });
   }
   }

+ 0 - 96
netbox/templates/users/objectpermission.html

@@ -1,101 +1,5 @@
 {% extends 'generic/object.html' %}
 {% extends 'generic/object.html' %}
 {% load i18n %}
 {% load i18n %}
-{% load helpers %}
-{% load render_table from django_tables2 %}
 
 
 {% block title %}{% trans "Permission" %} {{ object.name }}{% endblock %}
 {% block title %}{% trans "Permission" %} {{ object.name }}{% endblock %}
-
 {% block subtitle %}{% endblock %}
 {% block subtitle %}{% endblock %}
-
-{% block content %}
-  <div class="row mb-3">
-    <div class="col-md-6">
-      <div class="card">
-        <h2 class="card-header">{% trans "Permission" %}</h2>
-        <table class="table table-hover attr-table">
-          <tr>
-            <th scope="row">{% trans "Name" %}</th>
-            <td>{{ object.name }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Description" %}</th>
-            <td>{{ object.description|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Enabled" %}</th>
-            <td>{% checkmark object.enabled %}</td>
-          </tr>
-        </table>
-      </div>
-      <div class="card">
-        <h2 class="card-header">{% trans "Actions" %}</h2>
-        <table class="table table-hover attr-table">
-          <tr>
-            <th scope="row">{% trans "View" %}</th>
-            <td>{% checkmark object.can_view %}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Add" %}</th>
-            <td>{% checkmark object.can_add %}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Change" %}</th>
-            <td>{% checkmark object.can_change %}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Delete" %}</th>
-            <td>{% checkmark object.can_delete %}</td>
-          </tr>
-          {% for action in object.actions %}
-            {% if action not in reserved_actions %}
-              <tr>
-                <th scope="row">{{ action }}</th>
-                <td>{% checkmark True %}</td>
-              </tr>
-            {% endif %}
-          {% endfor %}
-        </table>
-      </div>
-      <div class="card">
-        <h2 class="card-header">{% trans "Constraints" %}</h2>
-        <div class="card-body">
-          {% if object.constraints %}
-            <pre>{{ object.constraints|json }}</pre>
-          {% else %}
-            <span class="text-muted">None</span>
-          {% endif %}
-        </div>
-      </div>
-    </div>
-    <div class="col-md-6">
-      <div class="card">
-        <h2 class="card-header">{% trans "Object Types" %}</h2>
-        <ul class="list-group list-group-flush">
-          {% for user in object.object_types.all %}
-            <li class="list-group-item">{{ user }}</li>
-          {% endfor %}
-        </ul>
-      </div>
-      <div class="card">
-        <h2 class="card-header">{% trans "Assigned Users" %}</h2>
-        <div class="list-group list-group-flush">
-          {% for user in object.users.all %}
-            <a href="{% url 'users:user' pk=user.pk %}" class="list-group-item list-group-item-action">{{ user }}</a>
-          {% empty %}
-            <div class="list-group-item text-muted">{% trans "None" %}</div>
-          {% endfor %}
-        </div>
-      </div>
-      <div class="card">
-        <h2 class="card-header">{% trans "Assigned Groups" %}</h2>
-        <div class="list-group list-group-flush">
-          {% for group in object.groups.all %}
-            <a href="{% url 'users:group' pk=group.pk %}" class="list-group-item list-group-item-action">{{ group }}</a>
-          {% empty %}
-            <div class="list-group-item text-muted">{% trans "None" %}</div>
-          {% endfor %}
-        </div>
-      </div>
-    </div>
-  </div>
-{% endblock %}

+ 20 - 0
netbox/templates/users/panels/custom_actions.html

@@ -0,0 +1,20 @@
+{% extends "ui/panels/_base.html" %}
+{% load helpers %}
+
+{% block panel_content %}
+  <table class="table table-hover attr-table">
+    {% for action, models in custom_actions %}
+      <tr>
+        <th scope="row">{{ action }}</th>
+        <td>
+          <div class="d-flex justify-content-between align-items-start">
+            {% checkmark True %}
+            {% if models %}
+              <small class="text-muted">{{ models }}</small>
+            {% endif %}
+          </div>
+        </td>
+      </tr>
+    {% endfor %}
+  </table>
+{% endblock panel_content %}

+ 42 - 0
netbox/users/ui/panels.py

@@ -1,6 +1,8 @@
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
 
 
+from netbox.registry import registry
 from netbox.ui import actions, attrs, panels
 from netbox.ui import actions, attrs, panels
+from users.constants import RESERVED_ACTIONS
 
 
 
 
 class TokenPanel(panels.ObjectAttributesPanel):
 class TokenPanel(panels.ObjectAttributesPanel):
@@ -54,6 +56,46 @@ class ObjectPermissionActionsPanel(panels.ObjectAttributesPanel):
     can_delete = attrs.BooleanAttr('can_delete', label=_('Delete'))
     can_delete = attrs.BooleanAttr('can_delete', label=_('Delete'))
 
 
 
 
+class ObjectPermissionCustomActionsPanel(panels.ObjectPanel):
+    """
+    A panel which displays non-CRUD (custom) actions assigned to an ObjectPermission.
+    """
+    template_name = 'users/panels/custom_actions.html'
+    title = _('Custom Actions')
+
+    def get_context(self, context):
+        obj = context['object']
+        custom_actions = [a for a in obj.actions if a not in RESERVED_ACTIONS]
+
+        # Build a list of (action_name, model_labels) tuples from the registry,
+        # scoped to the object types assigned to this permission.
+        assigned_types = {
+            f'{ot.app_label}.{ot.model}' for ot in obj.object_types.all()
+        }
+        action_models = {}
+        for model_key, model_actions in registry['model_actions'].items():
+            if model_key in assigned_types:
+                for action in model_actions:
+                    if action.name in custom_actions:
+                        action_models.setdefault(action.name, []).append(model_key)
+
+        custom_actions_display = [
+            (action, ', '.join(action_models.get(action, [])))
+            for action in custom_actions
+        ]
+
+        return {
+            **super().get_context(context),
+            'custom_actions': custom_actions_display,
+        }
+
+    def render(self, context):
+        ctx = self.get_context(context)
+        if not ctx['custom_actions']:
+            return ''
+        return super().render(context)
+
+
 class OwnerPanel(panels.ObjectAttributesPanel):
 class OwnerPanel(panels.ObjectAttributesPanel):
     name = attrs.TextAttr('name')
     name = attrs.TextAttr('name')
     group = attrs.RelatedObjectAttr('group', linkify=True)
     group = attrs.RelatedObjectAttr('group', linkify=True)

+ 1 - 6
netbox/users/views.py

@@ -19,7 +19,6 @@ from utilities.query import count_related
 from utilities.views import GetRelatedModelsMixin, register_model_view
 from utilities.views import GetRelatedModelsMixin, register_model_view
 
 
 from . import filtersets, forms, tables
 from . import filtersets, forms, tables
-from .constants import RESERVED_ACTIONS
 from .models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
 from .models import Group, ObjectPermission, Owner, OwnerGroup, Token, User
 
 
 #
 #
@@ -273,6 +272,7 @@ class ObjectPermissionView(generic.ObjectView):
         left_panels=[
         left_panels=[
             panels.ObjectPermissionPanel(),
             panels.ObjectPermissionPanel(),
             panels.ObjectPermissionActionsPanel(),
             panels.ObjectPermissionActionsPanel(),
+            panels.ObjectPermissionCustomActionsPanel(),
             JSONPanel('constraints', title=_('Constraints')),
             JSONPanel('constraints', title=_('Constraints')),
         ],
         ],
         right_panels=[
         right_panels=[
@@ -286,11 +286,6 @@ class ObjectPermissionView(generic.ObjectView):
         ],
         ],
     )
     )
 
 
-    def get_extra_context(self, request, instance):
-        return {
-            'reserved_actions': RESERVED_ACTIONS,
-        }
-
 
 
 @register_model_view(ObjectPermission, 'add', detail=False)
 @register_model_view(ObjectPermission, 'add', detail=False)
 @register_model_view(ObjectPermission, 'edit')
 @register_model_view(ObjectPermission, 'edit')

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio