mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-23 03:31:09 -05:00
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.
This commit is contained in:
188
backend/templates/moderation/history.html
Normal file
188
backend/templates/moderation/history.html
Normal file
@@ -0,0 +1,188 @@
|
||||
{% 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 %}
|
||||
Reference in New Issue
Block a user