Add comprehensive call control features and web phone transfer capabilities
## New Call Control Features - Call hold/unhold with music playback - Call transfer with agent selection dialog - Call requeue to different queues - Call recording with start/stop controls - Real-time recording status tracking ## Enhanced Transfer System - Transfer to agents with cell phones (direct) - Transfer to web phone agents via personal queues - Automatic queue creation for each user - Real-time agent availability status - Visual agent selection with status indicators (📱 phone, 💻 web) ## Call Recordings Management - New database table for call recordings - Recordings tab in voicemail interface - Play/download recordings functionality - Admin-only delete capability - Integration with Twilio recording webhooks ## Agent Queue System - Personal queues (agent_[user_id]) for web phone transfers - Automatic polling for incoming transfers - Transfer notifications with browser alerts - Agent status tracking (available/busy/offline) ## Technical Enhancements - 8 new AJAX endpoints for call controls - Recording status webhooks - Enhanced transfer dialogs with agent selection - Improved error handling and user feedback - Mobile-responsive call control interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,11 @@
|
||||
let notificationPermission = 'default';
|
||||
let backgroundAlertInterval = null;
|
||||
let isPageVisible = true;
|
||||
let isOnHold = false;
|
||||
let isRecording = false;
|
||||
let recordingSid = null;
|
||||
let personalQueueTimer = null;
|
||||
let personalQueueName = null;
|
||||
|
||||
// Initialize when document is ready
|
||||
$(document).ready(function() {
|
||||
@@ -38,6 +43,7 @@
|
||||
initVoicemailSection();
|
||||
initializeNotifications();
|
||||
initializePageVisibility();
|
||||
initializePersonalQueue();
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -271,6 +277,47 @@
|
||||
hangupCall();
|
||||
});
|
||||
|
||||
// Call control buttons
|
||||
$('#twp-hold-btn').on('click', function() {
|
||||
toggleHold();
|
||||
});
|
||||
|
||||
$('#twp-transfer-btn').on('click', function() {
|
||||
showTransferDialog();
|
||||
});
|
||||
|
||||
$('#twp-requeue-btn').on('click', function() {
|
||||
showRequeueDialog();
|
||||
});
|
||||
|
||||
$('#twp-record-btn').on('click', function() {
|
||||
toggleRecording();
|
||||
});
|
||||
|
||||
// Transfer dialog handlers
|
||||
$(document).on('click', '#twp-confirm-transfer', function() {
|
||||
const agentNumber = $('#twp-transfer-agent-number').val();
|
||||
if (agentNumber) {
|
||||
transferCall(agentNumber);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '#twp-cancel-transfer', function() {
|
||||
hideTransferDialog();
|
||||
});
|
||||
|
||||
// Requeue dialog handlers
|
||||
$(document).on('click', '#twp-confirm-requeue', function() {
|
||||
const queueId = $('#twp-requeue-select').val();
|
||||
if (queueId) {
|
||||
requeueCall(queueId);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', '#twp-cancel-requeue', function() {
|
||||
hideRequeueDialog();
|
||||
});
|
||||
|
||||
// Accept queue call button
|
||||
$('#twp-accept-queue-call').on('click', function() {
|
||||
acceptQueueCall();
|
||||
@@ -465,12 +512,24 @@
|
||||
* End call and cleanup
|
||||
*/
|
||||
function endCall() {
|
||||
// Stop recording if active
|
||||
if (isRecording) {
|
||||
stopRecording();
|
||||
}
|
||||
|
||||
currentCall = null;
|
||||
isOnHold = false;
|
||||
isRecording = false;
|
||||
recordingSid = null;
|
||||
stopCallTimer();
|
||||
updateCallState('idle');
|
||||
hideCallInfo();
|
||||
$('.twp-browser-phone-container').removeClass('incoming-call');
|
||||
|
||||
// Reset control buttons
|
||||
$('#twp-hold-btn').text('Hold').removeClass('btn-active');
|
||||
$('#twp-record-btn').text('Record').removeClass('btn-active');
|
||||
|
||||
// Restart alerts if enabled and there are waiting calls
|
||||
if (alertEnabled) {
|
||||
const hasWaitingCalls = userQueues.some(q => parseInt(q.current_waiting) > 0);
|
||||
@@ -671,20 +730,24 @@
|
||||
function updateCallState(state) {
|
||||
const $callBtn = $('#twp-call-btn');
|
||||
const $hangupBtn = $('#twp-hangup-btn');
|
||||
const $controlsPanel = $('#twp-call-controls-panel');
|
||||
|
||||
switch (state) {
|
||||
case 'idle':
|
||||
$callBtn.show().prop('disabled', false);
|
||||
$hangupBtn.hide();
|
||||
$controlsPanel.hide();
|
||||
break;
|
||||
case 'connecting':
|
||||
case 'ringing':
|
||||
$callBtn.hide();
|
||||
$hangupBtn.show();
|
||||
$controlsPanel.hide();
|
||||
break;
|
||||
case 'connected':
|
||||
$callBtn.hide();
|
||||
$hangupBtn.show();
|
||||
$controlsPanel.show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1002,6 +1065,9 @@
|
||||
if (backgroundAlertInterval) {
|
||||
clearInterval(backgroundAlertInterval);
|
||||
}
|
||||
if (personalQueueTimer) {
|
||||
clearInterval(personalQueueTimer);
|
||||
}
|
||||
if (twilioDevice) {
|
||||
twilioDevice.destroy();
|
||||
}
|
||||
@@ -1376,4 +1442,526 @@
|
||||
// Load alert preference on init
|
||||
loadAlertPreference();
|
||||
|
||||
/**
|
||||
* Initialize personal queue for incoming transfers
|
||||
*/
|
||||
function initializePersonalQueue() {
|
||||
if (!twp_frontend_ajax.user_id) return;
|
||||
|
||||
// Set personal queue name
|
||||
personalQueueName = 'agent_' + twp_frontend_ajax.user_id;
|
||||
|
||||
// Start polling for incoming transfers
|
||||
checkPersonalQueue();
|
||||
personalQueueTimer = setInterval(checkPersonalQueue, 3000); // Check every 3 seconds
|
||||
}
|
||||
|
||||
/**
|
||||
* Check personal queue for incoming transfers
|
||||
*/
|
||||
function checkPersonalQueue() {
|
||||
// Don't check if already in a call
|
||||
if (currentCall) return;
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_check_personal_queue',
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.has_waiting_call) {
|
||||
handleIncomingTransfer(response.data);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// Silently fail - don't interrupt user
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming transfer notification
|
||||
*/
|
||||
function handleIncomingTransfer(data) {
|
||||
// Show notification
|
||||
showMessage('Incoming transfer! The call will be connected automatically.', 'info');
|
||||
|
||||
// Show browser notification
|
||||
if (notificationPermission === 'granted') {
|
||||
showBrowserNotification('📞 Incoming Transfer!', {
|
||||
body: 'A call is being transferred to you',
|
||||
icon: '📞',
|
||||
vibrate: [300, 200, 300],
|
||||
requireInteraction: true,
|
||||
tag: 'transfer-notification'
|
||||
});
|
||||
}
|
||||
|
||||
// Play alert sound if enabled
|
||||
if (alertEnabled) {
|
||||
playAlertSound();
|
||||
}
|
||||
|
||||
// Auto-accept the transfer after a short delay
|
||||
setTimeout(function() {
|
||||
acceptTransferCall(data);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept incoming transfer call
|
||||
*/
|
||||
function acceptTransferCall(data) {
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_accept_transfer_call',
|
||||
call_sid: data.call_sid,
|
||||
queue_id: data.queue_id,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showMessage('Transfer accepted, connecting...', 'success');
|
||||
} else {
|
||||
showMessage('Failed to accept transfer: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to accept transfer', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle call hold
|
||||
*/
|
||||
function toggleHold() {
|
||||
if (!currentCall || currentCall.status() !== 'open') {
|
||||
showMessage('No active call to hold', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const $holdBtn = $('#twp-hold-btn');
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_toggle_hold',
|
||||
call_sid: currentCall.parameters.CallSid,
|
||||
hold: !isOnHold,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
isOnHold = !isOnHold;
|
||||
if (isOnHold) {
|
||||
$holdBtn.text('Unhold').addClass('btn-active');
|
||||
showMessage('Call placed on hold', 'info');
|
||||
} else {
|
||||
$holdBtn.text('Hold').removeClass('btn-active');
|
||||
showMessage('Call resumed', 'info');
|
||||
}
|
||||
} else {
|
||||
showMessage('Failed to toggle hold: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to toggle hold', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer call to another agent
|
||||
*/
|
||||
function transferCall(agentNumber) {
|
||||
if (!currentCall || currentCall.status() !== 'open') {
|
||||
showMessage('No active call to transfer', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_transfer_call',
|
||||
call_sid: currentCall.parameters.CallSid,
|
||||
agent_number: agentNumber,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showMessage('Call transferred successfully', 'success');
|
||||
hideTransferDialog();
|
||||
// End the call on our end
|
||||
if (currentCall) {
|
||||
currentCall.disconnect();
|
||||
}
|
||||
} else {
|
||||
showMessage('Failed to transfer call: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to transfer call', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requeue call to a different queue
|
||||
*/
|
||||
function requeueCall(queueId) {
|
||||
if (!currentCall || currentCall.status() !== 'open') {
|
||||
showMessage('No active call to requeue', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_requeue_call',
|
||||
call_sid: currentCall.parameters.CallSid,
|
||||
queue_id: queueId,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showMessage('Call requeued successfully', 'success');
|
||||
hideRequeueDialog();
|
||||
// End the call on our end
|
||||
if (currentCall) {
|
||||
currentCall.disconnect();
|
||||
}
|
||||
} else {
|
||||
showMessage('Failed to requeue call: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to requeue call', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle call recording
|
||||
*/
|
||||
function toggleRecording() {
|
||||
if (!currentCall || currentCall.status() !== 'open') {
|
||||
showMessage('No active call to record', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRecording) {
|
||||
stopRecording();
|
||||
} else {
|
||||
startRecording();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start recording the current call
|
||||
*/
|
||||
function startRecording() {
|
||||
const $recordBtn = $('#twp-record-btn');
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_start_recording',
|
||||
call_sid: currentCall.parameters.CallSid,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
isRecording = true;
|
||||
recordingSid = response.data.recording_sid;
|
||||
$recordBtn.text('Stop Recording').addClass('btn-active btn-recording');
|
||||
showMessage('Recording started', 'success');
|
||||
} else {
|
||||
showMessage('Failed to start recording: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to start recording', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop recording the current call
|
||||
*/
|
||||
function stopRecording() {
|
||||
if (!recordingSid) return;
|
||||
|
||||
const $recordBtn = $('#twp-record-btn');
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_stop_recording',
|
||||
call_sid: currentCall ? currentCall.parameters.CallSid : '',
|
||||
recording_sid: recordingSid,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
isRecording = false;
|
||||
recordingSid = null;
|
||||
$recordBtn.text('Record').removeClass('btn-active btn-recording');
|
||||
showMessage('Recording stopped', 'info');
|
||||
} else {
|
||||
showMessage('Failed to stop recording: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to stop recording', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show transfer dialog
|
||||
*/
|
||||
function showTransferDialog() {
|
||||
// First load available agents
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_get_online_agents',
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.length > 0) {
|
||||
showAgentTransferDialog(response.data);
|
||||
} else {
|
||||
// Fallback to manual phone number entry
|
||||
showManualTransferDialog();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// Fallback to manual phone number entry
|
||||
showManualTransferDialog();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show agent selection transfer dialog
|
||||
*/
|
||||
function showAgentTransferDialog(agents) {
|
||||
let agentOptions = '<div class="agent-list">';
|
||||
|
||||
agents.forEach(function(agent) {
|
||||
const statusClass = agent.is_available ? 'available' : (agent.status === 'busy' ? 'busy' : 'offline');
|
||||
const statusText = agent.is_available ? '🟢 Available' : (agent.status === 'busy' ? '🔴 Busy' : '⚫ Offline');
|
||||
const methodIcon = agent.has_phone ? '📱' : '💻';
|
||||
|
||||
agentOptions += `
|
||||
<div class="agent-option ${statusClass}" data-agent-id="${agent.id}"
|
||||
data-transfer-method="${agent.transfer_method}"
|
||||
data-transfer-value="${agent.transfer_value}">
|
||||
<div class="agent-info">
|
||||
<span class="agent-name">${agent.name}</span>
|
||||
<span class="agent-method">${methodIcon}</span>
|
||||
</div>
|
||||
<div class="agent-status">${statusText}</div>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
agentOptions += '</div>';
|
||||
|
||||
const dialog = `
|
||||
<div id="twp-transfer-dialog" class="twp-dialog-overlay">
|
||||
<div class="twp-dialog twp-agent-transfer-dialog">
|
||||
<h3>Transfer Call to Agent</h3>
|
||||
<p>Select an agent to transfer this call to:</p>
|
||||
${agentOptions}
|
||||
<div class="manual-option">
|
||||
<p>Or enter a phone number manually:</p>
|
||||
<input type="tel" id="twp-transfer-manual-number" placeholder="+1234567890" />
|
||||
</div>
|
||||
<div class="dialog-buttons">
|
||||
<button id="twp-confirm-agent-transfer" class="twp-btn twp-btn-primary" disabled>Transfer</button>
|
||||
<button id="twp-cancel-transfer" class="twp-btn twp-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
$('body').append(dialog);
|
||||
|
||||
// Handle agent selection
|
||||
let selectedAgent = null;
|
||||
$('.agent-option').on('click', function() {
|
||||
if ($(this).hasClass('offline')) {
|
||||
showMessage('Cannot transfer to offline agents', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
$('.agent-option').removeClass('selected');
|
||||
$(this).addClass('selected');
|
||||
|
||||
selectedAgent = {
|
||||
id: $(this).data('agent-id'),
|
||||
method: $(this).data('transfer-method'),
|
||||
value: $(this).data('transfer-value')
|
||||
};
|
||||
|
||||
$('#twp-transfer-manual-number').val('');
|
||||
$('#twp-confirm-agent-transfer').prop('disabled', false);
|
||||
});
|
||||
|
||||
// Handle manual number entry
|
||||
$('#twp-transfer-manual-number').on('input', function() {
|
||||
const number = $(this).val().trim();
|
||||
if (number) {
|
||||
$('.agent-option').removeClass('selected');
|
||||
selectedAgent = null;
|
||||
$('#twp-confirm-agent-transfer').prop('disabled', false);
|
||||
} else {
|
||||
$('#twp-confirm-agent-transfer').prop('disabled', !selectedAgent);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle transfer confirmation
|
||||
$('#twp-confirm-agent-transfer').on('click', function() {
|
||||
const manualNumber = $('#twp-transfer-manual-number').val().trim();
|
||||
|
||||
if (manualNumber) {
|
||||
// Manual phone transfer
|
||||
transferCall(manualNumber);
|
||||
} else if (selectedAgent) {
|
||||
// Agent transfer (phone or queue)
|
||||
transferToAgent(selectedAgent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show manual transfer dialog (fallback)
|
||||
*/
|
||||
function showManualTransferDialog() {
|
||||
const dialog = `
|
||||
<div id="twp-transfer-dialog" class="twp-dialog-overlay">
|
||||
<div class="twp-dialog">
|
||||
<h3>Transfer Call</h3>
|
||||
<p>Enter the phone number to transfer this call:</p>
|
||||
<input type="tel" id="twp-transfer-agent-number" placeholder="+1234567890" />
|
||||
<div class="dialog-buttons">
|
||||
<button id="twp-confirm-transfer" class="twp-btn twp-btn-primary">Transfer</button>
|
||||
<button id="twp-cancel-transfer" class="twp-btn twp-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
$('body').append(dialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer call to selected agent
|
||||
*/
|
||||
function transferToAgent(agent) {
|
||||
if (!currentCall || currentCall.status() !== 'open') {
|
||||
showMessage('No active call to transfer', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_transfer_to_agent_queue',
|
||||
call_sid: currentCall.parameters.CallSid,
|
||||
agent_id: agent.id,
|
||||
transfer_method: agent.method,
|
||||
transfer_value: agent.value,
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showMessage('Call transferred successfully', 'success');
|
||||
hideTransferDialog();
|
||||
// End the call on our end
|
||||
if (currentCall) {
|
||||
currentCall.disconnect();
|
||||
}
|
||||
} else {
|
||||
showMessage('Failed to transfer call: ' + (response.data || 'Unknown error'), 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to transfer call', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide transfer dialog
|
||||
*/
|
||||
function hideTransferDialog() {
|
||||
$('#twp-transfer-dialog').remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show requeue dialog
|
||||
*/
|
||||
function showRequeueDialog() {
|
||||
// Load available queues first
|
||||
$.ajax({
|
||||
url: twp_frontend_ajax.ajax_url,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'twp_get_all_queues',
|
||||
nonce: twp_frontend_ajax.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.length > 0) {
|
||||
let options = '';
|
||||
response.data.forEach(function(queue) {
|
||||
options += `<option value="${queue.id}">${queue.queue_name}</option>`;
|
||||
});
|
||||
|
||||
const dialog = `
|
||||
<div id="twp-requeue-dialog" class="twp-dialog-overlay">
|
||||
<div class="twp-dialog">
|
||||
<h3>Requeue Call</h3>
|
||||
<p>Select a queue to transfer this call to:</p>
|
||||
<select id="twp-requeue-select">
|
||||
${options}
|
||||
</select>
|
||||
<div class="dialog-buttons">
|
||||
<button id="twp-confirm-requeue" class="twp-btn twp-btn-primary">Requeue</button>
|
||||
<button id="twp-cancel-requeue" class="twp-btn twp-btn-secondary">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
$('body').append(dialog);
|
||||
} else {
|
||||
showMessage('No queues available', 'error');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
showMessage('Failed to load queues', 'error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide requeue dialog
|
||||
*/
|
||||
function hideRequeueDialog() {
|
||||
$('#twp-requeue-dialog').remove();
|
||||
}
|
||||
|
||||
})(jQuery);
|
Reference in New Issue
Block a user