style: aggiunte iconcine per copia numero ticket e titolo nella pagina di riepilogo del ticket e copia titolo nella pagina ticket/a mio carico. style: rimosso link apri in otrs sul titolo dell'header di un ticket
This commit is contained in:
@@ -13,7 +13,7 @@ const TicketDetailView = {
|
|||||||
const body = this.noteQuill ? this.noteQuill.root.innerHTML.trim() : '';
|
const body = this.noteQuill ? this.noteQuill.root.innerHTML.trim() : '';
|
||||||
const subject = document.getElementById('note-subject') ? document.getElementById('note-subject').value.trim() : '';
|
const subject = document.getElementById('note-subject') ? document.getElementById('note-subject').value.trim() : '';
|
||||||
const time_unit = document.getElementById('note-time-units') ? document.getElementById('note-time-units').value.trim() : '';
|
const time_unit = document.getElementById('note-time-units') ? document.getElementById('note-time-units').value.trim() : '';
|
||||||
|
|
||||||
if ((body !== '<p><br></p>' && body !== '') || subject !== '' || time_unit !== '' || this.noteAttachments.length > 0) {
|
if ((body !== '<p><br></p>' && body !== '') || subject !== '' || time_unit !== '' || this.noteAttachments.length > 0) {
|
||||||
App.saveDraft(this.ticketId, {
|
App.saveDraft(this.ticketId, {
|
||||||
type: 'note',
|
type: 'note',
|
||||||
@@ -96,7 +96,7 @@ const TicketDetailView = {
|
|||||||
const data = await App.api(`/api/tickets/${id}`);
|
const data = await App.api(`/api/tickets/${id}`);
|
||||||
const { ticket, articles, attachments } = data;
|
const { ticket, articles, attachments } = data;
|
||||||
// No automatic tab creation here anymore
|
// No automatic tab creation here anymore
|
||||||
|
|
||||||
let groupsData = { asMaster: [], asMember: [] };
|
let groupsData = { asMaster: [], asMember: [] };
|
||||||
try {
|
try {
|
||||||
groupsData = await App.api(`/api/groups/by-ticket/${id}`);
|
groupsData = await App.api(`/api/groups/by-ticket/${id}`);
|
||||||
@@ -153,13 +153,14 @@ const TicketDetailView = {
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="ticket-header">
|
<div class="ticket-header">
|
||||||
<div class="ticket-header-info">
|
<div class="ticket-header-info">
|
||||||
<div class="ticket-number">#${ticket.tn}</div>
|
<div class="ticket-number" style="display:inline-flex; align-items:center; gap:6px;">
|
||||||
<h2 class="ticket-detail-title">
|
<span class="copy-ticket-btn" data-tn="${ticket.tn}" style="cursor: pointer; font-size: 0.85rem;" title="Copia numero ticket">📋</span>
|
||||||
${data.otrsWebUrl ? `
|
#${ticket.tn}
|
||||||
<a href="${data.otrsWebUrl}" target="_blank" style="color:inherit; text-decoration:none; border-bottom:1px dashed transparent; transition:border-bottom 0.1s ease;" onmouseover="this.style.borderBottom='1px dashed var(--text-primary)'" onmouseout="this.style.borderBottom='transparent'" title="Apri in OTRS">
|
-
|
||||||
${App.escapeHtml(ticket.title || '(senza titolo)')}
|
</div>
|
||||||
</a>
|
<h2 class="ticket-detail-title" style="display:inline-flex; align-items:center; gap:6px; flex-wrap:wrap;">
|
||||||
` : App.escapeHtml(ticket.title || '(senza titolo)')}
|
<span class="copy-ticket-btn" data-tn="${App.escapeHtml(ticket.title || '')}" style="cursor: pointer; font-size: 0.85rem;" title="Copia titolo ticket">📋</span>
|
||||||
|
${App.escapeHtml(ticket.title || '(senza titolo)')}
|
||||||
</h2>
|
</h2>
|
||||||
<div class="ticket-meta-badges">
|
<div class="ticket-meta-badges">
|
||||||
<span class="badge badge-state" data-state-type="${(ticket.state_type || '').toLowerCase()}">${ticket.state_name}</span>
|
<span class="badge badge-state" data-state-type="${(ticket.state_type || '').toLowerCase()}">${ticket.state_name}</span>
|
||||||
@@ -287,7 +288,7 @@ const TicketDetailView = {
|
|||||||
<div class="articles-timeline">
|
<div class="articles-timeline">
|
||||||
${articles.length > 0 ? articles.map(a => {
|
${articles.length > 0 ? articles.map(a => {
|
||||||
const hasHtml = (a.a_content_type || '').toLowerCase().includes('html') || a.a_body.includes('</') || a.a_body.includes('/>');
|
const hasHtml = (a.a_content_type || '').toLowerCase().includes('html') || a.a_body.includes('</') || a.a_body.includes('/>');
|
||||||
|
|
||||||
let processedBody = a.a_body || '';
|
let processedBody = a.a_body || '';
|
||||||
const articleAttachments = (attachments || []).filter(att => att.article_id === a.article_id);
|
const articleAttachments = (attachments || []).filter(att => att.article_id === a.article_id);
|
||||||
|
|
||||||
@@ -521,7 +522,7 @@ const TicketDetailView = {
|
|||||||
modules: {
|
modules: {
|
||||||
toolbar: [
|
toolbar: [
|
||||||
['bold', 'italic', 'underline', 'strike'],
|
['bold', 'italic', 'underline', 'strike'],
|
||||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
|
||||||
['link', 'image'],
|
['link', 'image'],
|
||||||
['clean']
|
['clean']
|
||||||
],
|
],
|
||||||
@@ -529,7 +530,7 @@ const TicketDetailView = {
|
|||||||
bindings: {
|
bindings: {
|
||||||
tab: {
|
tab: {
|
||||||
key: 'Tab',
|
key: 'Tab',
|
||||||
handler: function() {
|
handler: function () {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,7 +940,7 @@ const TicketDetailView = {
|
|||||||
|
|
||||||
if (window.EmailCompose) {
|
if (window.EmailCompose) {
|
||||||
const hasHtml = (article.a_content_type || '').toLowerCase().includes('html') || article.a_body.includes('</') || article.a_body.includes('/>');
|
const hasHtml = (article.a_content_type || '').toLowerCase().includes('html') || article.a_body.includes('</') || article.a_body.includes('/>');
|
||||||
|
|
||||||
let processedQuoted = article.a_body || '';
|
let processedQuoted = article.a_body || '';
|
||||||
if (hasHtml) {
|
if (hasHtml) {
|
||||||
const articleAttachments = (attachments || []).filter(att => att.article_id === article.article_id);
|
const articleAttachments = (attachments || []).filter(att => att.article_id === article.article_id);
|
||||||
@@ -961,7 +962,7 @@ const TicketDetailView = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const quotedBody = hasHtml ? processedQuoted : App.escapeHtml(article.a_body || '').replace(/\n/g, '<br>');
|
const quotedBody = hasHtml ? processedQuoted : App.escapeHtml(article.a_body || '').replace(/\n/g, '<br>');
|
||||||
|
|
||||||
const initialBodyHtml = `
|
const initialBodyHtml = `
|
||||||
<p><br></p>
|
<p><br></p>
|
||||||
<p>Il ${App.formatDateTime(article.create_time)}, <strong>${App.escapeHtml(article.a_from || 'Sistema')}</strong> ha scritto:</p>
|
<p>Il ${App.formatDateTime(article.create_time)}, <strong>${App.escapeHtml(article.a_from || 'Sistema')}</strong> ha scritto:</p>
|
||||||
@@ -1292,7 +1293,7 @@ const TicketDetailView = {
|
|||||||
if (doc && doc.readyState === 'complete') {
|
if (doc && doc.readyState === 'complete') {
|
||||||
attachImageClick();
|
attachImageClick();
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.attachment-badge[data-is-image="true"]').forEach(badge => {
|
document.querySelectorAll('.attachment-badge[data-is-image="true"]').forEach(badge => {
|
||||||
@@ -1302,5 +1303,19 @@ const TicketDetailView = {
|
|||||||
this.openImageLightbox(badge.href);
|
this.openImageLightbox(badge.href);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.copy-ticket-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const tn = btn.dataset.tn;
|
||||||
|
if (tn) {
|
||||||
|
navigator.clipboard.writeText(tn).then(() => {
|
||||||
|
Toast.success('Copiato negli appunti!');
|
||||||
|
}).catch(err => {
|
||||||
|
Toast.error('Errore durante la copia: ' + err.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,18 +39,18 @@ const TicketListView = {
|
|||||||
Filters.state.user_id = activeAgentId;
|
Filters.state.user_id = activeAgentId;
|
||||||
Filters.save();
|
Filters.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
const params = Filters.toQueryParams();
|
const params = Filters.toQueryParams();
|
||||||
params.set('page', this.currentPage);
|
params.set('page', this.currentPage);
|
||||||
params.set('per_page', this.perPage);
|
params.set('per_page', this.perPage);
|
||||||
params.set('sort_by', this.sortBy);
|
params.set('sort_by', this.sortBy);
|
||||||
params.set('sort_dir', this.sortDir);
|
params.set('sort_dir', this.sortDir);
|
||||||
|
|
||||||
const searchInput = document.getElementById('global-search');
|
const searchInput = document.getElementById('global-search');
|
||||||
if (searchInput && searchInput.value.trim()) {
|
if (searchInput && searchInput.value.trim()) {
|
||||||
params.set('search', searchInput.value.trim());
|
params.set('search', searchInput.value.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await App.api(`/api/tickets?${params.toString()}`);
|
const data = await App.api(`/api/tickets?${params.toString()}`);
|
||||||
|
|
||||||
this.renderContent(container, data);
|
this.renderContent(container, data);
|
||||||
@@ -135,9 +135,9 @@ const TicketListView = {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
${tickets.length > 0 ? tickets.map(t => {
|
${tickets.length > 0 ? tickets.map(t => {
|
||||||
const displayQueue = t.queue_name.includes('::') ? t.queue_name.split('::').pop() : t.queue_name;
|
const displayQueue = t.queue_name.includes('::') ? t.queue_name.split('::').pop() : t.queue_name;
|
||||||
const shortQueue = displayQueue.length > 15 ? displayQueue.substring(0, 12) + '...' : displayQueue;
|
const shortQueue = displayQueue.length > 15 ? displayQueue.substring(0, 12) + '...' : displayQueue;
|
||||||
return `
|
return `
|
||||||
<tr data-ticket-id="${t.id}" class="${this.selectedIds.has(String(t.id)) ? 'selected' : ''} ${this.selectedOrder[0] === String(t.id) ? 'first-selected' : ''}" style="cursor:pointer;">
|
<tr data-ticket-id="${t.id}" class="${this.selectedIds.has(String(t.id)) ? 'selected' : ''} ${this.selectedOrder[0] === String(t.id) ? 'first-selected' : ''}" style="cursor:pointer;">
|
||||||
<td>
|
<td>
|
||||||
<span class="ticket-tn" style="display:inline-flex; align-items:center;">
|
<span class="ticket-tn" style="display:inline-flex; align-items:center;">
|
||||||
@@ -153,14 +153,14 @@ const TicketListView = {
|
|||||||
</td>
|
</td>
|
||||||
<td style="color:var(--text-tertiary);font-size:0.78rem;">${App.formatDateTime(t.create_time)}</td>
|
<td style="color:var(--text-tertiary);font-size:0.78rem;">${App.formatDateTime(t.create_time)}</td>
|
||||||
<td><span class="badge badge-state" data-state-type="${(t.state_type || '').toLowerCase()}">${t.state_name}</span></td>
|
<td><span class="badge badge-state" data-state-type="${(t.state_type || '').toLowerCase()}">${t.state_name}</span></td>
|
||||||
<td class="ticket-title-cell"><a href="#/tickets/${t.id}" class="ticket-title-link" onclick="event.stopPropagation()">${App.escapeHtml(t.title || '(senza titolo)')}</a></td>
|
<td class="ticket-title-cell"><span class="copy-ticket-btn" data-tn="${t.title}" style="cursor: pointer; font-size: 0.82rem; display: inline-flex; align-items: center; margin-right: 4px;" onclick="event.stopPropagation();" title="Copia titolo ticket">📋</span><a href="#/tickets/${t.id}" class="ticket-title-link" onclick="event.stopPropagation()">${App.escapeHtml(t.title || '(senza titolo)')}</a></td>
|
||||||
<td class="queue-cell"><span class="badge badge-queue">${App.escapeHtml(shortQueue)}</span><div class="queue-tooltip">${App.escapeHtml(t.queue_name)}</div></td>
|
<td class="queue-cell"><span class="badge badge-queue">${App.escapeHtml(shortQueue)}</span><div class="queue-tooltip">${App.escapeHtml(t.queue_name)}</div></td>
|
||||||
<td style="color:var(--text-secondary);font-size:0.82rem;">${t.owner_first || ''} ${t.owner_last || ''}</td>
|
<td style="color:var(--text-secondary);font-size:0.82rem;">${t.owner_first || ''} ${t.owner_last || ''}</td>
|
||||||
<td style="color:var(--text-secondary);font-size:0.82rem;">${t.customer_first ? `${t.customer_first} ${t.customer_last}` : (t.customer_user_id || '—')}</td>
|
<td style="color:var(--text-secondary);font-size:0.82rem;">${t.customer_first ? `${t.customer_first} ${t.customer_last}` : (t.customer_user_id || '—')}</td>
|
||||||
<td><span class="badge badge-priority" data-priority="${App.priorityIndex(t.priority_name)}">${App.priorityIndex(t.priority_name)}</span></td>
|
<td><span class="badge badge-priority" data-priority="${App.priorityIndex(t.priority_name)}">${App.priorityIndex(t.priority_name)}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}).join('') : `
|
}).join('') : `
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="8">
|
<td colspan="8">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
@@ -265,7 +265,7 @@ const TicketListView = {
|
|||||||
if (e.target.closest('.ticket-tn-link') || e.target.closest('.ticket-title-link')) {
|
if (e.target.closest('.ticket-tn-link') || e.target.closest('.ticket-title-link')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = String(row.dataset.ticketId);
|
const id = String(row.dataset.ticketId);
|
||||||
if (this.selectedIds.has(id)) {
|
if (this.selectedIds.has(id)) {
|
||||||
this.selectedIds.delete(id);
|
this.selectedIds.delete(id);
|
||||||
@@ -289,7 +289,7 @@ const TicketListView = {
|
|||||||
tr.classList.remove('first-selected');
|
tr.classList.remove('first-selected');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.updateBatchBar();
|
this.updateBatchBar();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -312,7 +312,7 @@ const TicketListView = {
|
|||||||
batchOpenTabsBtn.addEventListener('click', (e) => {
|
batchOpenTabsBtn.addEventListener('click', (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (this.selectedIds.size === 0) return;
|
if (this.selectedIds.size === 0) return;
|
||||||
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
this.selectedIds.forEach(id => {
|
this.selectedIds.forEach(id => {
|
||||||
const row = document.querySelector(`.ticket-table tbody tr[data-ticket-id="${id}"]`);
|
const row = document.querySelector(`.ticket-table tbody tr[data-ticket-id="${id}"]`);
|
||||||
@@ -325,7 +325,7 @@ const TicketListView = {
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
Toast.success(`${count} ticket aperti in nuove schede!`);
|
Toast.success(`${count} ticket aperti in nuove schede!`);
|
||||||
this.selectedIds.clear();
|
this.selectedIds.clear();
|
||||||
|
|||||||
Reference in New Issue
Block a user