mirror of
https://github.com/netbox-community/netbox.git
synced 2026-04-20 16:01:34 +02:00
Improve detail view: human-friendly descriptions and additional actions
Return dicts from get_registered_actions() with help_text and verbose model names. Add get_additional_actions() for manually-entered actions that aren't CRUD or registered. Show both in the Actions panel.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
{% extends "ui/panels/_base.html" %}
|
{% extends "ui/panels/_base.html" %}
|
||||||
{% load helpers %}
|
{% load helpers i18n %}
|
||||||
|
|
||||||
{% block panel_content %}
|
{% block panel_content %}
|
||||||
<table class="table table-hover attr-table">
|
<table class="table table-hover attr-table">
|
||||||
@@ -9,18 +9,24 @@
|
|||||||
<td>{% checkmark enabled %}</td>
|
<td>{% checkmark enabled %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for action, enabled, models in registered_actions %}
|
{% for action in registered_actions %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{{ action }}</th>
|
<th scope="row">{{ action.help_text|default:action.name }}</th>
|
||||||
<td>
|
<td>
|
||||||
<div class="d-flex justify-content-between align-items-start">
|
<div class="d-flex justify-content-between align-items-start">
|
||||||
{% checkmark enabled %}
|
{% checkmark action.enabled %}
|
||||||
{% if models %}
|
{% if action.models %}
|
||||||
<small class="text-muted">{{ models|join:", " }}</small>
|
<small class="text-muted">{{ action.models|join:", "|title }}</small>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if additional_actions %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Additional actions" %}</th>
|
||||||
|
<td>{{ additional_actions|join:", " }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
{% endblock panel_content %}
|
{% endblock panel_content %}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from django.apps import apps
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@@ -86,20 +87,52 @@ class ObjectPermission(CloningMixin, models.Model):
|
|||||||
|
|
||||||
def get_registered_actions(self):
|
def get_registered_actions(self):
|
||||||
"""
|
"""
|
||||||
Return a list of (action_name, is_enabled, model_keys) tuples for all
|
Return a list of dicts for all registered actions:
|
||||||
registered actions, indicating which are enabled on this permission.
|
name: The action identifier
|
||||||
|
help_text: Human-friendly description (first registration wins)
|
||||||
|
enabled: Whether this action is enabled on this permission
|
||||||
|
models: Sorted list of human-friendly model verbose names
|
||||||
"""
|
"""
|
||||||
enabled_actions = set(self.actions) - set(RESERVED_ACTIONS)
|
enabled_actions = set(self.actions) - set(RESERVED_ACTIONS)
|
||||||
|
|
||||||
|
action_info = {}
|
||||||
action_models = {}
|
action_models = {}
|
||||||
for model_key, model_actions in registry['model_actions'].items():
|
for model_key, model_actions in registry['model_actions'].items():
|
||||||
|
app_label, model_name = model_key.split('.')
|
||||||
|
try:
|
||||||
|
verbose_name = str(apps.get_model(app_label, model_name)._meta.verbose_name)
|
||||||
|
except LookupError:
|
||||||
|
verbose_name = model_key
|
||||||
for action in model_actions:
|
for action in model_actions:
|
||||||
action_models.setdefault(action.name, []).append(model_key)
|
# First registration's help_text wins for shared action names
|
||||||
|
if action.name not in action_info:
|
||||||
|
action_info[action.name] = action
|
||||||
|
action_models.setdefault(action.name, []).append(verbose_name)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
(name, name in enabled_actions, sorted(action_models[name]))
|
{
|
||||||
|
'name': name,
|
||||||
|
'help_text': action_info[name].help_text,
|
||||||
|
'enabled': name in enabled_actions,
|
||||||
|
'models': sorted(action_models[name]),
|
||||||
|
}
|
||||||
for name in sorted(action_models)
|
for name in sorted(action_models)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def get_additional_actions(self):
|
||||||
|
"""
|
||||||
|
Return a sorted list of actions that are neither CRUD nor registered.
|
||||||
|
These are manually-entered actions from the "Additional actions" field.
|
||||||
|
"""
|
||||||
|
registered_names = set()
|
||||||
|
for model_actions in registry['model_actions'].values():
|
||||||
|
for action in model_actions:
|
||||||
|
registered_names.add(action.name)
|
||||||
|
|
||||||
|
return sorted(
|
||||||
|
a for a in self.actions
|
||||||
|
if a not in RESERVED_ACTIONS and a not in registered_names
|
||||||
|
)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('users:objectpermission', args=[self.pk])
|
return reverse('users:objectpermission', args=[self.pk])
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ class ObjectPermissionActionsPanel(panels.ObjectPanel):
|
|||||||
**super().get_context(context),
|
**super().get_context(context),
|
||||||
'crud_actions': crud_actions,
|
'crud_actions': crud_actions,
|
||||||
'registered_actions': obj.get_registered_actions(),
|
'registered_actions': obj.get_registered_actions(),
|
||||||
|
'additional_actions': obj.get_additional_actions(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -167,11 +167,11 @@ class ObjectPermissionFormTest(TestCase):
|
|||||||
|
|
||||||
registered = permission.get_registered_actions()
|
registered = permission.get_registered_actions()
|
||||||
self.assertEqual(len(registered), 1)
|
self.assertEqual(len(registered), 1)
|
||||||
action_name, is_enabled, model_keys = registered[0]
|
action = registered[0]
|
||||||
self.assertEqual(action_name, 'render_config')
|
self.assertEqual(action['name'], 'render_config')
|
||||||
self.assertTrue(is_enabled)
|
self.assertEqual(action['help_text'], '')
|
||||||
self.assertIn('dcim.device', model_keys)
|
self.assertTrue(action['enabled'])
|
||||||
self.assertIn('virtualization.virtualmachine', model_keys)
|
self.assertEqual(action['models'], ['device', 'virtual machine'])
|
||||||
|
|
||||||
permission.delete()
|
permission.delete()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user