Files
dtic-DIIAA/tools/orquestador/dashboard/verificar.rb
T

369 lines
10 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# frozen_string_literal: true
# tools/orquestador/dashboard/verificar.rb
# ========================================
# Herramienta para verificar el estado y estructura del dashboard P2601
# Filosofía: "Menos es más" - herramienta pequeña, específica y reutilizable
require 'fileutils'
class DashboardVerifier
def initialize(dashboard_path = nil)
@dashboard_path = dashboard_path || default_dashboard_path
end
def default_dashboard_path
File.expand_path('../../../../dashboard/index.html', __FILE__)
end
def verificar_estructura
puts "🔍 VERIFICANDO ESTRUCTURA DEL DASHBOARD P2601"
puts "=" * 60
unless File.exist?(@dashboard_path)
puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}"
return false
end
# Leer contenido
puts "📖 Analizando dashboard..."
content = File.read(@dashboard_path)
# Realizar verificaciones
resultados = {
archivo: verificar_archivo(content),
estructura: verificar_estructura_basica(content),
hitos: verificar_hitos(content),
timeline: verificar_timeline(content),
estadisticas: verificar_estadisticas(content)
}
# Mostrar resumen
mostrar_resumen(resultados)
# Retornar éxito si todas las verificaciones críticas pasan
resultados[:archivo][:exito] && resultados[:estructura][:exito]
end
def analizar_hitos
puts "📋 ANALIZANDO HITOS DEL DASHBOARD"
puts "=" * 60
unless File.exist?(@dashboard_path)
puts "❌ Error: No se encuentra el dashboard"
return false
end
content = File.read(@dashboard_path)
# Extraer información de hitos
hitos_info = extraer_info_hitos(content)
# Mostrar análisis
mostrar_analisis_hitos(hitos_info)
true
end
private
def verificar_archivo(content)
puts "📄 Verificando archivo..."
{
exito: true,
detalles: {
tamaño_bytes: content.length,
lineas: content.lines.count,
encoding: content.encoding.name,
valido_html: content.include?('<!DOCTYPE html>') && content.include?('</html>')
}
}
end
def verificar_estructura_basica(content)
puts "🏗️ Verificando estructura básica..."
elementos_requeridos = {
'DOCTYPE html' => content.include?('<!DOCTYPE html>'),
'head' => content.include?('<head>') && content.include?('</head>'),
'body' => content.include?('<body>') && content.include?('</body>'),
'title P2601' => content.include?('P2601'),
'container' => content.include?('class="container"'),
'header' => content.include?('class="header"'),
'footer' => content.include?('class="footer"')
}
exito = elementos_requeridos.values.all?
{
exito: exito,
detalles: elementos_requeridos
}
end
def verificar_hitos(content)
puts "🎯 Verificando hitos..."
# Buscar hitos
hitos_count = content.scan(/<div class="tl-item">/).size
hitos_duplicados = buscar_hitos_duplicados(content)
# Verificar estructura de hitos
hitos_validos = content.scan(/<div class="tl-item">[\s\S]*?<\/div>\s*<\/div>\s*<\/div>/m).size
{
exito: hitos_count > 0 && hitos_count == hitos_validos,
detalles: {
total_hitos: hitos_count,
hitos_validos: hitos_validos,
hitos_duplicados: hitos_duplicados.size,
porcentaje_validos: hitos_count > 0 ? (hitos_validos * 100 / hitos_count).round(1) : 0
}
}
end
def verificar_timeline(content)
puts "📅 Verificando timeline..."
timeline_presente = content.include?('class="timeline"')
if timeline_presente
# Extraer sección timeline
timeline_match = content.match(/<div class="timeline">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m)
timeline_content = timeline_match ? timeline_match[1] : ''
hitos_en_timeline = timeline_content.scan(/<div class="tl-item">/).size
else
hitos_en_timeline = 0
end
{
exito: timeline_presente,
detalles: {
presente: timeline_presente,
hitos_en_timeline: hitos_en_timeline
}
}
end
def verificar_estadisticas(content)
puts "📊 Verificando estadísticas..."
# Buscar métricas comunes
metricas = {
progreso: content.include?('Progreso General') || content.include?('progressPct'),
hitos_completados: content.include?('Hitos Completados'),
hitos_pendientes: content.include?('Hitos Pendientes'),
esfuerzo_total: content.include?('Esfuerzo Total')
}
{
exito: metricas.values.any?,
detalles: metricas
}
end
def buscar_hitos_duplicados(content)
# Extraer todos los hitos
hitos = content.scan(/<div class="tl-item">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m)
# Buscar duplicados por ID
ids_encontrados = {}
duplicados = []
hitos.each do |hito_html|
# Buscar ID en el hito
id_match = hito_html[0].match(/<span class="tl-id">([^<]+)<\/span>/)
next unless id_match
id = id_match[1]
if ids_encontrados[id]
duplicados << id
else
ids_encontrados[id] = true
end
end
duplicados
end
def extraer_info_hitos(content)
# Extraer todos los hitos
hitos_matches = content.scan(/<div class="tl-item">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m)
hitos_info = []
hitos_matches.each do |hito_html|
hito = hito_html[0]
# Extraer información
id_match = hito.match(/<span class="tl-id">([^<]+)<\/span>/)
titulo_match = hito.match(/<div class="tl-title">([^<]+)<\/div>/)
estado_match = hito.match(/<div class="tl-dot ([^"]+)"><\/div>/)
fecha_match = hito.match(/<span class="tl-date">([^<]+)<\/span>/)
hitos_info << {
id: id_match ? id_match[1] : 'Desconocido',
titulo: titulo_match ? titulo_match[1] : 'Sin título',
estado: estado_match ? estado_match[1] : 'unknown',
fecha: fecha_match ? fecha_match[1] : 'Sin fecha',
tags: hito.scan(/<span class="[^"]*tag[^"]*">([^<]+)<\/span>/).flatten
}
end
hitos_info.uniq { |h| h[:id] } # Eliminar duplicados por ID
end
def mostrar_resumen(resultados)
puts "\n📋 RESUMEN DE VERIFICACIÓN"
puts "=" * 60
resultados.each do |nombre, resultado|
emoji = resultado[:exito] ? '✅' : '❌'
puts "#{emoji} #{nombre.to_s.capitalize}: #{resultado[:exito] ? 'OK' : 'PROBLEMA'}"
# Mostrar detalles importantes
if resultado[:detalles].is_a?(Hash)
resultado[:detalles].each do |detalle, valor|
puts " • #{detalle}: #{valor}"
end
end
puts
end
# Resumen general
verificaciones_exitosas = resultados.values.count { |r| r[:exito] }
total_verificaciones = resultados.size
puts "📊 RESUMEN GENERAL:"
puts " • Verificaciones exitosas: #{verificaciones_exitosas}/#{total_verificaciones}"
puts " • Porcentaje de éxito: #{(verificaciones_exitosas * 100 / total_verificaciones).round(1)}%"
if verificaciones_exitosas == total_verificaciones
puts "\n🎉 ¡Todas las verificaciones pasaron exitosamente!"
else
puts "\n⚠️ Se encontraron problemas que requieren atención"
end
end
def mostrar_analisis_hitos(hitos_info)
puts "📈 ANÁLISIS DE HITOS"
puts "=" * 60
if hitos_info.empty?
puts "❌ No se encontraron hitos en el dashboard"
return
end
# Estadísticas generales
puts "📊 ESTADÍSTICAS:"
puts " • Total de hitos únicos: #{hitos_info.size}"
# Agrupar por estado
estados = Hash.new(0)
hitos_info.each { |h| estados[h[:estado]] += 1 }
puts " • Distribución por estado:"
estados.each do |estado, count|
porcentaje = (count * 100.0 / hitos_info.size).round(1)
puts " - #{estado}: #{count} (#{porcentaje}%)"
end
# Tags más comunes
todos_tags = hitos_info.flat_map { |h| h[:tags] }
tags_frecuentes = Hash.new(0)
todos_tags.each { |tag| tags_frecuentes[tag] += 1 }
if tags_frecuentes.any?
puts " • Tags más comunes:"
tags_frecuentes.sort_by { |_, count| -count }.first(5).each do |tag, count|
puts " - #{tag}: #{count} hitos"
end
end
# Lista de hitos
puts "\n📋 LISTA DE HITOS:"
hitos_info.each_with_index do |hito, i|
puts " #{i + 1}. [#{hito[:id]}] #{hito[:titulo]}"
puts " Estado: #{hito[:estado]} | Fecha: #{hito[:fecha]}"
puts " Tags: #{hito[:tags].join(', ')}" if hito[:tags].any?
puts
end
# Recomendaciones
puts "💡 RECOMENDACIONES:"
if estados['pending'] && estados['pending'] > hitos_info.size * 0.5
puts " • Muchos hitos pendientes (#{estados['pending']}/#{hitos_info.size})"
puts " • Considerar priorizar y actualizar estados"
end
if hitos_info.size < 5
puts " • Pocos hitos definidos (#{hitos_info.size})"
puts " • Considerar agregar más hitos para mejor seguimiento"
end
puts "\n✅ Análisis completado"
end
end
# Interfaz de línea de comandos
if __FILE__ == $0
begin
# Parsear argumentos
dashboard_path = nil
command = 'verificar'
ARGV.each_with_index do |arg, i|
if arg == '--dashboard' && ARGV[i + 1]
dashboard_path = ARGV[i + 1]
elsif i == 0 && !arg.start_with?('--')
command = arg
end
end
verifier = DashboardVerifier.new(dashboard_path)
case command
when 'verificar', 'check'
success = verifier.verificar_estructura
when 'analizar', 'analyze'
success = verifier.analizar_hitos
when 'help', '--help', '-h'
puts "📖 USO:"
puts " #{$0} [comando] [--dashboard RUTA]"
puts
puts "COMANDOS:"
puts " verificar, check - Verificar estructura del dashboard (predeterminado)"
puts " analizar, analyze - Analizar hitos en detalle"
puts " help - Mostrar esta ayuda"
puts
puts "OPCIONES:"
puts " --dashboard RUTA - Ruta personalizada al archivo dashboard"
puts
success = true
else
puts "❌ Comando '#{command}' no reconocido"
puts " Use '#{$0} help' para ver la ayuda"
success = false
end
if success
puts "\n🚀 PRÓXIMOS PASOS SUGERIDOS:"
puts " 1. Usar 'limpiar.rb' si hay hitos duplicados"
puts " 2. Usar 'agregar_hitos.rb' para agregar hitos de fase 5"
puts " 3. Revisar dashboard en: https://ns8.frlr.utn.edu.ar/bitacoras/p2601"
puts "\n📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
puts "=" * 60
else
exit 1
end
rescue => e
puts "❌ Error: #{e.message}"
puts e.backtrace if ENV['DEBUG']
exit 1
end
end