Show all registered actions with enable/disable instead of show/hide

This commit is contained in:
Jason Novinger
2026-03-30 09:30:33 -05:00
parent 2bd8f9d677
commit cf6599d9f8
5 changed files with 24 additions and 34 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
import { getElements } from '../util';
/**
* Show/hide registered action checkboxes based on selected object_types.
* Enable/disable registered action checkboxes based on selected object_types.
*/
export function initRegisteredActions(): void {
const actionsContainer = document.getElementById('id_registered_actions_container');
@@ -11,7 +11,7 @@ export function initRegisteredActions(): void {
return;
}
function updateVisibility(): void {
function updateState(): void {
const selectedModels = new Set<string>();
// Get model keys from selected options
@@ -22,40 +22,33 @@ export function initRegisteredActions(): void {
}
}
// Show/hide action groups
// Enable/disable action groups based on selected models
const groups = actionsContainer!.querySelectorAll('.model-actions');
let anyVisible = false;
groups.forEach(group => {
const modelKey = group.getAttribute('data-model');
const visible = modelKey !== null && selectedModels.has(modelKey);
(group as HTMLElement).style.display = visible ? 'block' : 'none';
if (visible) {
anyVisible = true;
const enabled = modelKey !== null && selectedModels.has(modelKey);
const el = group as HTMLElement;
el.style.opacity = enabled ? '1' : '0.4';
// Toggle disabled on checkboxes within the group
for (const checkbox of Array.from(
el.querySelectorAll<HTMLInputElement>('input[type="checkbox"]'),
)) {
checkbox.disabled = !enabled;
}
});
// Show/hide "no actions" message
const noActionsMsg = document.getElementById('no-custom-actions-message');
if (noActionsMsg) {
noActionsMsg.style.display = anyVisible ? 'none' : 'block';
}
// Hide the entire field row when no actions are visible
const fieldRow = actionsContainer!.closest('.field-row, .mb-3');
if (fieldRow) {
(fieldRow as HTMLElement).style.display = anyVisible ? '' : 'none';
}
}
// Initial update
updateVisibility();
updateState();
// Listen to move button clicks
for (const btn of getElements<HTMLButtonElement>('.move-option')) {
btn.addEventListener('click', () => {
// Wait for DOM update
setTimeout(updateVisibility, 50);
setTimeout(updateState, 50);
});
}
}

View File

@@ -352,7 +352,7 @@ class ObjectPermissionForm(forms.ModelForm):
label=_('Additional actions'),
base_field=forms.CharField(),
required=False,
help_text=_('Actions granted in addition to those listed above')
help_text=_('Additional actions for models which have not yet registered their own actions')
)
users = DynamicModelMultipleChoiceField(
label=_('Users'),

View File

@@ -1,15 +1,16 @@
{% load i18n %}
<div class="registered-actions-container" id="id_registered_actions_container">
{% for model_key, model_data in widget.model_actions.items %}
<div class="model-actions" data-model="{{ model_key }}" style="display: none;">
<h5 class="mb-2 mt-3">{{ model_data.label }}</h5>
<div class="model-actions" data-model="{{ model_key }}">
<small class="text-muted d-block mt-3 mb-1">{{ model_data.label }}</small>
{% for action in model_data.actions %}
<div class="form-check">
<div class="form-check mb-0">
<input type="checkbox"
class="form-check-input"
name="{{ widget.name }}"
value="{{ model_key }}.{{ action.name }}"
id="id_{{ widget.name }}_{{ forloop.parentloop.counter }}_{{ forloop.counter }}"
disabled
{% if model_key|add:"."|add:action.name in widget.value %}checked{% endif %}>
<label class="form-check-label" for="id_{{ widget.name }}_{{ forloop.parentloop.counter }}_{{ forloop.counter }}">
{{ action.name }}
@@ -20,9 +21,5 @@
</div>
{% endfor %}
</div>
{% empty %}
<p class="text-muted" id="no-custom-actions-message">
{% trans "No custom actions registered." %}
</p>
{% endfor %}
</div>