Files
itflow/agent/js/tickets_kanban.js

125 lines
4.6 KiB
JavaScript

document.addEventListener('DOMContentLoaded', function () {
// -------------------------------
// Drag: Kanban Columns (Statuses)
// -------------------------------
new Sortable(document.querySelector('#kanban-board'), {
animation: 150,
handle: '.kanban-column-header',
draggable: '.kanban-column',
onEnd: function () {
const columnPositions = Array.from(document.querySelectorAll('#kanban-board .kanban-column')).map((col, index) => ({
status_id: col.dataset.statusId,
status_kanban: index
}));
if (CONFIG_TICKET_MOVING_COLUMNS === 1) {
itflowPostForm('ajax.php', {
update_kanban_status_position: true,
positions: columnPositions
}).catch((err) => {
console.error('Error updating status order:', err);
});
}
}
});
// -------------------------------
// Drag: Tasks within Columns
// -------------------------------
document.querySelectorAll('.kanban-status').forEach(statusCol => {
new Sortable(statusCol, {
group: 'tickets',
animation: 150,
// Let the ticket number / subject links work without starting a drag
filter: 'a',
preventOnFilter: false,
handle: isTouchDevice() ? '.drag-handle-class' : undefined,
onStart: () => hidePlaceholders(),
onEnd: function (evt) {
const target = evt.to;
const movedEl = evt.item;
// Disallow reordering in same column if config says so
if (CONFIG_TICKET_ORDERING === 0 && evt.from === evt.to) {
evt.from.insertBefore(movedEl, evt.from.children[evt.oldIndex]);
showPlaceholders();
return;
}
const columnId = target.dataset.statusId;
const positions = Array.from(target.querySelectorAll('.task')).map((card, index) => {
const ticketId = card.dataset.ticketId;
const oldStatus = ticketId === movedEl.dataset.ticketId
? movedEl.dataset.ticketStatusId
: false;
card.dataset.ticketStatusId = columnId; // update DOM
return {
ticket_id: ticketId,
ticket_order: index,
ticket_oldStatus: oldStatus,
ticket_status: columnId
};
});
itflowPostForm('ajax.php', {
update_kanban_ticket: true,
positions: positions
}).catch((err) => {
console.error('Error updating ticket positions:', err);
});
// Refresh placeholders after update
showPlaceholders();
}
});
});
// -------------------------------
// 📱 Touch Support: Show drag handle on mobile
// -------------------------------
if (isTouchDevice()) {
document.querySelectorAll('.drag-handle-class').forEach(function (el) {
el.style.display = 'inline';
});
}
// -------------------------------
// Placeholder Management
// -------------------------------
function showPlaceholders() {
document.querySelectorAll('.kanban-status').forEach(status => {
const placeholderClass = 'empty-placeholder';
// Remove existing placeholder
const existing = status.querySelector(`.${placeholderClass}`);
if (existing) existing.remove();
// Only show if there are no tasks
if (status.querySelectorAll('.task').length === 0) {
const placeholder = document.createElement('div');
placeholder.className = `${placeholderClass} text-muted text-center p-2`;
placeholder.innerText = 'Drop ticket here';
placeholder.style.pointerEvents = 'none';
status.appendChild(placeholder);
}
});
}
function hidePlaceholders() {
document.querySelectorAll('.empty-placeholder').forEach(el => el.remove());
}
// Run once on load
showPlaceholders();
// -------------------------------
// Utility: Detect touch device
// -------------------------------
function isTouchDevice() {
return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
}
});