- Add .gitignore to exclude node_modules, dist, logs, and system files - Add comprehensive project documentation including README, deployment guide, and development setup - Add .kiro project specifications for amazon-product-bar-extension, appwrite-cloud-storage, appwrite-userid-repair, blacklist-feature, and enhanced-item-management - Add .kiro steering documents for product, structure, styling, and tech guidelines - Add VSCode settings configuration for consistent development environment - Add manifest.json and babel/vite configuration for extension build setup - Add complete source code implementation including AppWrite integration, storage managers, UI components, and services - Add comprehensive test suite with Jest configuration and 30+ test files covering all major modules - Add test HTML files for integration testing and validation - Add coverage reports and build validation scripts - Add AppWrite setup and repair documentation for database schema management - Add migration guides and responsive accessibility implementation documentation - Establish foundation for Amazon product bar extension with full feature set including blacklist management, enhanced item workflows, and real-time synchronization
723 lines
28 KiB
HTML
723 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Real-Time Sync Service Test</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.container {
|
|
background: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
margin-bottom: 20px;
|
|
}
|
|
.status {
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
margin: 10px 0;
|
|
}
|
|
.status.success { background-color: #d4edda; color: #155724; }
|
|
.status.error { background-color: #f8d7da; color: #721c24; }
|
|
.status.info { background-color: #d1ecf1; color: #0c5460; }
|
|
.status.warning { background-color: #fff3cd; color: #856404; }
|
|
button {
|
|
background-color: #007bff;
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 16px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
margin: 5px;
|
|
}
|
|
button:hover { background-color: #0056b3; }
|
|
button:disabled { background-color: #6c757d; cursor: not-allowed; }
|
|
.grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 20px;
|
|
}
|
|
.log {
|
|
background-color: #f8f9fa;
|
|
border: 1px solid #dee2e6;
|
|
border-radius: 4px;
|
|
padding: 10px;
|
|
height: 200px;
|
|
overflow-y: auto;
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
}
|
|
.stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
gap: 10px;
|
|
margin: 10px 0;
|
|
}
|
|
.stat-item {
|
|
background-color: #f8f9fa;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
text-align: center;
|
|
}
|
|
.stat-value {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #007bff;
|
|
}
|
|
.stat-label {
|
|
font-size: 12px;
|
|
color: #6c757d;
|
|
}
|
|
input, select {
|
|
padding: 8px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
margin: 5px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Real-Time Sync Service Test</h1>
|
|
|
|
<div class="container">
|
|
<h2>Service Status</h2>
|
|
<div id="serviceStatus" class="status info">Initializing...</div>
|
|
<div class="stats">
|
|
<div class="stat-item">
|
|
<div id="totalSyncs" class="stat-value">0</div>
|
|
<div class="stat-label">Total Syncs</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div id="successfulSyncs" class="stat-value">0</div>
|
|
<div class="stat-label">Successful</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div id="failedSyncs" class="stat-value">0</div>
|
|
<div class="stat-label">Failed</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div id="successRate" class="stat-value">0%</div>
|
|
<div class="stat-label">Success Rate</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div id="avgSyncTime" class="stat-value">0ms</div>
|
|
<div class="stat-label">Avg Sync Time</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div id="networkStatus" class="stat-value">Unknown</div>
|
|
<div class="stat-label">Network Status</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<div class="container">
|
|
<h2>Sync Operations</h2>
|
|
|
|
<h3>Enhanced Items</h3>
|
|
<div>
|
|
<input type="text" id="itemTitle" placeholder="Item title" value="Test Enhanced Item">
|
|
<input type="text" id="itemPrice" placeholder="Price" value="29.99">
|
|
<input type="text" id="itemUrl" placeholder="Amazon URL" value="https://amazon.de/dp/B08N5WRWNW">
|
|
<br>
|
|
<button onclick="createEnhancedItem()">Create Item</button>
|
|
<button onclick="updateEnhancedItem()">Update Item</button>
|
|
<button onclick="deleteEnhancedItem()">Delete Item</button>
|
|
</div>
|
|
|
|
<h3>Blacklist</h3>
|
|
<div>
|
|
<input type="text" id="brandName" placeholder="Brand name" value="Test Brand">
|
|
<br>
|
|
<button onclick="addBrand()">Add Brand</button>
|
|
<button onclick="deleteBrand()">Delete Brand</button>
|
|
</div>
|
|
|
|
<h3>Settings</h3>
|
|
<div>
|
|
<input type="text" id="apiKey" placeholder="API Key" value="test-api-key-123">
|
|
<select id="titleSelection">
|
|
<option value="first">First</option>
|
|
<option value="second">Second</option>
|
|
<option value="third">Third</option>
|
|
</select>
|
|
<br>
|
|
<button onclick="updateSettings()">Update Settings</button>
|
|
</div>
|
|
|
|
<h3>Batch Operations</h3>
|
|
<div>
|
|
<input type="number" id="batchSize" placeholder="Batch size" value="5" min="1" max="20">
|
|
<br>
|
|
<button onclick="batchCreateItems()">Batch Create Items</button>
|
|
<button onclick="batchCreateBrands()">Batch Create Brands</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<h2>Real-Time Events</h2>
|
|
<button onclick="clearLog()">Clear Log</button>
|
|
<button onclick="forceRefresh()">Force Refresh</button>
|
|
<button onclick="toggleSync()">Toggle Sync</button>
|
|
<div id="eventLog" class="log"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<h2>Collection Monitoring</h2>
|
|
<div id="monitoringStatus" class="status info">Monitoring status will appear here...</div>
|
|
<button onclick="enableAllMonitoring()">Enable All Monitoring</button>
|
|
<button onclick="disableAllMonitoring()">Disable All Monitoring</button>
|
|
</div>
|
|
|
|
<script type="module">
|
|
import { RealTimeSyncService } from './src/RealTimeSyncService.js';
|
|
import { AppWriteManager } from './src/AppWriteManager.js';
|
|
import { OfflineService } from './src/OfflineService.js';
|
|
|
|
let realTimeSyncService = null;
|
|
let appWriteManager = null;
|
|
let offlineService = null;
|
|
let isAuthenticated = false;
|
|
let syncEnabled = true;
|
|
let lastItemId = null;
|
|
let lastBrandId = null;
|
|
|
|
// Initialize services
|
|
async function initializeServices() {
|
|
try {
|
|
updateStatus('Initializing AppWrite services...', 'info');
|
|
|
|
appWriteManager = new AppWriteManager();
|
|
|
|
// Check authentication
|
|
const authService = appWriteManager.getAuthService();
|
|
const user = await authService.getCurrentUser();
|
|
|
|
if (!user) {
|
|
updateStatus('User not authenticated. Please login first.', 'error');
|
|
return;
|
|
}
|
|
|
|
isAuthenticated = true;
|
|
updateStatus(`Authenticated as: ${user.email}`, 'success');
|
|
|
|
// Initialize offline service
|
|
offlineService = new OfflineService(appWriteManager);
|
|
|
|
// Initialize real-time sync service
|
|
realTimeSyncService = new RealTimeSyncService(appWriteManager, offlineService);
|
|
|
|
// Setup event listeners
|
|
setupEventListeners();
|
|
|
|
// Enable monitoring for all collections
|
|
await enableAllMonitoring();
|
|
|
|
updateStatus('Real-time sync service initialized successfully!', 'success');
|
|
updateStats();
|
|
|
|
} catch (error) {
|
|
console.error('Failed to initialize services:', error);
|
|
updateStatus(`Initialization failed: ${error.message}`, 'error');
|
|
}
|
|
}
|
|
|
|
function setupEventListeners() {
|
|
// Real-time sync events
|
|
realTimeSyncService.addEventListener('sync:completed', (data) => {
|
|
logEvent('Sync Completed', data);
|
|
updateStats();
|
|
});
|
|
|
|
realTimeSyncService.addEventListener('sync:error', (data) => {
|
|
logEvent('Sync Error', data);
|
|
updateStats();
|
|
});
|
|
|
|
realTimeSyncService.addEventListener('data:changed', (data) => {
|
|
logEvent('Data Changed', data);
|
|
});
|
|
|
|
realTimeSyncService.addEventListener('batch:completed', (data) => {
|
|
logEvent('Batch Completed', data);
|
|
updateStats();
|
|
});
|
|
|
|
// Offline service events
|
|
if (offlineService) {
|
|
offlineService.onOnlineStatusChanged((isOnline) => {
|
|
logEvent('Network Status', { isOnline });
|
|
updateNetworkStatus(isOnline);
|
|
});
|
|
|
|
offlineService.onSyncProgress((status, processed, total) => {
|
|
logEvent('Sync Progress', { status, processed, total });
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateStatus(message, type = 'info') {
|
|
const statusEl = document.getElementById('serviceStatus');
|
|
statusEl.textContent = message;
|
|
statusEl.className = `status ${type}`;
|
|
}
|
|
|
|
function updateStats() {
|
|
if (!realTimeSyncService) return;
|
|
|
|
const stats = realTimeSyncService.getSyncStats();
|
|
|
|
document.getElementById('totalSyncs').textContent = stats.totalSyncs;
|
|
document.getElementById('successfulSyncs').textContent = stats.successfulSyncs;
|
|
document.getElementById('failedSyncs').textContent = stats.failedSyncs;
|
|
document.getElementById('successRate').textContent = `${stats.successRate}%`;
|
|
document.getElementById('avgSyncTime').textContent = `${stats.averageSyncTime}ms`;
|
|
}
|
|
|
|
function updateNetworkStatus(isOnline) {
|
|
const statusEl = document.getElementById('networkStatus');
|
|
statusEl.textContent = isOnline ? 'Online' : 'Offline';
|
|
statusEl.style.color = isOnline ? '#28a745' : '#dc3545';
|
|
}
|
|
|
|
function logEvent(type, data) {
|
|
const logEl = document.getElementById('eventLog');
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
const logEntry = `[${timestamp}] ${type}: ${JSON.stringify(data, null, 2)}\n`;
|
|
logEl.textContent += logEntry;
|
|
logEl.scrollTop = logEl.scrollHeight;
|
|
}
|
|
|
|
// Sync operation functions
|
|
window.createEnhancedItem = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated) {
|
|
updateStatus('Service not initialized or not authenticated', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const title = document.getElementById('itemTitle').value;
|
|
const price = document.getElementById('itemPrice').value;
|
|
const url = document.getElementById('itemUrl').value;
|
|
|
|
const itemData = {
|
|
itemId: `test_${Date.now()}`,
|
|
amazonUrl: url,
|
|
originalTitle: title,
|
|
customTitle: `Enhanced: ${title}`,
|
|
price: price,
|
|
currency: 'EUR',
|
|
titleSuggestions: [`AI: ${title}`, `Smart: ${title}`, `Pro: ${title}`],
|
|
hashValue: `hash_${Date.now()}`,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
lastItemId = itemData.itemId;
|
|
|
|
const result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('enhancedItems'),
|
|
'create',
|
|
itemData.itemId,
|
|
itemData
|
|
);
|
|
|
|
if (result.success) {
|
|
updateStatus('Enhanced item created successfully!', 'success');
|
|
} else {
|
|
updateStatus(`Failed to create item: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error creating enhanced item:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.updateEnhancedItem = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated || !lastItemId) {
|
|
updateStatus('No item to update or service not ready', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Find the document first
|
|
const documents = await appWriteManager.getUserDocuments(
|
|
appWriteManager.getCollectionId('enhancedItems'),
|
|
[{ method: 'equal', attribute: 'itemId', values: [lastItemId] }]
|
|
);
|
|
|
|
if (documents.documents.length === 0) {
|
|
updateStatus('Item not found for update', 'error');
|
|
return;
|
|
}
|
|
|
|
const updateData = {
|
|
customTitle: `Updated: ${document.getElementById('itemTitle').value}`,
|
|
price: document.getElementById('itemPrice').value,
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
const result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('enhancedItems'),
|
|
'update',
|
|
documents.documents[0].$id,
|
|
updateData
|
|
);
|
|
|
|
if (result.success) {
|
|
updateStatus('Enhanced item updated successfully!', 'success');
|
|
} else {
|
|
updateStatus(`Failed to update item: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating enhanced item:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.deleteEnhancedItem = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated || !lastItemId) {
|
|
updateStatus('No item to delete or service not ready', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Find the document first
|
|
const documents = await appWriteManager.getUserDocuments(
|
|
appWriteManager.getCollectionId('enhancedItems'),
|
|
[{ method: 'equal', attribute: 'itemId', values: [lastItemId] }]
|
|
);
|
|
|
|
if (documents.documents.length === 0) {
|
|
updateStatus('Item not found for deletion', 'error');
|
|
return;
|
|
}
|
|
|
|
const result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('enhancedItems'),
|
|
'delete',
|
|
documents.documents[0].$id
|
|
);
|
|
|
|
if (result.success) {
|
|
updateStatus('Enhanced item deleted successfully!', 'success');
|
|
lastItemId = null;
|
|
} else {
|
|
updateStatus(`Failed to delete item: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error deleting enhanced item:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.addBrand = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated) {
|
|
updateStatus('Service not initialized or not authenticated', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const brandName = document.getElementById('brandName').value;
|
|
|
|
const brandData = {
|
|
brandId: `bl_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
|
name: brandName,
|
|
addedAt: new Date().toISOString()
|
|
};
|
|
|
|
lastBrandId = brandData.brandId;
|
|
|
|
const result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('blacklist'),
|
|
'create',
|
|
null,
|
|
brandData
|
|
);
|
|
|
|
if (result.success) {
|
|
updateStatus('Brand added successfully!', 'success');
|
|
} else {
|
|
updateStatus(`Failed to add brand: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error adding brand:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.deleteBrand = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated || !lastBrandId) {
|
|
updateStatus('No brand to delete or service not ready', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Find the document first
|
|
const documents = await appWriteManager.getUserDocuments(
|
|
appWriteManager.getCollectionId('blacklist'),
|
|
[{ method: 'equal', attribute: 'brandId', values: [lastBrandId] }]
|
|
);
|
|
|
|
if (documents.documents.length === 0) {
|
|
updateStatus('Brand not found for deletion', 'error');
|
|
return;
|
|
}
|
|
|
|
const result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('blacklist'),
|
|
'delete',
|
|
documents.documents[0].$id
|
|
);
|
|
|
|
if (result.success) {
|
|
updateStatus('Brand deleted successfully!', 'success');
|
|
lastBrandId = null;
|
|
} else {
|
|
updateStatus(`Failed to delete brand: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error deleting brand:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.updateSettings = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated) {
|
|
updateStatus('Service not initialized or not authenticated', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const apiKey = document.getElementById('apiKey').value;
|
|
const titleSelection = document.getElementById('titleSelection').value;
|
|
|
|
const settingsData = {
|
|
mistralApiKey: apiKey,
|
|
defaultTitleSelection: titleSelection,
|
|
autoExtractEnabled: true,
|
|
maxRetries: 3,
|
|
timeoutSeconds: 10,
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
// Check if settings document exists
|
|
const existingSettings = await appWriteManager.getUserDocuments(
|
|
appWriteManager.getCollectionId('settings')
|
|
);
|
|
|
|
let result;
|
|
if (existingSettings.documents.length > 0) {
|
|
result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('settings'),
|
|
'update',
|
|
existingSettings.documents[0].$id,
|
|
settingsData
|
|
);
|
|
} else {
|
|
result = await realTimeSyncService.syncToCloud(
|
|
appWriteManager.getCollectionId('settings'),
|
|
'create',
|
|
null,
|
|
settingsData
|
|
);
|
|
}
|
|
|
|
if (result.success) {
|
|
updateStatus('Settings updated successfully!', 'success');
|
|
} else {
|
|
updateStatus(`Failed to update settings: ${result.message}`, 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating settings:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.batchCreateItems = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated) {
|
|
updateStatus('Service not initialized or not authenticated', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const batchSize = parseInt(document.getElementById('batchSize').value);
|
|
const operations = [];
|
|
|
|
for (let i = 0; i < batchSize; i++) {
|
|
const itemData = {
|
|
itemId: `batch_item_${Date.now()}_${i}`,
|
|
amazonUrl: `https://amazon.de/dp/BATCH${i}`,
|
|
originalTitle: `Batch Item ${i + 1}`,
|
|
customTitle: `Enhanced Batch Item ${i + 1}`,
|
|
price: `${(Math.random() * 100).toFixed(2)}`,
|
|
currency: 'EUR',
|
|
titleSuggestions: [`AI Batch ${i + 1}`, `Smart Batch ${i + 1}`],
|
|
hashValue: `batch_hash_${Date.now()}_${i}`,
|
|
createdAt: new Date().toISOString(),
|
|
updatedAt: new Date().toISOString()
|
|
};
|
|
|
|
operations.push({
|
|
collectionId: appWriteManager.getCollectionId('enhancedItems'),
|
|
operation: 'create',
|
|
documentId: itemData.itemId,
|
|
data: itemData
|
|
});
|
|
}
|
|
|
|
updateStatus(`Creating ${batchSize} items in batch...`, 'info');
|
|
|
|
const result = await realTimeSyncService.batchSync(operations);
|
|
|
|
if (result.success) {
|
|
updateStatus(`Batch created successfully! ${result.successfulOperations}/${result.totalOperations} items created.`, 'success');
|
|
} else {
|
|
updateStatus(`Batch partially failed: ${result.successfulOperations}/${result.totalOperations} items created.`, 'warning');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in batch create:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.batchCreateBrands = async function() {
|
|
if (!realTimeSyncService || !isAuthenticated) {
|
|
updateStatus('Service not initialized or not authenticated', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const batchSize = parseInt(document.getElementById('batchSize').value);
|
|
const operations = [];
|
|
|
|
for (let i = 0; i < batchSize; i++) {
|
|
const brandData = {
|
|
brandId: `batch_brand_${Date.now()}_${i}`,
|
|
name: `Batch Brand ${i + 1}`,
|
|
addedAt: new Date().toISOString()
|
|
};
|
|
|
|
operations.push({
|
|
collectionId: appWriteManager.getCollectionId('blacklist'),
|
|
operation: 'create',
|
|
data: brandData
|
|
});
|
|
}
|
|
|
|
updateStatus(`Creating ${batchSize} brands in batch...`, 'info');
|
|
|
|
const result = await realTimeSyncService.batchSync(operations);
|
|
|
|
if (result.success) {
|
|
updateStatus(`Batch created successfully! ${result.successfulOperations}/${result.totalOperations} brands created.`, 'success');
|
|
} else {
|
|
updateStatus(`Batch partially failed: ${result.successfulOperations}/${result.totalOperations} brands created.`, 'warning');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in batch create:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.clearLog = function() {
|
|
document.getElementById('eventLog').textContent = '';
|
|
};
|
|
|
|
window.forceRefresh = async function() {
|
|
if (!realTimeSyncService) {
|
|
updateStatus('Service not initialized', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await realTimeSyncService.forceRefreshAll();
|
|
updateStatus('Force refresh completed!', 'success');
|
|
} catch (error) {
|
|
console.error('Error in force refresh:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.toggleSync = function() {
|
|
if (!realTimeSyncService) {
|
|
updateStatus('Service not initialized', 'error');
|
|
return;
|
|
}
|
|
|
|
syncEnabled = !syncEnabled;
|
|
realTimeSyncService.setSyncEnabled(syncEnabled);
|
|
updateStatus(`Sync ${syncEnabled ? 'enabled' : 'disabled'}`, 'info');
|
|
};
|
|
|
|
window.enableAllMonitoring = async function() {
|
|
if (!realTimeSyncService || !appWriteManager) {
|
|
updateStatus('Services not initialized', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const collections = ['enhancedItems', 'blacklist', 'settings'];
|
|
|
|
for (const collection of collections) {
|
|
await realTimeSyncService.enableSyncForCollection(
|
|
appWriteManager.getCollectionId(collection),
|
|
{
|
|
onDataChanged: (documents) => {
|
|
logEvent(`${collection} Data Changed`, { count: documents.length });
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
const stats = realTimeSyncService.getSyncStats();
|
|
document.getElementById('monitoringStatus').textContent =
|
|
`Monitoring enabled for ${stats.monitoredCollections.length} collections: ${stats.monitoredCollections.join(', ')}`;
|
|
document.getElementById('monitoringStatus').className = 'status success';
|
|
|
|
} catch (error) {
|
|
console.error('Error enabling monitoring:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
window.disableAllMonitoring = function() {
|
|
if (!realTimeSyncService || !appWriteManager) {
|
|
updateStatus('Services not initialized', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const collections = ['enhancedItems', 'blacklist', 'settings'];
|
|
|
|
for (const collection of collections) {
|
|
realTimeSyncService.disableSyncForCollection(
|
|
appWriteManager.getCollectionId(collection)
|
|
);
|
|
}
|
|
|
|
document.getElementById('monitoringStatus').textContent = 'All monitoring disabled';
|
|
document.getElementById('monitoringStatus').className = 'status warning';
|
|
|
|
} catch (error) {
|
|
console.error('Error disabling monitoring:', error);
|
|
updateStatus(`Error: ${error.message}`, 'error');
|
|
}
|
|
};
|
|
|
|
// Initialize on page load
|
|
document.addEventListener('DOMContentLoaded', initializeServices);
|
|
|
|
// Update network status on load
|
|
updateNetworkStatus(navigator.onLine);
|
|
</script>
|
|
</body>
|
|
</html> |