[UPDT] HORILLA: Add HX-Refresh response handling to login_required for HTMX requests

This commit is contained in:
Horilla
2025-08-01 12:20:56 +05:30
parent bb12035b4e
commit 232e469a2b
2 changed files with 70 additions and 68 deletions

View File

@@ -258,6 +258,8 @@ def login_required(view_func):
or not employee
or not employee.is_active
):
if request.headers.get("HX-Request"):
return HttpResponse(status=204, headers={"HX-Refresh": "true"})
return redirect(redirect_url)
try:
func = view_func(request, *args, **kwargs)

View File

@@ -99,9 +99,9 @@
$(document).ready(function () {
// Define the viewId
var viewId = '#{{view_id}}'
let draggedCard = null
// Initialize drag events for cards
function initDragAndDrop() {
// Drag start
@@ -111,44 +111,44 @@
draggedCard.addClass('dragging')
}, 0)
})
// Drag end
$(viewId + ' .kanban-card').on('dragend', function () {
$(this).removeClass('dragging')
draggedCard = null
updateTaskCounts()
})
// Handle dragover to allow drops
$(viewId + ' .cards-container').on('dragover', function (e) {
e.preventDefault()
$(this).addClass('drop-zone')
})
// Remove drop zone highlighting
$(viewId + ' .cards-container').on('dragleave', function () {
$(this).removeClass('drop-zone')
})
// Handle drops
$(viewId + ' .cards-container').on('drop', function (e) {
e.preventDefault()
$(this).removeClass('drop-zone')
if (draggedCard) {
// Find the "Add task" button and insert before it
const addTaskButton = $(this).find('.add-task')
draggedCard.insertBefore(addTaskButton)
const itemId = draggedCard.data('id')
const column = $(this).closest('.kanban-column')
const newStage = column.data('stage')
console.log(`Item ${itemId} moved to ${newStage}`)
// Update card styling based on new column
updateCardStyling(draggedCard, newStage)
// 🔁 Replace with AJAX to update backend
/*
$.ajax({
@@ -167,28 +167,28 @@
}
})
}
// Initialize profile dropdowns for cards
function initProfileDropdowns() {
// Avatar click to show dropdown
$(viewId).on('click', '.avatar, .avatar-placeholder', function (e) {
e.stopPropagation()
const dropdown = $(this).siblings('.assignee-dropdown')
// Close all other dropdowns first
$(viewId + ' .assignee-dropdown.active')
.not(dropdown)
.removeClass('active')
// Toggle this dropdown
dropdown.toggleClass('active')
})
// Assignee selection
$(viewId).on('click', '.assignee-option', function () {
const profileContainer = $(this).closest('.profile-container')
const initials = $(this).data('initials')
if (initials === 'UN') {
// Unassign
profileContainer.find('.avatar, .avatar-placeholder').replaceWith($('<div class="avatar-placeholder" title="Unassigned">+</div>'))
@@ -197,39 +197,39 @@
const personName = $(this).find('span').text()
const avatar = $(this).find('.avatar').clone()
avatar.attr('title', personName)
profileContainer.find('.avatar, .avatar-placeholder').replaceWith(avatar)
}
// Close dropdown
profileContainer.find('.assignee-dropdown').removeClass('active')
})
// Close dropdowns when clicking elsewhere
$(document).on('click', function () {
$(viewId + ' .assignee-dropdown.active').removeClass('active')
})
}
// Initialize column collapse/expand functionality
function initColumnCollapse() {
$(viewId + ' .column-header').on('click', function () {
$(this).closest('.kanban-column').toggleClass('collapsed')
})
}
// Handle adding new tasks
function initAddTask() {
$(viewId + ' .add-task').on('click', function () {
const column = $(this).closest('.kanban-column')
const stage = column.data('stage')
// Create a new card
const newCard = createNewTaskCard(stage)
// Add it before the add button
$(this).before(newCard)
// Initialize drag events for the new card
newCard
.on('dragstart', function () {
@@ -243,19 +243,19 @@
draggedCard = null
updateTaskCounts()
})
// Update counts
updateTaskCounts()
console.log(`New task created in ${stage}`)
})
}
// Create a new task card
function createNewTaskCard(stage) {
// Create unique ID for the card
const newId = Date.now()
// Create the card with proper structure
const newCard = $('<div class="kanban-card" draggable="true"></div>').attr('data-id', newId).append(`
<div class="card-title">New Task</div>
@@ -288,13 +288,13 @@
</div>
</div>
`)
// Apply styling based on column
updateCardStyling(newCard, stage)
return newCard
}
// Update card styling based on column
function updateCardStyling(card, stage) {
if (stage === 'todo') {
@@ -314,7 +314,7 @@
})
}
}
// Update task counts for each column
function updateTaskCounts() {
$(viewId + ' .kanban-column').each(function () {
@@ -322,7 +322,7 @@
$(this).find('.task-count').text(cardCount)
})
}
// Initialize everything
function init() {
initDragAndDrop()
@@ -331,7 +331,7 @@
initAddTask()
updateTaskCounts()
}
// Run initialization
init()
})
@@ -342,9 +342,9 @@
const columns = document.querySelectorAll('.kanban-column')
const cardsContainers = document.querySelectorAll('.cards-container')
const addTaskButtons = document.querySelectorAll('.add-task')
let draggedCard = null
// Initialize card dragging
cards.forEach((card) => {
card.addEventListener('dragstart', () => {
@@ -353,19 +353,19 @@
card.classList.add('dragging')
}, 0)
})
card.addEventListener('dragend', () => {
draggedCard = null
card.classList.remove('dragging')
updateTaskCounts()
})
// Set up profile dropdown functionality
const profileContainer = card.querySelector('.profile-container')
if (profileContainer) {
const avatar = profileContainer.querySelector('.avatar, .avatar-placeholder')
const dropdown = profileContainer.querySelector('.assignee-dropdown')
avatar.addEventListener('click', (e) => {
e.stopPropagation()
// Close all other dropdowns first
@@ -376,14 +376,14 @@
})
dropdown.classList.toggle('active')
})
// Handle assignee selection
const assigneeOptions = dropdown.querySelectorAll('.assignee-option')
assigneeOptions.forEach((option) => {
option.addEventListener('click', () => {
const initials = option.getAttribute('data-initials')
const currentAvatar = profileContainer.querySelector('.avatar, .avatar-placeholder')
if (initials === 'UN') {
// Unassign
profileContainer.innerHTML = `
@@ -403,16 +403,16 @@
</div>
`
}
// Reset event listeners for the new elements
const newDropdown = profileContainer.querySelector('.assignee-dropdown')
const newAvatar = profileContainer.querySelector('.avatar, .avatar-placeholder')
newAvatar.addEventListener('click', (e) => {
e.stopPropagation()
newDropdown.classList.toggle('active')
})
// Reset assignee option event listeners
const newOptions = newDropdown.querySelectorAll('.assignee-option')
newOptions.forEach((newOpt) => {
@@ -422,13 +422,13 @@
this.click() // This is a simplified approach
})
})
dropdown.classList.remove('active')
})
})
}
})
// Handle column collapse
document.querySelectorAll('.column-header').forEach((header) => {
header.addEventListener('click', () => {
@@ -436,43 +436,43 @@
column.classList.toggle('collapsed')
})
})
// Close dropdowns when clicking outside
document.addEventListener('click', () => {
document.querySelectorAll('.assignee-dropdown.active').forEach((dropdown) => {
dropdown.classList.remove('active')
})
})
// Handle drag and drop for columns
cardsContainers.forEach((container) => {
container.addEventListener('dragover', (e) => {
e.preventDefault()
container.classList.add('drop-zone')
})
container.addEventListener('dragleave', () => {
container.classList.remove('drop-zone')
})
container.addEventListener('drop', (e) => {
e.preventDefault()
container.classList.remove('drop-zone')
if (draggedCard) {
// Find the "Add task" button and insert before it
const addTaskButton = container.querySelector('.add-task')
container.insertBefore(draggedCard, addTaskButton)
const itemId = draggedCard.getAttribute('data-id')
const column = container.closest('.kanban-column')
const newStage = column.getAttribute('data-stage')
console.log(`Item ${itemId} moved to ${newStage}`)
// Update card styling based on new column
updateCardStyling(draggedCard, newStage)
// 🔁 Replace with AJAX to update backend
/*
fetch('/api/kanban/update-stage/', {
@@ -490,21 +490,21 @@
}
})
})
// Handle add task button clicks
addTaskButtons.forEach((button) => {
button.addEventListener('click', () => {
const column = button.closest('.kanban-column')
const stage = column.getAttribute('data-stage')
const container = column.querySelector('.cards-container')
// Create a new card with a unique ID (this is just for demo purposes)
const newId = Date.now()
const newCard = document.createElement('div')
newCard.className = 'kanban-card'
newCard.setAttribute('draggable', 'true')
newCard.setAttribute('data-id', newId)
// Set the default content for the new card
newCard.innerHTML = `
<div class="card-title">New Task</div>
@@ -514,13 +514,13 @@
<span>Today</span>
</div>
`
// Apply styling based on the column
updateCardStyling(newCard, stage)
// Add the new card before the add task button
container.insertBefore(newCard, button)
// Set up drag events for the new card
newCard.addEventListener('dragstart', () => {
draggedCard = newCard
@@ -528,26 +528,26 @@
newCard.classList.add('dragging')
}, 0)
})
newCard.addEventListener('dragend', () => {
draggedCard = null
newCard.classList.remove('dragging')
updateTaskCounts()
})
// Update counts
updateTaskCounts()
console.log(`New task created in ${stage}`)
})
})
// Function to update card styling based on column
function updateCardStyling(card, stage) {
// Remove all potential styling classes first
card.style.borderLeftColor = ''
card.style.background = ''
// Apply styling based on stage
if (stage === 'todo') {
card.style.borderLeftColor = '#f43f5e'
@@ -560,7 +560,7 @@
card.style.background = '#ecfdf5'
}
}
// Function to update task counts
function updateTaskCounts() {
columns.forEach((column) => {
@@ -569,7 +569,7 @@
countSpan.textContent = cards
})
}
// Initial count update
updateTaskCounts()
</script>