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

@@ -0,0 +1,181 @@
/* Version Control System Styles */
.version-control-ui {
--vcs-primary: #3b82f6;
--vcs-success: #10b981;
--vcs-warning: #f59e0b;
--vcs-error: #ef4444;
--vcs-gray: #6b7280;
}
/* Branch Status Indicators */
.branch-indicator {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
font-size: 0.875rem;
font-weight: 500;
}
.branch-indicator.active {
background-color: rgba(16, 185, 129, 0.1);
color: var(--vcs-success);
}
.branch-indicator.inactive {
background-color: rgba(107, 114, 128, 0.1);
color: var(--vcs-gray);
}
/* Change Status Tags */
.change-status {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.75rem;
border-radius: 0.375rem;
font-size: 0.75rem;
font-weight: 500;
}
.change-status.applied {
background-color: rgba(16, 185, 129, 0.1);
color: var(--vcs-success);
}
.change-status.pending {
background-color: rgba(245, 158, 11, 0.1);
color: var(--vcs-warning);
}
.change-status.failed {
background-color: rgba(239, 68, 68, 0.1);
color: var(--vcs-error);
}
/* Change History */
.change-history {
border-left: 2px solid #e5e7eb;
margin-left: 1rem;
padding-left: 1rem;
}
.change-history-item {
position: relative;
padding: 1rem 0;
}
.change-history-item::before {
content: '';
position: absolute;
left: -1.25rem;
top: 1.5rem;
height: 0.75rem;
width: 0.75rem;
border-radius: 9999px;
background-color: white;
border: 2px solid var(--vcs-primary);
}
/* Merge Interface */
.merge-conflict {
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
margin: 1rem 0;
padding: 1rem;
}
.merge-conflict-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
}
.merge-conflict-content {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.merge-version {
background-color: #f9fafb;
padding: 1rem;
border-radius: 0.375rem;
}
/* Branch Selection */
.branch-selector {
position: relative;
}
.branch-list {
max-height: 24rem;
overflow-y: auto;
}
.branch-item {
display: flex;
align-items: center;
padding: 0.5rem;
border-radius: 0.375rem;
transition: background-color 0.2s;
}
.branch-item:hover {
background-color: #f9fafb;
}
.branch-item.active {
background-color: rgba(59, 130, 246, 0.1);
}
/* Version Tags */
.version-tag {
display: inline-flex;
align-items: center;
padding: 0.25rem 0.75rem;
border-radius: 9999px;
background-color: #f3f4f6;
color: var(--vcs-gray);
font-size: 0.875rem;
margin: 0.25rem;
}
/* Loading States */
.vcs-loading {
position: relative;
pointer-events: none;
opacity: 0.7;
}
.vcs-loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 1.5rem;
height: 1.5rem;
border: 2px solid #e5e7eb;
border-top-color: var(--vcs-primary);
border-radius: 50%;
animation: vcs-spin 1s linear infinite;
}
@keyframes vcs-spin {
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}
/* Responsive Design */
@media (max-width: 640px) {
.merge-conflict-content {
grid-template-columns: 1fr;
}
.branch-selector {
width: 100%;
}
}

20
static/js/map-init.js Normal file
View File

@@ -0,0 +1,20 @@
document.addEventListener('DOMContentLoaded', function() {
const mapContainer = document.getElementById('map');
if (!mapContainer) return;
const lat = parseFloat(mapContainer.dataset.lat);
const lng = parseFloat(mapContainer.dataset.lng);
const name = mapContainer.dataset.name;
if (isNaN(lat) || isNaN(lng)) return;
const map = L.map('map').setView([lat, lng], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
L.marker([lat, lng])
.addTo(map)
.bindPopup(name);
});

View File

@@ -0,0 +1,155 @@
// Version Control System Functionality
class VersionControl {
constructor() {
this.setupEventListeners();
}
setupEventListeners() {
// Branch switching
document.addEventListener('htmx:afterRequest', (event) => {
if (event.detail.target.id === 'branch-form-container') {
this.handleBranchFormResponse(event);
}
});
// Listen for branch switches
document.addEventListener('branch-switched', () => {
this.refreshContent();
});
// Handle merge operations
document.addEventListener('htmx:afterRequest', (event) => {
if (event.detail.target.id === 'merge-panel') {
this.handleMergeResponse(event);
}
});
}
handleBranchFormResponse(event) {
if (event.detail.successful) {
// Clear the branch form container
document.getElementById('branch-form-container').innerHTML = '';
// Trigger branch list refresh
document.body.dispatchEvent(new CustomEvent('branch-updated'));
}
}
handleMergeResponse(event) {
if (event.detail.successful) {
const mergePanel = document.getElementById('merge-panel');
if (mergePanel.innerHTML.includes('Merge Successful')) {
// Trigger content refresh after successful merge
setTimeout(() => {
this.refreshContent();
}, 1500);
}
}
}
refreshContent() {
// Reload the page to show content from new branch
window.location.reload();
}
// Branch operations
createBranch(name, parentBranch = null) {
const formData = new FormData();
formData.append('name', name);
if (parentBranch) {
formData.append('parent', parentBranch);
}
return fetch('/vcs/branches/create/', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': this.getCsrfToken()
}
}).then(response => response.json());
}
switchBranch(branchName) {
const formData = new FormData();
formData.append('branch', branchName);
return fetch('/vcs/branches/switch/', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': this.getCsrfToken()
}
}).then(response => {
if (response.ok) {
document.body.dispatchEvent(new CustomEvent('branch-switched'));
}
return response.json();
});
}
// Merge operations
initiateMerge(sourceBranch, targetBranch) {
const formData = new FormData();
formData.append('source', sourceBranch);
formData.append('target', targetBranch);
return fetch('/vcs/merge/', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': this.getCsrfToken()
}
}).then(response => response.json());
}
resolveConflicts(resolutions) {
return fetch('/vcs/resolve-conflicts/', {
method: 'POST',
body: JSON.stringify(resolutions),
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': this.getCsrfToken()
}
}).then(response => response.json());
}
// History operations
getHistory(branch = null) {
let url = '/vcs/history/';
if (branch) {
url += `?branch=${encodeURIComponent(branch)}`;
}
return fetch(url)
.then(response => response.json());
}
// Utility functions
getCsrfToken() {
return document.querySelector('[name=csrfmiddlewaretoken]').value;
}
showError(message) {
const errorDiv = document.createElement('div');
errorDiv.className = 'bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4';
errorDiv.innerHTML = `
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-red-500" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
</svg>
</div>
<div class="ml-3">
<p>${message}</p>
</div>
</div>
`;
document.querySelector('.version-control-ui').prepend(errorDiv);
setTimeout(() => errorDiv.remove(), 5000);
}
}
// Initialize version control
document.addEventListener('DOMContentLoaded', () => {
window.versionControl = new VersionControl();
});