[UPDT] HORILLA: Add HX-Refresh response handling to login_required for HTMX requests
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user