Skip to content

Commit 0a8c84b

Browse files
Create dashboard.js
1 parent e10bb46 commit 0a8c84b

File tree

1 file changed

+329
-0
lines changed

1 file changed

+329
-0
lines changed

static/dashboard.js

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
// Dashboard functionality for DirectAdmin Email Forwarder
2+
let currentForwarders = [];
3+
let emailAccounts = [];
4+
5+
// Load email accounts for destination dropdown
6+
async function loadEmailAccounts() {
7+
try {
8+
const response = await fetch('/api/email-accounts');
9+
const data = await response.json();
10+
11+
if (response.ok && data.accounts) {
12+
emailAccounts = data.accounts;
13+
updateDestinationDropdown();
14+
} else {
15+
console.error('Failed to load email accounts:', data.error);
16+
showMessage('Failed to load email accounts', 'error');
17+
}
18+
} catch (error) {
19+
console.error('Error loading email accounts:', error);
20+
}
21+
}
22+
23+
// Update destination dropdown with email accounts
24+
function updateDestinationDropdown() {
25+
const select = document.getElementById('destination');
26+
if (!select) return;
27+
28+
// Clear existing options
29+
select.innerHTML = '';
30+
31+
// Add placeholder
32+
const placeholder = document.createElement('option');
33+
placeholder.value = '';
34+
placeholder.textContent = 'Select destination...';
35+
placeholder.disabled = true;
36+
placeholder.selected = true;
37+
select.appendChild(placeholder);
38+
39+
// Add email account options
40+
if (emailAccounts.length > 0) {
41+
emailAccounts.forEach(email => {
42+
const option = document.createElement('option');
43+
option.value = email;
44+
option.textContent = email;
45+
select.appendChild(option);
46+
});
47+
}
48+
49+
// Add separator
50+
const separator = document.createElement('option');
51+
separator.disabled = true;
52+
separator.textContent = '──────────────';
53+
select.appendChild(separator);
54+
55+
// Add custom email option
56+
const customOption = document.createElement('option');
57+
customOption.value = 'custom';
58+
customOption.textContent = 'Enter custom email address...';
59+
select.appendChild(customOption);
60+
61+
// Handle selection changes
62+
select.addEventListener('change', function() {
63+
const customInput = document.getElementById('customDestination');
64+
if (this.value === 'custom') {
65+
customInput.style.display = 'block';
66+
customInput.required = true;
67+
customInput.focus();
68+
} else {
69+
customInput.style.display = 'none';
70+
customInput.required = false;
71+
customInput.value = '';
72+
}
73+
});
74+
}
75+
76+
// Load forwarders from API
77+
async function loadForwarders() {
78+
const tbody = document.querySelector('#forwardersTable tbody');
79+
if (!tbody) return;
80+
81+
try {
82+
const response = await fetch('/api/forwarders');
83+
84+
if (!response.ok) {
85+
throw new Error(`HTTP error! status: ${response.status}`);
86+
}
87+
88+
const data = await response.json();
89+
console.log('Forwarders response:', data);
90+
91+
// Extract forwarders array from response
92+
if (data && Array.isArray(data.forwarders)) {
93+
currentForwarders = data.forwarders;
94+
} else {
95+
console.warn('Unexpected forwarders format:', data);
96+
currentForwarders = [];
97+
}
98+
99+
displayForwarders();
100+
101+
} catch (error) {
102+
console.error('Error loading forwarders:', error);
103+
tbody.innerHTML = '<tr><td colspan="3" class="error-message">Failed to load forwarders. Please check your DirectAdmin settings.</td></tr>';
104+
}
105+
}
106+
107+
// Display forwarders in the table
108+
function displayForwarders() {
109+
const tbody = document.querySelector('#forwardersTable tbody');
110+
if (!tbody) return;
111+
112+
tbody.innerHTML = '';
113+
114+
if (currentForwarders.length === 0) {
115+
tbody.innerHTML = '<tr><td colspan="3" class="no-data">No email forwarders configured</td></tr>';
116+
return;
117+
}
118+
119+
currentForwarders.forEach(forwarder => {
120+
const row = document.createElement('tr');
121+
122+
// Create cells
123+
const fromCell = document.createElement('td');
124+
fromCell.textContent = forwarder.address || 'Unknown';
125+
126+
const toCell = document.createElement('td');
127+
toCell.textContent = forwarder.destination || 'Unknown';
128+
129+
const actionsCell = document.createElement('td');
130+
const deleteBtn = document.createElement('button');
131+
deleteBtn.className = 'btn-danger btn-sm';
132+
deleteBtn.textContent = 'Delete';
133+
deleteBtn.onclick = () => deleteForwarder(forwarder.address);
134+
actionsCell.appendChild(deleteBtn);
135+
136+
row.appendChild(fromCell);
137+
row.appendChild(toCell);
138+
row.appendChild(actionsCell);
139+
tbody.appendChild(row);
140+
});
141+
}
142+
143+
// Create new forwarder
144+
async function createForwarder(event) {
145+
event.preventDefault();
146+
147+
const form = event.target;
148+
const addressInput = form.querySelector('#address');
149+
const destinationSelect = form.querySelector('#destination');
150+
const customDestInput = form.querySelector('#customDestination');
151+
const submitButton = form.querySelector('button[type="submit"]');
152+
153+
// Get the actual destination
154+
let destination = destinationSelect.value;
155+
if (destination === 'custom') {
156+
destination = customDestInput.value.trim();
157+
if (!destination) {
158+
showMessage('Please enter a custom email address', 'error');
159+
customDestInput.focus();
160+
return;
161+
}
162+
}
163+
164+
// Validate
165+
if (!addressInput.value.trim() || !destination) {
166+
showMessage('Please fill in all required fields', 'error');
167+
return;
168+
}
169+
170+
// Disable form during submission
171+
submitButton.disabled = true;
172+
submitButton.textContent = 'Creating...';
173+
174+
try {
175+
const response = await fetch('/api/forwarders', {
176+
method: 'POST',
177+
headers: {
178+
'Content-Type': 'application/json',
179+
},
180+
body: JSON.stringify({
181+
address: addressInput.value.trim(),
182+
destination: destination
183+
})
184+
});
185+
186+
const data = await response.json();
187+
188+
if (response.ok) {
189+
// Clear form
190+
form.reset();
191+
customDestInput.style.display = 'none';
192+
193+
// Reload forwarders
194+
await loadForwarders();
195+
196+
// Show success message
197+
showMessage(data.message || 'Forwarder created successfully', 'success');
198+
} else {
199+
showMessage(data.error || 'Failed to create forwarder', 'error');
200+
}
201+
} catch (error) {
202+
console.error('Error creating forwarder:', error);
203+
showMessage('Failed to create forwarder. Please try again.', 'error');
204+
} finally {
205+
// Re-enable form
206+
submitButton.disabled = false;
207+
submitButton.textContent = 'Create Forwarder';
208+
}
209+
}
210+
211+
// Delete forwarder
212+
async function deleteForwarder(address) {
213+
if (!address) {
214+
console.error('No address provided for deletion');
215+
return;
216+
}
217+
218+
if (!confirm(`Are you sure you want to delete the forwarder for ${address}?`)) {
219+
return;
220+
}
221+
222+
try {
223+
const response = await fetch('/api/forwarders', {
224+
method: 'DELETE',
225+
headers: {
226+
'Content-Type': 'application/json',
227+
},
228+
body: JSON.stringify({
229+
address: address
230+
})
231+
});
232+
233+
const data = await response.json();
234+
235+
if (response.ok) {
236+
await loadForwarders();
237+
showMessage(data.message || 'Forwarder deleted successfully', 'success');
238+
} else {
239+
showMessage(data.error || 'Failed to delete forwarder', 'error');
240+
}
241+
} catch (error) {
242+
console.error('Error deleting forwarder:', error);
243+
showMessage('Failed to delete forwarder. Please try again.', 'error');
244+
}
245+
}
246+
247+
// Show message to user
248+
function showMessage(message, type = 'info') {
249+
const container = document.getElementById('messageContainer');
250+
if (!container) {
251+
console.error('Message container not found');
252+
return;
253+
}
254+
255+
// Create message element
256+
const div = document.createElement('div');
257+
div.className = `alert alert-${type}`;
258+
div.textContent = message;
259+
260+
// Add close button
261+
const closeBtn = document.createElement('span');
262+
closeBtn.innerHTML = '&times;';
263+
closeBtn.style.float = 'right';
264+
closeBtn.style.cursor = 'pointer';
265+
closeBtn.style.marginLeft = '15px';
266+
closeBtn.onclick = () => div.remove();
267+
div.appendChild(closeBtn);
268+
269+
// Clear existing messages and add new one
270+
container.innerHTML = '';
271+
container.appendChild(div);
272+
273+
// Auto-hide after 5 seconds
274+
setTimeout(() => {
275+
if (div.parentNode) {
276+
div.remove();
277+
}
278+
}, 5000);
279+
}
280+
281+
// Initialize when DOM is ready
282+
document.addEventListener('DOMContentLoaded', function() {
283+
console.log('Dashboard JS loaded');
284+
285+
// Check if we're on the dashboard page
286+
const forwardersTable = document.getElementById('forwardersTable');
287+
if (!forwardersTable) {
288+
console.log('Not on dashboard page, skipping initialization');
289+
return;
290+
}
291+
292+
console.log('Initializing dashboard...');
293+
294+
// Load initial data
295+
loadEmailAccounts();
296+
loadForwarders();
297+
298+
// Set up auto-refresh every 60 seconds
299+
setInterval(loadForwarders, 60000);
300+
301+
// Set up form handler
302+
const form = document.getElementById('createForwarderForm');
303+
if (form) {
304+
form.addEventListener('submit', createForwarder);
305+
} else {
306+
console.error('Create forwarder form not found');
307+
}
308+
309+
// Set up manual refresh button (if you want one)
310+
const refreshBtn = document.getElementById('refreshBtn');
311+
if (refreshBtn) {
312+
refreshBtn.addEventListener('click', () => {
313+
loadForwarders();
314+
showMessage('Forwarders refreshed', 'info');
315+
});
316+
}
317+
});
318+
319+
// Utility function to escape HTML (prevent XSS)
320+
function escapeHtml(unsafe) {
321+
if (!unsafe) return '';
322+
return unsafe
323+
.toString()
324+
.replace(/&/g, "&amp;")
325+
.replace(/</g, "&lt;")
326+
.replace(/>/g, "&gt;")
327+
.replace(/"/g, "&quot;")
328+
.replace(/'/g, "&#039;");
329+
}

0 commit comments

Comments
 (0)