Add version control context processor and integrate map functionality with dedicated JavaScript

This commit is contained in:
pacnpal
2025-02-06 20:06:10 -05:00
parent f3d28817a5
commit ecf94bf84e
16 changed files with 1671 additions and 89 deletions

View File

@@ -73,7 +73,50 @@ class Park(HistoricalModel):
def save(self, *args: Any, **kwargs: Any) -> None:
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
# Get the branch from context or use default
from history_tracking.signals import get_current_branch
current_branch = get_current_branch()
if current_branch:
# Save in the context of the current branch
super().save(*args, **kwargs)
else:
# If no branch context, save in main branch
from history_tracking.models import VersionBranch
main_branch, _ = VersionBranch.objects.get_or_create(
name='main',
defaults={'metadata': {'type': 'default_branch'}}
)
from history_tracking.signals import ChangesetContextManager
with ChangesetContextManager(branch=main_branch):
super().save(*args, **kwargs)
def get_version_info(self) -> dict:
"""Get version control information for this park"""
from history_tracking.models import VersionBranch, ChangeSet
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(self)
latest_changes = ChangeSet.objects.filter(
content_type=content_type,
object_id=self.pk,
status='applied'
).order_by('-created_at')[:5]
active_branches = VersionBranch.objects.filter(
changesets__content_type=content_type,
changesets__object_id=self.pk,
is_active=True
).distinct()
return {
'latest_changes': latest_changes,
'active_branches': active_branches,
'current_branch': get_current_branch(),
'total_changes': latest_changes.count()
}
def get_absolute_url(self) -> str:
return reverse("parks:park_detail", kwargs={"slug": self.slug})
@@ -134,7 +177,51 @@ class ParkArea(HistoricalModel):
def save(self, *args: Any, **kwargs: Any) -> None:
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
# Get the branch from context or use default
from history_tracking.signals import get_current_branch
current_branch = get_current_branch()
if current_branch:
# Save in the context of the current branch
super().save(*args, **kwargs)
else:
# If no branch context, save in main branch
from history_tracking.models import VersionBranch
main_branch, _ = VersionBranch.objects.get_or_create(
name='main',
defaults={'metadata': {'type': 'default_branch'}}
)
from history_tracking.signals import ChangesetContextManager
with ChangesetContextManager(branch=main_branch):
super().save(*args, **kwargs)
def get_version_info(self) -> dict:
"""Get version control information for this park area"""
from history_tracking.models import VersionBranch, ChangeSet
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(self)
latest_changes = ChangeSet.objects.filter(
content_type=content_type,
object_id=self.pk,
status='applied'
).order_by('-created_at')[:5]
active_branches = VersionBranch.objects.filter(
changesets__content_type=content_type,
changesets__object_id=self.pk,
is_active=True
).distinct()
return {
'latest_changes': latest_changes,
'active_branches': active_branches,
'current_branch': get_current_branch(),
'total_changes': latest_changes.count(),
'parent_park_branch': self.park.get_version_info()['current_branch']
}
def get_absolute_url(self) -> str:
return reverse(

View File

@@ -0,0 +1,200 @@
{% extends "base.html" %}
{% load static %}
{% block title %}{{ park.name }} - ThrillWiki{% endblock %}
{% block content %}
<div class="container mx-auto px-4 py-8">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Main Content Column -->
<div class="lg:col-span-2">
<!-- Version Control UI -->
{% include "history_tracking/includes/version_control_ui.html" %}
<!-- Park Information -->
<div class="bg-white rounded-lg shadow-sm p-6">
<div class="flex justify-between items-start">
<h1 class="text-3xl font-bold text-gray-900">{{ park.name }}</h1>
<span class="px-3 py-1 rounded text-sm
{% if park.status == 'OPERATING' %}
bg-green-100 text-green-800
{% elif park.status == 'CLOSED_TEMP' %}
bg-yellow-100 text-yellow-800
{% elif park.status == 'UNDER_CONSTRUCTION' %}
bg-blue-100 text-blue-800
{% else %}
bg-red-100 text-red-800
{% endif %}">
{{ park.get_status_display }}
</span>
</div>
{% if park.description %}
<div class="mt-4 prose">
{{ park.description|linebreaks }}
</div>
{% endif %}
<!-- Park Details -->
<div class="mt-6 grid grid-cols-2 gap-4">
{% if park.opening_date %}
<div>
<h3 class="text-sm font-medium text-gray-500">Opening Date</h3>
<p class="mt-1">{{ park.opening_date }}</p>
</div>
{% endif %}
{% if park.size_acres %}
<div>
<h3 class="text-sm font-medium text-gray-500">Size</h3>
<p class="mt-1">{{ park.size_acres }} acres</p>
</div>
{% endif %}
{% if park.operating_season %}
<div>
<h3 class="text-sm font-medium text-gray-500">Operating Season</h3>
<p class="mt-1">{{ park.operating_season }}</p>
</div>
{% endif %}
{% if park.owner %}
<div>
<h3 class="text-sm font-medium text-gray-500">Owner</h3>
<p class="mt-1">
<a href="{{ park.owner.get_absolute_url }}" class="text-blue-600 hover:underline">
{{ park.owner.name }}
</a>
</p>
</div>
{% endif %}
</div>
</div>
<!-- Rides Section -->
<div class="mt-8">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Rides</h2>
{% if park.rides.all %}
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{% for ride in park.rides.all %}
<div class="bg-white rounded-lg shadow-sm p-4">
<h3 class="text-lg font-semibold">
<a href="{{ ride.get_absolute_url }}" class="text-blue-600 hover:underline">
{{ ride.name }}
</a>
</h3>
<p class="text-sm text-gray-600 mt-1">{{ ride.type }}</p>
</div>
{% endfor %}
</div>
{% else %}
<p class="text-gray-600">No rides listed yet.</p>
{% endif %}
</div>
<!-- Areas Section -->
{% if park.areas.exists %}
<div class="mt-8">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Areas</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{% for area in park.areas.all %}
<div class="bg-white rounded-lg shadow-sm p-4">
<h3 class="text-lg font-semibold">
<a href="{{ area.get_absolute_url }}" class="text-blue-600 hover:underline">
{{ area.name }}
</a>
</h3>
{% if area.description %}
<p class="text-sm text-gray-600 mt-1">{{ area.description|truncatewords:20 }}</p>
{% endif %}
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<!-- Sidebar -->
<div class="lg:col-span-1">
<!-- Location -->
{% if park.formatted_location %}
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
<h2 class="text-lg font-semibold mb-3">Location</h2>
<p>{{ park.formatted_location }}</p>
{% if park.coordinates %}
<div id="map"
class="h-64 mt-4 rounded-lg"
data-lat="{{ park.coordinates.0|stringformat:'f' }}"
data-lng="{{ park.coordinates.1|stringformat:'f' }}"
data-name="{{ park.name|escapejs }}">
</div>
{% endif %}
</div>
{% endif %}
<!-- Statistics -->
<div class="bg-white rounded-lg shadow-sm p-6 mb-6">
<h2 class="text-lg font-semibold mb-3">Statistics</h2>
<div class="space-y-3">
{% if park.average_rating %}
<div>
<span class="text-gray-600">Average Rating:</span>
<span class="font-medium">{{ park.average_rating }}/5</span>
</div>
{% endif %}
{% if park.ride_count %}
<div>
<span class="text-gray-600">Total Rides:</span>
<span class="font-medium">{{ park.ride_count }}</span>
</div>
{% endif %}
{% if park.coaster_count %}
<div>
<span class="text-gray-600">Roller Coasters:</span>
<span class="font-medium">{{ park.coaster_count }}</span>
</div>
{% endif %}
</div>
</div>
<!-- Photo Gallery -->
{% if park.photos.exists %}
<div class="bg-white rounded-lg shadow-sm p-6">
<h2 class="text-lg font-semibold mb-3" id="photo-gallery">Photo Gallery</h2>
<ul class="grid grid-cols-2 gap-2 list-none p-0"
aria-labelledby="photo-gallery">
{% for photo in park.photos.all|slice:":4" %}
<li class="aspect-w-1 aspect-h-1">
<img src="{{ photo.image.url }}"
alt="{% if photo.title %}{{ photo.title }} - {% endif %}{{ park.name }}"
class="object-cover rounded"
loading="lazy"
decoding="async"
fetchpriority="low"
width="300"
height="300">
</li>
{% endfor %}
</ul>
{% if park.photos.count > 4 %}
<a href="{% url 'photos:park-gallery' park.slug %}"
class="text-blue-600 hover:underline text-sm block mt-3"
aria-label="View full photo gallery of {{ park.name }}">
View all {{ park.photos.count }} photos
</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
{{ block.super }}
{% if park.coordinates %}
<script src="{% static 'js/map-init.js' %}"></script>
{% endif %}
{% endblock %}