mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 23:32:58 +00:00
243 lines
7.1 KiB
JavaScript
243 lines
7.1 KiB
JavaScript
/**
|
|
* Reusable polling system for NetCop AI agents
|
|
* Handles async request polling with proper cleanup and error handling
|
|
*/
|
|
|
|
class AgentPoller {
|
|
constructor(config) {
|
|
this.requestId = config.requestId;
|
|
this.statusUrl = config.statusUrl;
|
|
this.maxPolls = config.maxPolls || 30;
|
|
this.pollInterval = config.pollInterval || 1000;
|
|
this.onComplete = config.onComplete;
|
|
this.onError = config.onError;
|
|
this.onTimeout = config.onTimeout;
|
|
|
|
// Internal state
|
|
this.pollCount = 0;
|
|
this.currentInterval = null;
|
|
this.isPolling = false;
|
|
this.resultsDisplayed = false;
|
|
}
|
|
|
|
start() {
|
|
if (this.isPolling) {
|
|
console.warn('Poller is already running');
|
|
return;
|
|
}
|
|
|
|
this.isPolling = true;
|
|
this.pollCount = 0;
|
|
this.resultsDisplayed = false;
|
|
|
|
// Clear any existing interval
|
|
this.stop();
|
|
|
|
this.currentInterval = setInterval(() => {
|
|
this.pollCount++;
|
|
|
|
fetch(this.statusUrl)
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(result => {
|
|
if (result.status === 'completed' || result.status === 'failed') {
|
|
this.stop();
|
|
|
|
// Display results only once
|
|
if (!this.resultsDisplayed) {
|
|
this.resultsDisplayed = true;
|
|
if (this.onComplete) {
|
|
this.onComplete(result);
|
|
}
|
|
}
|
|
} else if (this.pollCount >= this.maxPolls) {
|
|
this.stop();
|
|
if (this.onTimeout) {
|
|
this.onTimeout();
|
|
}
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error polling results:', error);
|
|
this.stop();
|
|
if (this.onError) {
|
|
this.onError(error);
|
|
}
|
|
});
|
|
}, this.pollInterval);
|
|
}
|
|
|
|
stop() {
|
|
if (this.currentInterval) {
|
|
clearInterval(this.currentInterval);
|
|
this.currentInterval = null;
|
|
}
|
|
this.isPolling = false;
|
|
}
|
|
|
|
isRunning() {
|
|
return this.isPolling;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Global polling manager to handle multiple pollers
|
|
*/
|
|
class PollingManager {
|
|
constructor() {
|
|
this.pollers = new Map();
|
|
}
|
|
|
|
createPoller(id, config) {
|
|
// Stop existing poller if any
|
|
this.stopPoller(id);
|
|
|
|
const poller = new AgentPoller(config);
|
|
this.pollers.set(id, poller);
|
|
return poller;
|
|
}
|
|
|
|
stopPoller(id) {
|
|
const poller = this.pollers.get(id);
|
|
if (poller) {
|
|
poller.stop();
|
|
this.pollers.delete(id);
|
|
}
|
|
}
|
|
|
|
stopAll() {
|
|
this.pollers.forEach(poller => poller.stop());
|
|
this.pollers.clear();
|
|
}
|
|
}
|
|
|
|
// Global instance
|
|
window.pollingManager = new PollingManager();
|
|
|
|
/**
|
|
* Utility functions for common agent UI operations
|
|
*/
|
|
window.AgentUtils = {
|
|
// Update wallet balance display
|
|
updateWalletBalance(newBalance) {
|
|
const balanceElement = document.querySelector('[data-wallet-balance]') ||
|
|
document.getElementById('walletBalance');
|
|
if (balanceElement) {
|
|
balanceElement.textContent = `${newBalance.toFixed(2)} AED`;
|
|
}
|
|
window.currentWalletBalance = newBalance;
|
|
},
|
|
|
|
// Reset UI to initial state
|
|
resetUI(config) {
|
|
const elements = {
|
|
processingStatus: document.getElementById(config.processingStatusId || 'processingStatus'),
|
|
processButton: document.getElementById(config.processButtonId || 'processButton'),
|
|
results: document.getElementById(config.resultsId)
|
|
};
|
|
|
|
if (elements.processingStatus) {
|
|
elements.processingStatus.style.display = 'none';
|
|
}
|
|
|
|
if (elements.processButton) {
|
|
elements.processButton.disabled = false;
|
|
elements.processButton.innerHTML = config.buttonText || 'Process';
|
|
}
|
|
|
|
if (elements.results) {
|
|
elements.results.style.display = 'none';
|
|
}
|
|
},
|
|
|
|
// Show processing status
|
|
showProcessing(config) {
|
|
const elements = {
|
|
processingStatus: document.getElementById(config.processingStatusId || 'processingStatus'),
|
|
processButton: document.getElementById(config.processButtonId || 'processButton'),
|
|
results: document.getElementById(config.resultsId)
|
|
};
|
|
|
|
if (elements.processingStatus) {
|
|
elements.processingStatus.style.display = 'block';
|
|
}
|
|
|
|
if (elements.processButton) {
|
|
elements.processButton.disabled = true;
|
|
elements.processButton.innerHTML = config.processingText || '⏳ Processing...';
|
|
}
|
|
|
|
if (elements.results) {
|
|
elements.results.style.display = 'none';
|
|
}
|
|
},
|
|
|
|
// Show toast notification
|
|
showToast(message, type = 'info') {
|
|
// Prevent duplicate toasts
|
|
const existingToast = document.querySelector('.agent-toast');
|
|
if (existingToast) {
|
|
existingToast.remove();
|
|
}
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = 'agent-toast';
|
|
toast.style.cssText = `
|
|
position: fixed;
|
|
top: 16px;
|
|
right: 16px;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
color: white;
|
|
font-size: 13px;
|
|
z-index: 1000;
|
|
max-width: 300px;
|
|
font-weight: 500;
|
|
${type === 'success' ? 'background: #10b981;' : 'background: #ef4444;'}
|
|
`;
|
|
toast.textContent = message;
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
if (toast.parentNode) {
|
|
toast.remove();
|
|
}
|
|
}, 2000);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Progressive status steps for better UX
|
|
*/
|
|
window.StatusStepper = class {
|
|
constructor(steps, statusTextElementId, interval = 800) {
|
|
this.steps = steps;
|
|
this.statusTextElement = document.getElementById(statusTextElementId);
|
|
this.interval = interval;
|
|
this.currentStep = 0;
|
|
this.stepInterval = null;
|
|
}
|
|
|
|
start() {
|
|
this.currentStep = 0;
|
|
this.stepInterval = setInterval(() => {
|
|
if (this.currentStep < this.steps.length && this.statusTextElement) {
|
|
this.statusTextElement.textContent = this.steps[this.currentStep];
|
|
this.currentStep++;
|
|
} else {
|
|
this.stop();
|
|
}
|
|
}, this.interval);
|
|
}
|
|
|
|
stop() {
|
|
if (this.stepInterval) {
|
|
clearInterval(this.stepInterval);
|
|
this.stepInterval = null;
|
|
}
|
|
}
|
|
}; |