Files
domnitor/app/Views/tld-registry/import-progress.twig

303 lines
14 KiB
Twig
Raw Normal View History

{% extends 'layout/base.twig' %}
{% set title = title|default('Import Progress') %}
{% set pageTitle = title %}
{% set pageDescription = 'Progressive data import with real-time progress' %}
{% set pageIcon = 'fas fa-tasks' %}
{% block content %}
2025-10-08 14:23:07 +03:00
<div class="max-w-4xl mx-auto">
{# Header #}
2025-10-08 14:23:07 +03:00
<div class="mb-6">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">{{ title }}</h1>
<p class="text-gray-600 dark:text-slate-400 mt-1">
{% set descriptions = {
tld_list: 'Importing complete TLD list from IANA',
rdap: 'Importing RDAP servers for existing TLDs',
whois: 'Importing WHOIS & Registry data via RDAP API (with HTML fallback)',
check_updates: 'Checking for IANA updates',
complete_workflow: 'Complete TLD import workflow (TLD List → RDAP → WHOIS & Registry Data)'
} %}
{{ descriptions[import_type]|default('Processing import') }}
2025-10-08 14:23:07 +03:00
</p>
</div>
<a href="/tld-registry" class="inline-flex items-center px-4 py-2 border border-gray-300 dark:border-slate-600 text-gray-700 dark:text-slate-300 text-sm rounded-lg hover:bg-gray-50 dark:hover:bg-slate-700 transition-colors font-medium">
2025-10-08 14:23:07 +03:00
<i class="fas fa-arrow-left mr-2"></i>
Back to TLD Registry
</a>
</div>
</div>
{# Progress Card #}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-gray-200 dark:border-slate-700 p-6 mb-6">
2025-10-08 14:23:07 +03:00
<div class="flex items-center justify-between mb-4">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Import Status</h2>
<div id="status-badge" class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-yellow-100 dark:bg-yellow-500/10 text-yellow-800 dark:text-yellow-400">
2025-10-08 14:23:07 +03:00
<i class="fas fa-clock mr-2"></i>
<span id="status-text">Starting...</span>
</div>
</div>
{# Progress Bar #}
2025-10-08 14:23:07 +03:00
<div class="mb-4">
<div class="flex justify-between text-sm text-gray-600 dark:text-slate-400 mb-2">
2025-10-08 14:23:07 +03:00
<span id="progress-text">0 of 0 items processed</span>
<span id="percentage-text">0%</span>
</div>
<div class="w-full bg-gray-200 dark:bg-slate-700 rounded-full h-3">
2025-10-08 14:23:07 +03:00
<div id="progress-bar" class="bg-blue-600 h-3 rounded-full transition-all duration-300" style="width: 0%"></div>
</div>
</div>
{# Step Progress (for complete workflow) #}
2025-10-08 14:23:07 +03:00
<div id="step-progress" class="mb-4" style="display: none;">
<div class="text-sm text-gray-600 dark:text-slate-400 mb-2">Workflow Steps:</div>
2025-10-08 14:23:07 +03:00
<div class="grid grid-cols-3 gap-2">
<div class="step-item bg-gray-100 dark:bg-slate-700 rounded-lg p-2 text-center">
<div class="text-xs font-medium text-gray-600 dark:text-slate-400">Step 1</div>
<div class="text-xs text-gray-500 dark:text-slate-400">TLD List</div>
<div id="step-1-status" class="text-xs text-gray-400 dark:text-slate-500">Pending</div>
2025-10-08 14:23:07 +03:00
</div>
<div class="step-item bg-gray-100 dark:bg-slate-700 rounded-lg p-2 text-center">
<div class="text-xs font-medium text-gray-600 dark:text-slate-400">Step 2</div>
<div class="text-xs text-gray-500 dark:text-slate-400">RDAP</div>
<div id="step-2-status" class="text-xs text-gray-400 dark:text-slate-500">Pending</div>
2025-10-08 14:23:07 +03:00
</div>
<div class="step-item bg-gray-100 dark:bg-slate-700 rounded-lg p-2 text-center">
<div class="text-xs font-medium text-gray-600 dark:text-slate-400">Step 3</div>
<div class="text-xs text-gray-500 dark:text-slate-400">WHOIS & Registry</div>
<div id="step-3-status" class="text-xs text-gray-400 dark:text-slate-500">Pending</div>
2025-10-08 14:23:07 +03:00
</div>
</div>
</div>
{# Statistics #}
2025-10-08 14:23:07 +03:00
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="bg-gray-50 dark:bg-slate-900 rounded-lg p-4">
2025-10-08 14:23:07 +03:00
<div class="flex items-center">
<div class="w-10 h-10 bg-blue-100 dark:bg-blue-500/10 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-list text-blue-600 dark:text-blue-400"></i>
2025-10-08 14:23:07 +03:00
</div>
<div>
<p class="text-sm text-gray-500 dark:text-slate-400">Total</p>
<p id="total-count" class="text-xl font-semibold text-gray-900 dark:text-white">0</p>
2025-10-08 14:23:07 +03:00
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-slate-900 rounded-lg p-4">
2025-10-08 14:23:07 +03:00
<div class="flex items-center">
<div class="w-10 h-10 bg-green-100 dark:bg-green-500/10 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-check text-green-600 dark:text-green-400"></i>
2025-10-08 14:23:07 +03:00
</div>
<div>
<p class="text-sm text-gray-500 dark:text-slate-400">Processed</p>
<p id="processed-count" class="text-xl font-semibold text-gray-900 dark:text-white">0</p>
2025-10-08 14:23:07 +03:00
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-slate-900 rounded-lg p-4">
2025-10-08 14:23:07 +03:00
<div class="flex items-center">
<div class="w-10 h-10 bg-red-100 dark:bg-red-500/10 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-times text-red-600 dark:text-red-400"></i>
2025-10-08 14:23:07 +03:00
</div>
<div>
<p class="text-sm text-gray-500 dark:text-slate-400">Failed</p>
<p id="failed-count" class="text-xl font-semibold text-gray-900 dark:text-white">0</p>
2025-10-08 14:23:07 +03:00
</div>
</div>
</div>
<div class="bg-gray-50 dark:bg-slate-900 rounded-lg p-4">
2025-10-08 14:23:07 +03:00
<div class="flex items-center">
<div class="w-10 h-10 bg-orange-100 dark:bg-orange-500/10 rounded-lg flex items-center justify-center mr-3">
<i class="fas fa-hourglass-half text-orange-600 dark:text-orange-400"></i>
2025-10-08 14:23:07 +03:00
</div>
<div>
<p class="text-sm text-gray-500 dark:text-slate-400">Remaining</p>
<p id="remaining-count" class="text-xl font-semibold text-gray-900 dark:text-white">0</p>
2025-10-08 14:23:07 +03:00
</div>
</div>
</div>
</div>
</div>
{# Log Output #}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-gray-200 dark:border-slate-700 p-6">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Import Log</h3>
2025-10-08 14:23:07 +03:00
<div id="log-output" class="bg-gray-900 text-green-400 p-4 rounded-lg font-mono text-sm h-64 overflow-y-auto">
<div class="text-gray-500">Initializing import process...</div>
</div>
</div>
</div>
<script>
let logId = {{ log_id|json_encode|raw }};
let importType = {{ import_type|json_encode|raw }};
2025-10-08 14:23:07 +03:00
let isComplete = false;
let totalProcessed = 0;
let totalFailed = 0;
if (importType === 'complete_workflow') {
document.getElementById('step-progress').style.display = 'block';
}
function addLogMessage(message, type = 'info') {
const logOutput = document.getElementById('log-output');
const timestamp = new Date().toLocaleTimeString();
const colorClass = type === 'error' ? 'text-red-400' : type === 'success' ? 'text-green-400' : 'text-blue-400';
2025-10-08 14:23:07 +03:00
const logEntry = document.createElement('div');
logEntry.className = colorClass;
logEntry.innerHTML = `[${timestamp}] ${message}`;
2025-10-08 14:23:07 +03:00
logOutput.appendChild(logEntry);
logOutput.scrollTop = logOutput.scrollHeight;
}
function updateProgress(data) {
const total = data.total || 0;
const processed = data.processed || 0;
const failed = data.failed || 0;
const remaining = data.remaining || 0;
2025-10-08 14:23:07 +03:00
document.getElementById('total-count').textContent = total;
document.getElementById('processed-count').textContent = processed;
document.getElementById('failed-count').textContent = failed;
document.getElementById('remaining-count').textContent = remaining;
2025-10-08 14:23:07 +03:00
const totalToProcess = processed + remaining;
const percentage = totalToProcess > 0 ? Math.round((processed / totalToProcess) * 100) : 0;
2025-10-08 14:23:07 +03:00
document.getElementById('progress-bar').style.width = percentage + '%';
document.getElementById('progress-text').textContent = `${processed} of ${totalToProcess} items processed`;
document.getElementById('percentage-text').textContent = percentage + '%';
2025-10-08 14:23:07 +03:00
if (importType === 'complete_workflow' && data.message) {
updateStepProgress(data.message, processed, total);
}
const statusBadge = document.getElementById('status-badge');
const statusText = document.getElementById('status-text');
2025-10-08 14:23:07 +03:00
if (data.status === 'complete') {
statusBadge.className = 'inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-green-100 dark:bg-green-500/10 text-green-800 dark:text-green-400';
2025-10-08 14:23:07 +03:00
statusText.innerHTML = '<i class="fas fa-check mr-2"></i>Complete';
isComplete = true;
const completionMessage = data.message || 'Import completed successfully!';
addLogMessage(completionMessage, 'success');
2025-10-08 14:23:07 +03:00
if (importType === 'complete_workflow') {
for (let i = 1; i <= 3; i++) {
updateStepStatus(i, 'completed');
}
}
} else if (data.status === 'in_progress') {
statusBadge.className = 'inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-blue-100 dark:bg-blue-500/10 text-blue-800 dark:text-blue-400';
2025-10-08 14:23:07 +03:00
statusText.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>In Progress';
addLogMessage(data.message || 'Processing batch...', 'info');
} else if (data.status === 'error') {
statusBadge.className = 'inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 dark:bg-red-500/10 text-red-800 dark:text-red-400';
2025-10-08 14:23:07 +03:00
statusText.innerHTML = '<i class="fas fa-exclamation-triangle mr-2"></i>Error';
addLogMessage(data.message || 'An error occurred', 'error');
isComplete = true;
}
}
function checkProgress() {
if (isComplete) {
return;
}
2025-10-08 14:23:07 +03:00
fetch(`/tld-registry/api/import-progress?log_id=${logId}`)
.then(response => {
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
return response.text().then(text => {
addLogMessage('Server returned non-JSON response. This might be a PHP error or session issue.', 'error');
addLogMessage('Response preview: ' + text.substring(0, 200) + '...', 'error');
isComplete = true;
throw new Error('Non-JSON response received');
});
}
return response.json();
})
2025-10-08 14:23:07 +03:00
.then(data => {
if (data.error) {
addLogMessage('Error: ' + data.error, 'error');
isComplete = true;
return;
}
2025-10-08 14:23:07 +03:00
updateProgress(data);
2025-10-08 14:23:07 +03:00
if (data.status !== 'complete' && data.status !== 'error') {
setTimeout(checkProgress, 2000);
2025-10-08 14:23:07 +03:00
}
})
.catch(error => {
if (error.message.includes('Gateway Timeout') || error.message.includes('timeout')) {
addLogMessage('Gateway timeout detected. Retrying in 5 seconds...', 'warning');
setTimeout(checkProgress, 5000);
} else {
addLogMessage('Network error: ' + error.message, 'error');
isComplete = true;
}
2025-10-08 14:23:07 +03:00
});
}
function updateStepProgress(message, currentStep, totalSteps) {
const stepMatch = message.match(/Step (\d+)\/(\d+)/);
if (stepMatch) {
const stepNumber = parseInt(stepMatch[1]);
const totalSteps = parseInt(stepMatch[2]);
2025-10-08 14:23:07 +03:00
const isCompleted = message.toLowerCase().includes('completed');
2025-10-08 14:23:07 +03:00
if (isCompleted) {
for (let i = 1; i <= stepNumber; i++) {
updateStepStatus(i, 'completed');
}
2025-10-08 14:23:07 +03:00
if (stepNumber < totalSteps) {
updateStepStatus(stepNumber + 1, 'in_progress');
}
} else {
for (let i = 1; i < stepNumber; i++) {
updateStepStatus(i, 'completed');
}
2025-10-08 14:23:07 +03:00
updateStepStatus(stepNumber, 'in_progress');
}
}
}
function updateStepStatus(stepNumber, status) {
const stepElement = document.getElementById(`step-${stepNumber}-status`);
const stepItem = stepElement.closest('.step-item');
2025-10-08 14:23:07 +03:00
if (status === 'completed') {
stepElement.textContent = 'Completed';
stepElement.className = 'text-xs text-green-600 dark:text-green-400';
stepItem.className = 'step-item bg-green-100 dark:bg-green-500/10 rounded-lg p-2 text-center';
2025-10-08 14:23:07 +03:00
} else if (status === 'in_progress') {
stepElement.textContent = 'In Progress';
stepElement.className = 'text-xs text-blue-600 dark:text-blue-400';
stepItem.className = 'step-item bg-blue-100 dark:bg-blue-500/10 rounded-lg p-2 text-center';
2025-10-08 14:23:07 +03:00
} else if (status === 'failed') {
stepElement.textContent = 'Failed';
stepElement.className = 'text-xs text-red-600 dark:text-red-400';
stepItem.className = 'step-item bg-red-100 dark:bg-red-500/10 rounded-lg p-2 text-center';
2025-10-08 14:23:07 +03:00
}
}
checkProgress();
</script>
{% endblock %}