mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-22 20:31:10 -05:00
- 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.
189 lines
6.4 KiB
HTML
189 lines
6.4 KiB
HTML
{% extends "base/base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}Transition History - ThrillWiki Moderation{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
/* HTMX Loading States */
|
|
.htmx-request .htmx-indicator {
|
|
opacity: 1;
|
|
}
|
|
|
|
.htmx-request.htmx-indicator {
|
|
opacity: 1;
|
|
}
|
|
|
|
.htmx-indicator {
|
|
opacity: 0;
|
|
transition: opacity 200ms ease-in-out;
|
|
}
|
|
|
|
/* State cloak for Alpine.js */
|
|
[x-cloak] {
|
|
display: none !important;
|
|
}
|
|
|
|
/* Custom scrollbar for history table */
|
|
.overflow-x-auto::-webkit-scrollbar {
|
|
height: 8px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-track {
|
|
background: rgba(0, 0, 0, 0.1);
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-thumb {
|
|
background: rgba(0, 0, 0, 0.2);
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.dark .overflow-x-auto::-webkit-scrollbar-track {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.dark .overflow-x-auto::-webkit-scrollbar-thumb {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
}
|
|
|
|
.dark .overflow-x-auto::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
/* Animation for row hover */
|
|
tbody tr {
|
|
transition: background-color 150ms ease-in-out;
|
|
}
|
|
|
|
/* Skeleton loading animation */
|
|
.animate-pulse {
|
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% {
|
|
opacity: 1;
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container max-w-7xl px-4 py-6 mx-auto">
|
|
<!-- Page Header -->
|
|
<div class="mb-6">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
|
|
<i class="mr-2 text-blue-500 fas fa-history"></i>
|
|
Transition History
|
|
</h1>
|
|
<p class="mt-1 text-sm text-gray-600 dark:text-gray-400">
|
|
View all state machine transitions across the system
|
|
</p>
|
|
</div>
|
|
<a href="{% url 'moderation:dashboard' %}"
|
|
class="inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 dark:bg-gray-800 dark:text-gray-300 dark:border-gray-600 dark:hover:bg-gray-700">
|
|
<i class="mr-2 fas fa-arrow-left"></i>
|
|
Back to Dashboard
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
{% include 'moderation/partials/history_filters.html' %}
|
|
|
|
<!-- History Table Container -->
|
|
<div id="history-table-wrapper" class="relative">
|
|
<div id="history-table-container"
|
|
hx-get="{% url 'moderation:moderation-reports-all-history' %}"
|
|
hx-trigger="load"
|
|
hx-indicator="#page-loading"
|
|
hx-swap="outerHTML">
|
|
<!-- Initial Loading State -->
|
|
<div class="overflow-hidden bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
|
<div class="p-8">
|
|
<div class="flex flex-col items-center justify-center">
|
|
<div class="w-16 h-16 mb-4 bg-gray-200 rounded-full animate-pulse dark:bg-gray-700"></div>
|
|
<div class="w-48 h-4 mb-2 bg-gray-200 rounded animate-pulse dark:bg-gray-700"></div>
|
|
<div class="w-32 h-3 bg-gray-200 rounded animate-pulse dark:bg-gray-700"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Page Loading Indicator -->
|
|
<div id="page-loading" class="absolute inset-0 flex items-center justify-center bg-white/75 dark:bg-gray-800/75 htmx-indicator">
|
|
<div class="flex flex-col items-center">
|
|
<i class="mb-2 text-3xl text-blue-500 fas fa-spinner fa-spin"></i>
|
|
<span class="text-sm text-gray-600 dark:text-gray-400">Loading history...</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- History Detail Modal -->
|
|
{% include 'moderation/partials/history_detail_modal.html' %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
// HTMX Configuration
|
|
document.body.addEventListener('htmx:configRequest', function(evt) {
|
|
evt.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
|
|
});
|
|
|
|
// Handle successful history table loads
|
|
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
|
if (evt.detail.target.id === 'history-table-container') {
|
|
console.log('History table updated');
|
|
}
|
|
});
|
|
|
|
// Handle errors
|
|
document.body.addEventListener('htmx:responseError', function(evt) {
|
|
if (evt.detail.target.id === 'history-table-container') {
|
|
console.error('Failed to load history:', evt.detail.error);
|
|
// Show error message in the container
|
|
evt.detail.target.innerHTML = `
|
|
<div class="overflow-hidden bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
|
|
<div class="px-4 py-12 text-center">
|
|
<div class="flex flex-col items-center justify-center">
|
|
<div class="flex items-center justify-center w-16 h-16 mb-4 text-red-500 bg-red-100 rounded-full dark:bg-red-900/30">
|
|
<i class="text-2xl fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<h3 class="mb-1 text-sm font-medium text-gray-900 dark:text-gray-300">Failed to load history</h3>
|
|
<p class="mb-4 text-sm text-gray-500 dark:text-gray-400">There was an error loading the transition history.</p>
|
|
<button class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-500"
|
|
hx-get="{% url 'moderation:moderation-reports-all-history' %}"
|
|
hx-target="#history-table-container"
|
|
hx-swap="outerHTML">
|
|
<i class="mr-2 fas fa-sync-alt"></i>
|
|
Try Again
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
htmx.process(evt.detail.target);
|
|
}
|
|
});
|
|
|
|
// History modal event handler
|
|
document.addEventListener('open-history-modal', function() {
|
|
const modal = document.querySelector('#history-detail-modal');
|
|
if (modal && modal.__x) {
|
|
modal.__x.$data.open = true;
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|