Files
thrillwiki_django_no_react/backend/templates/htmx/state_actions.html
pacnpal 45d97b6e68 Add test utilities and state machine diagrams for FSM models
- Introduced reusable test utilities in `backend/tests/utils` for FSM transitions, HTMX interactions, and common scenarios.
- Added factory functions for creating test submissions, parks, rides, and photo submissions.
- Implemented assertion helpers for verifying state changes, toast notifications, and transition logs.
- Created comprehensive state machine diagrams for all FSM-enabled models in `docs/STATE_DIAGRAMS.md`, detailing states, transitions, and guard conditions.
2025-12-22 08:55:39 -05:00

59 lines
2.7 KiB
HTML

{% comment %}
FSM State Actions Partial Template
Renders available transition buttons for an FSM-enabled object.
Uses HTMX for seamless state transitions with toast notifications.
Required context:
- object: The FSM-enabled model instance
- user: The current user (usually request.user)
Optional context:
- target_id: The ID of the element to swap after transition (defaults to object-{{ object.id }})
- button_size: 'sm', 'md', or 'lg' (defaults to 'md')
- show_labels: Whether to show button labels (defaults to true)
- inline: Whether to render buttons inline (defaults to false)
{% endcomment %}
{% load fsm_tags %}
{% get_available_transitions object user as transitions %}
{% if transitions %}
<div class="fsm-actions flex {% if inline %}flex-row gap-2{% else %}flex-wrap gap-2{% endif %}"
id="actions-{{ object.id }}">
{% for transition in transitions %}
<button
type="button"
hx-post="{% url 'core:fsm_transition' app_label=object|app_label model_name=object|model_name pk=object.pk transition_name=transition.name %}"
hx-target="#{{ target_id|default:object|default_target_id }}"
hx-swap="outerHTML"
{% if transition.requires_confirm %}
hx-confirm="{{ transition.confirm_message|default:'Are you sure?' }}"
{% endif %}
hx-indicator="#loading-{{ object.id }}"
class="inline-flex items-center justify-center gap-1.5 px-{% if button_size == 'sm' %}2.5 py-1.5 text-xs{% elif button_size == 'lg' %}5 py-3 text-base{% else %}4 py-2.5 text-sm{% endif %} font-medium rounded-lg transition-all duration-200 shadow-xs hover:shadow-md
{% if transition.style == 'green' %}
bg-green-600 text-white hover:bg-green-500 dark:bg-green-700 dark:hover:bg-green-600
{% elif transition.style == 'red' %}
bg-red-600 text-white hover:bg-red-500 dark:bg-red-700 dark:hover:bg-red-600
{% elif transition.style == 'yellow' %}
bg-yellow-600 text-white hover:bg-yellow-500 dark:bg-yellow-700 dark:hover:bg-yellow-600
{% elif transition.style == 'blue' %}
bg-blue-600 text-white hover:bg-blue-500 dark:bg-blue-700 dark:hover:bg-blue-600
{% else %}
bg-gray-600 text-white hover:bg-gray-500 dark:bg-gray-700 dark:hover:bg-gray-600
{% endif %}">
<i class="fas fa-{{ transition.icon|default:'arrow-right' }}"></i>
{% if show_labels|default:True %}
<span>{{ transition.label }}</span>
{% endif %}
</button>
{% endfor %}
<!-- Loading indicator -->
<span id="loading-{{ object.id }}" class="htmx-indicator inline-flex items-center">
<i class="fas fa-spinner fa-spin text-blue-500"></i>
</span>
</div>
{% endif %}