296 lines
10 KiB
JavaScript
296 lines
10 KiB
JavaScript
/**
|
|
* Mail Calendar Sync - Personal Settings JavaScript
|
|
*/
|
|
(function() {
|
|
'use strict';
|
|
|
|
const BASE_URL = OC.generateUrl('/apps/mail_calendar_sync/api');
|
|
|
|
let currentConfig = {};
|
|
let mailAccounts = [];
|
|
let calendars = [];
|
|
|
|
async function init() {
|
|
try {
|
|
const [configData, accountsData, calendarsData] = await Promise.all([
|
|
fetchJson(`${BASE_URL}/config`),
|
|
fetchJson(`${BASE_URL}/mail-accounts`),
|
|
fetchJson(`${BASE_URL}/calendars`),
|
|
]);
|
|
|
|
currentConfig = configData;
|
|
mailAccounts = accountsData;
|
|
calendars = calendarsData;
|
|
|
|
renderForm();
|
|
loadLog();
|
|
} catch (error) {
|
|
console.error('Failed to load Mail Calendar Sync settings:', error);
|
|
showStatus('Failed to load settings: ' + error.message, 'error');
|
|
} finally {
|
|
document.getElementById('mcs-loading').style.display = 'none';
|
|
document.getElementById('mcs-config').style.display = '';
|
|
}
|
|
}
|
|
|
|
function renderForm() {
|
|
// Enabled checkbox
|
|
const enabledCheckbox = document.getElementById('mcs-enabled');
|
|
enabledCheckbox.checked = currentConfig.enabled || false;
|
|
enabledCheckbox.addEventListener('change', onEnabledChange);
|
|
|
|
// Mail accounts dropdown
|
|
const mailSelect = document.getElementById('mcs-mail-account');
|
|
mailSelect.innerHTML = '<option value="">Select a mail account…</option>';
|
|
mailAccounts.forEach(account => {
|
|
const option = document.createElement('option');
|
|
option.value = account.id;
|
|
option.textContent = `${account.name} (${account.email})`;
|
|
if (currentConfig.mailAccountId == account.id) {
|
|
option.selected = true;
|
|
}
|
|
mailSelect.appendChild(option);
|
|
});
|
|
|
|
if (mailAccounts.length === 0) {
|
|
const option = document.createElement('option');
|
|
option.value = '';
|
|
option.textContent = 'No mail accounts found — configure one in the Mail app first';
|
|
option.disabled = true;
|
|
mailSelect.appendChild(option);
|
|
}
|
|
|
|
// Calendars dropdown
|
|
const calSelect = document.getElementById('mcs-calendar');
|
|
calSelect.innerHTML = '<option value="">Select a calendar…</option>';
|
|
calendars.forEach(cal => {
|
|
const option = document.createElement('option');
|
|
option.value = cal.uri;
|
|
option.textContent = cal.name;
|
|
if (cal.color) {
|
|
option.style.borderLeft = `4px solid ${cal.color}`;
|
|
option.style.paddingLeft = '8px';
|
|
}
|
|
if (currentConfig.calendarUri === cal.uri) {
|
|
option.selected = true;
|
|
}
|
|
calSelect.appendChild(option);
|
|
});
|
|
|
|
// Sync interval dropdown
|
|
const intervalSelect = document.getElementById('mcs-sync-interval');
|
|
const currentInterval = currentConfig.syncInterval || 600;
|
|
for (let i = 0; i < intervalSelect.options.length; i++) {
|
|
if (parseInt(intervalSelect.options[i].value) === currentInterval) {
|
|
intervalSelect.options[i].selected = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Auto-accept checkbox
|
|
document.getElementById('mcs-auto-accept').checked = currentConfig.autoAccept || false;
|
|
|
|
// Show/hide sections based on enabled state
|
|
updateSectionVisibility(currentConfig.enabled || false);
|
|
|
|
// Bind buttons
|
|
document.getElementById('mcs-save').addEventListener('click', onSave);
|
|
document.getElementById('mcs-trigger-sync').addEventListener('click', onTriggerSync);
|
|
}
|
|
|
|
function onEnabledChange(event) {
|
|
updateSectionVisibility(event.target.checked);
|
|
}
|
|
|
|
function updateSectionVisibility(enabled) {
|
|
const sections = [
|
|
'mcs-mail-section',
|
|
'mcs-calendar-section',
|
|
'mcs-interval-section',
|
|
'mcs-auto-accept-section',
|
|
'mcs-save-section',
|
|
];
|
|
sections.forEach(id => {
|
|
document.getElementById(id).style.display = enabled ? '' : 'none';
|
|
});
|
|
}
|
|
|
|
async function onSave() {
|
|
const saveBtn = document.getElementById('mcs-save');
|
|
saveBtn.disabled = true;
|
|
showStatus('Saving…', 'loading');
|
|
|
|
const config = {
|
|
enabled: document.getElementById('mcs-enabled').checked,
|
|
mailAccountId: document.getElementById('mcs-mail-account').value || null,
|
|
calendarUri: document.getElementById('mcs-calendar').value || null,
|
|
autoAccept: document.getElementById('mcs-auto-accept').checked,
|
|
syncInterval: parseInt(document.getElementById('mcs-sync-interval').value) || 600,
|
|
};
|
|
|
|
if (config.enabled) {
|
|
if (!config.mailAccountId) {
|
|
showStatus('Please select a mail account', 'error');
|
|
saveBtn.disabled = false;
|
|
return;
|
|
}
|
|
if (!config.calendarUri) {
|
|
showStatus('Please select a calendar', 'error');
|
|
saveBtn.disabled = false;
|
|
return;
|
|
}
|
|
}
|
|
|
|
try {
|
|
const result = await fetchJson(`${BASE_URL}/config`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(config),
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
|
|
currentConfig = result;
|
|
showStatus('Settings saved', 'success');
|
|
|
|
if (config.enabled) {
|
|
document.getElementById('mcs-log-section').style.display = '';
|
|
loadLog();
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to save config:', error);
|
|
showStatus('Failed to save: ' + error.message, 'error');
|
|
} finally {
|
|
saveBtn.disabled = false;
|
|
}
|
|
}
|
|
|
|
async function onTriggerSync() {
|
|
const btn = document.getElementById('mcs-trigger-sync');
|
|
btn.disabled = true;
|
|
showStatus('Syncing…', 'loading');
|
|
|
|
// Show the sync details section
|
|
const detailsSection = document.getElementById('mcs-sync-details');
|
|
const syncLog = document.getElementById('mcs-sync-log');
|
|
detailsSection.style.display = '';
|
|
syncLog.textContent = 'Running sync…';
|
|
|
|
try {
|
|
const result = await fetchJson(`${BASE_URL}/trigger-sync`, {
|
|
method: 'POST',
|
|
});
|
|
|
|
const stats = result.stats || {};
|
|
const messages = stats.messages || [];
|
|
|
|
// Show detailed log
|
|
if (messages.length > 0) {
|
|
syncLog.textContent = messages.join('\n');
|
|
} else {
|
|
syncLog.textContent = 'Sync completed with no messages.';
|
|
}
|
|
|
|
const msg = `Sync complete: ${stats.processed || 0} scanned, ${stats.updated || 0} updated, ${stats.errors || 0} errors`;
|
|
showStatus(msg, stats.errors > 0 ? 'warning' : 'success');
|
|
|
|
loadLog();
|
|
} catch (error) {
|
|
console.error('Sync failed:', error);
|
|
syncLog.textContent = 'Sync failed: ' + error.message;
|
|
showStatus('Sync failed — see details below', 'error');
|
|
} finally {
|
|
btn.disabled = false;
|
|
}
|
|
}
|
|
|
|
async function loadLog() {
|
|
try {
|
|
const entries = await fetchJson(`${BASE_URL}/log?limit=20`);
|
|
const tbody = document.getElementById('mcs-log-body');
|
|
const emptyMsg = document.getElementById('mcs-log-empty');
|
|
const logSection = document.getElementById('mcs-log-section');
|
|
|
|
if (currentConfig.enabled) {
|
|
logSection.style.display = '';
|
|
}
|
|
|
|
tbody.innerHTML = '';
|
|
|
|
if (entries.length === 0) {
|
|
emptyMsg.style.display = '';
|
|
return;
|
|
}
|
|
|
|
emptyMsg.style.display = 'none';
|
|
|
|
entries.forEach(entry => {
|
|
const tr = document.createElement('tr');
|
|
tr.className = `mcs-log-${entry.action.toLowerCase()}`;
|
|
|
|
const date = entry.createdAt
|
|
? new Date(entry.createdAt).toLocaleString()
|
|
: '—';
|
|
|
|
tr.innerHTML = `
|
|
<td class="mcs-log-date">${escapeHtml(date)}</td>
|
|
<td class="mcs-log-event">${escapeHtml(entry.eventSummary || entry.eventUid || '—')}</td>
|
|
<td class="mcs-log-action"><span class="mcs-badge mcs-badge-${entry.action.toLowerCase()}">${escapeHtml(entry.action)}</span></td>
|
|
<td class="mcs-log-message">${escapeHtml(entry.message || '—')}</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
} catch (error) {
|
|
console.error('Failed to load log:', error);
|
|
}
|
|
}
|
|
|
|
function showStatus(message, type) {
|
|
const statusEl = document.getElementById('mcs-status');
|
|
statusEl.textContent = message;
|
|
statusEl.className = `mcs-status mcs-status-${type}`;
|
|
|
|
if (type === 'success') {
|
|
setTimeout(() => {
|
|
statusEl.textContent = '';
|
|
statusEl.className = 'mcs-status';
|
|
}, 5000);
|
|
}
|
|
}
|
|
|
|
async function fetchJson(url, options = {}) {
|
|
const { headers: optHeaders, ...restOptions } = options;
|
|
const response = await fetch(url, {
|
|
credentials: 'same-origin',
|
|
...restOptions,
|
|
headers: {
|
|
'requesttoken': OC.requestToken,
|
|
...(optHeaders || {}),
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
let errorMsg = `HTTP ${response.status}`;
|
|
try {
|
|
const errorData = await response.json();
|
|
if (errorData.error) {
|
|
errorMsg = errorData.error;
|
|
}
|
|
} catch (e) {
|
|
// ignore parse error
|
|
}
|
|
throw new Error(errorMsg);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
})();
|