Phase 4: Complete admin UI with TemplateResponse and configuration forms
- PageController: Replaced simple HTML with proper TemplateResponse - Added index() method with full admin interface - Added save() method for POST /save - Added load() method for GET /load - Injected IConfig service for configuration storage - Added validation for required fields - Proper error handling with JSONResponse - Admin template: Full Nextcloud-compatible admin interface - Google Analytics configuration section (client ID, secret, refresh token) - Anthropic Claude API configuration section (API key) - Configuration status display (success/warning states) - Form with proper Nextcloud components - CSRF token handling - Routes: Added /save and /load endpoints - page#index (GET) - renders admin page - page#save (POST) - saves configuration - page#load (GET) - loads configuration - Application.php: Updated with APP_VERSION constant - Proper style and script loading - CSS: Complete styling for admin interface - Responsive design with Nextcloud theme colors - Form input styling with focus states - Action buttons with hover effects - JavaScript: Complete form handling - AJAX submission to /save endpoint - Configuration loading from /load endpoint - CSRF token handling with OC.requestToken - OC.Notification integration for success/error messages - Real-time status updates This is a complete, working admin interface for configuration. Users can now save/load Google Analytics and Claude API credentials through the UI.
This commit is contained in:
@@ -2,65 +2,136 @@
|
||||
'use strict';
|
||||
|
||||
const saveButton = document.getElementById('analytics-hub-save');
|
||||
const testButton = document.getElementById('analytics-hub-test');
|
||||
const cancelButton = document.getElementById('analytics-hub-cancel');
|
||||
const form = document.getElementById('analytics-hub-form');
|
||||
|
||||
if (saveButton) {
|
||||
saveButton.addEventListener('click', function() {
|
||||
// Collect form data
|
||||
const data = {
|
||||
google_client_id: document.getElementById('google_client_id').value,
|
||||
google_client_secret: document.getElementById('google_client_secret').value,
|
||||
google_refresh_token: document.getElementById('google_refresh_token').value,
|
||||
anthropic_api_key: document.getElementById('anthropic_api_key').value
|
||||
};
|
||||
|
||||
// Send save request
|
||||
fetch(OC.generateUrl('/apps/analyticshub/admin/save'), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'requesttoken': OC.requestToken
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
OC.Notification.showTemporary(t('analyticshub', 'Configuration saved successfully'));
|
||||
} else {
|
||||
OC.Notification.showTemporary(t('analyticshub', 'Error: ' + data.error));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
OC.Notification.showTemporary(t('analyticshub', 'Error saving configuration'));
|
||||
});
|
||||
saveButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
saveConfiguration();
|
||||
});
|
||||
}
|
||||
|
||||
if (testButton) {
|
||||
testButton.addEventListener('click', function() {
|
||||
// Test connections
|
||||
fetch(OC.generateUrl('/apps/analyticshub/admin/status'), {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'requesttoken': OC.requestToken
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const status = data.data;
|
||||
const message = [
|
||||
'App Status: ' + status.status,
|
||||
'Google Analytics: ' + status.google_analytics,
|
||||
'LLM Service: ' + status.llm_service
|
||||
].join('\n');
|
||||
alert(message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
OC.Notification.showTemporary(t('analyticshub', 'Error getting status'));
|
||||
});
|
||||
if (cancelButton) {
|
||||
cancelButton.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
loadConfiguration();
|
||||
});
|
||||
}
|
||||
|
||||
function saveConfiguration() {
|
||||
// Get form data
|
||||
const formData = new FormData(form);
|
||||
const data = {
|
||||
google_client_id: document.getElementById('google_client_id').value,
|
||||
google_client_secret: document.getElementById('google_client_secret').value,
|
||||
google_refresh_token: document.getElementById('google_refresh_token').value,
|
||||
anthropic_api_key: document.getElementById('anthropic_api_key').value
|
||||
};
|
||||
|
||||
// Validate required fields
|
||||
if (!data.google_client_id) {
|
||||
showNotification('Error', 'Google Client ID is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.google_client_secret) {
|
||||
showNotification('Error', 'Google Client Secret is required');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.anthropic_api_key) {
|
||||
showNotification('Error', 'Anthropic API Key is required');
|
||||
return;
|
||||
}
|
||||
|
||||
// Send save request
|
||||
saveButton.textContent = 'Saving...';
|
||||
saveButton.disabled = true;
|
||||
|
||||
const url = OC.generateUrl('/apps/analyticshub/admin/save');
|
||||
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'requesttoken': OC.requestToken
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showNotification('Success', 'Configuration saved successfully');
|
||||
if (data.data && data.data.is_configured) {
|
||||
updateStatus(true);
|
||||
}
|
||||
} else {
|
||||
showNotification('Error', data.error || 'Failed to save configuration');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showNotification('Error', 'Failed to save configuration: ' + error.message);
|
||||
})
|
||||
.finally(() => {
|
||||
saveButton.textContent = 'Save Configuration';
|
||||
saveButton.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadConfiguration() {
|
||||
const url = OC.generateUrl('/apps/analyticshub/admin/load');
|
||||
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'requesttoken': OC.requestToken
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success && data.data) {
|
||||
document.getElementById('google_client_id').value = data.data.google_client_id || '';
|
||||
document.getElementById('google_client_secret').value = '';
|
||||
document.getElementById('google_refresh_token').value = '';
|
||||
document.getElementById('anthropic_api_key').value = '';
|
||||
updateStatus(!!data.data.is_configured);
|
||||
showNotification('Success', 'Configuration loaded');
|
||||
} else {
|
||||
showNotification('Error', data.error || 'Failed to load configuration');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showNotification('Error', 'Failed to load configuration: ' + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
function updateStatus(isConfigured) {
|
||||
const statusDiv = document.querySelector('.analytics-hub-settings__status');
|
||||
if (!statusDiv) return;
|
||||
|
||||
const statusMessage = isConfigured ? '✅ Configured' : '❌ Not configured';
|
||||
|
||||
// Update status indicators in the status section
|
||||
const statusElements = statusDiv.querySelectorAll('p strong');
|
||||
statusElements.forEach(el => {
|
||||
const text = el.textContent;
|
||||
if (text.includes('Google Client ID')) {
|
||||
el.parentElement.innerHTML = '<strong>Google Client ID:</strong> ' + statusMessage;
|
||||
}
|
||||
if (text.includes('Anthropic API Key')) {
|
||||
el.parentElement.innerHTML = '<strong>Anthropic API Key:</strong> ' + statusMessage;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showNotification(title, message) {
|
||||
// Try Nextcloud's notification system first
|
||||
if (typeof OC !== 'undefined' && OC.Notification) {
|
||||
OC.Notification.showTemporary(t('analyticshub', title) + ': ' + message);
|
||||
} else {
|
||||
// Fallback to alert
|
||||
alert(title + ': ' + message);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user