#!/usr/bin/env ruby # frozen_string_literal: true # tools/orquestador/dashboard/vista_previa.rb # =========================================== # Herramienta para vista previa rápida del dashboard P2601 # Filosofía: "Menos es más" - herramienta pequeña, específica y reutilizable require 'fileutils' class DashboardPreview 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 mostrar_vista_previa(modo = 'resumen') puts "👁️ VISTA PREVIA DEL DASHBOARD P2601" puts "=" * 60 unless File.exist?(@dashboard_path) puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}" return false end puts "📖 Analizando dashboard..." content = File.read(@dashboard_path) case modo when 'resumen' mostrar_resumen(content) when 'hitos' mostrar_hitos_detallados(content) when 'estructura' mostrar_estructura(content) when 'estadisticas' mostrar_estadisticas(content) else puts "❌ Modo '#{modo}' no válido" puts " Modos disponibles: resumen, hitos, estructura, estadisticas" return false end true end def mostrar_resumen_rapido puts "⚡ RESUMEN RÁPIDO DASHBOARD" puts "=" * 40 unless File.exist?(@dashboard_path) puts "❌ Dashboard no encontrado" return false end content = File.read(@dashboard_path) # Información básica puts "📄 Archivo: #{File.basename(@dashboard_path)}" puts " • Tamaño: #{content.bytesize / 1024} KB" puts " • Líneas: #{content.lines.count}" puts " • Última modificación: #{File.mtime(@dashboard_path).strftime('%Y-%m-%d %H:%M')}" # Hitos hitos_count = content.scan(/
/).size hitos_unicos = extraer_hitos_unicos(content).size puts "🎯 Hitos: #{hitos_count} totales, #{hitos_unicos} únicos" # Estados estados = contar_estados_hitos(content) if estados.any? puts "📊 Estados:" estados.each do |estado, count| puts " • #{estado}: #{count}" end end # Timeline timeline_presente = content.include?('class="timeline"') puts "📅 Timeline: #{timeline_presente ? '✅ Presente' : '❌ Ausente'}" # Métricas clave metricas = extraer_metricas_clave(content) if metricas.any? puts "📈 Métricas clave:" metricas.each do |nombre, valor| puts " • #{nombre}: #{valor}" end end puts "\n🔗 URL: https://ns8.frlr.utn.edu.ar/bitacoras/p2601" puts "📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}" puts "=" * 40 true end private def mostrar_resumen(content) puts "📋 RESUMEN COMPLETO" puts "=" * 60 # Información del archivo puts "📄 INFORMACIÓN DEL ARCHIVO:" puts " • Ruta: #{@dashboard_path}" puts " • Tamaño: #{content.bytesize} bytes (#{content.bytesize / 1024} KB)" puts " • Líneas: #{content.lines.count}" puts " • Encoding: #{content.encoding.name}" # Estructura HTML puts "\n🏗️ ESTRUCTURA HTML:" elementos = { 'DOCTYPE html' => content.include?(''), 'Elemento head' => content.include?('') && content.include?(''), 'Elemento body' => content.include?('') && content.include?(''), 'Título P2601' => content.include?('P2601'), 'Container principal' => content.include?('class="container"'), 'Header' => content.include?('class="header"'), 'Footer' => content.include?('class="footer"') } elementos.each do |elemento, presente| puts " • #{elemento}: #{presente ? '✅' : '❌'}" end # Hitos puts "\n🎯 INFORMACIÓN DE HITOS:" hitos_count = content.scan(/
/).size hitos_unicos = extraer_hitos_unicos(content) puts " • Total de hitos: #{hitos_count}" puts " • Hitos únicos: #{hitos_unicos.size}" if hitos_unicos.any? puts " • Distribución por estado:" estados = Hash.new(0) hitos_unicos.each { |h| estados[h[:estado]] += 1 } estados.each do |estado, count| porcentaje = (count * 100.0 / hitos_unicos.size).round(1) puts " - #{estado}: #{count} (#{porcentaje}%)" end end # Timeline puts "\n📅 TIMELINE:" timeline_presente = content.include?('class="timeline"') puts " • Presente: #{timeline_presente ? '✅ Sí' : '❌ No'}" if timeline_presente timeline_match = content.match(/
([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m) if timeline_match hitos_en_timeline = timeline_match[1].scan(/
/).size puts " • Hitos en timeline: #{hitos_en_timeline}" end end # Métricas puts "\n📈 MÉTRICAS Y ESTADÍSTICAS:" metricas = { 'Progreso General' => content.include?('Progreso General'), 'Hitos Completados' => content.include?('Hitos Completados'), 'Hitos Pendientes' => content.include?('Hitos Pendientes'), 'Esfuerzo Total' => content.include?('Esfuerzo Total') } metricas.each do |metrica, presente| puts " • #{metrica}: #{presente ? '✅ Presente' : '❌ Ausente'}" end # Extraer valores de métricas si existen valores_metricas = extraer_valores_metricas(content) if valores_metricas.any? puts " • Valores encontrados:" valores_metricas.each do |nombre, valor| puts " - #{nombre}: #{valor}" end end puts "\n💡 RECOMENDACIONES:" if hitos_count > hitos_unicos.size * 2 puts " • Posibles hitos duplicados detectados" puts " • Considerar usar 'limpiar.rb'" end if hitos_unicos.size < 3 puts " • Pocos hitos definidos" puts " • Considerar agregar más hitos con 'agregar_hitos.rb'" end puts "\n✅ Resumen completado" end def mostrar_hitos_detallados(content) puts "📋 HITOS DETALLADOS" puts "=" * 60 hitos = extraer_hitos_unicos(content) if hitos.empty? puts "ℹ️ No se encontraron hitos en el dashboard" return end puts "🎯 Total de hitos únicos: #{hitos.size}" puts hitos.each_with_index do |hito, i| puts " #{i + 1}. [#{hito[:id]}] #{hito[:titulo]}" puts " 📊 Estado: #{hito[:estado]}" puts " 📅 Fecha: #{hito[:fecha]}" puts " 🏷️ Tags: #{hito[:tags].join(', ')}" if hito[:tags].any? # Mostrar descripción truncada if hito[:descripcion] && hito[:descripcion].length > 100 puts " 📝 Descripción: #{hito[:descripcion][0..100]}..." elsif hito[:descripcion] puts " 📝 Descripción: #{hito[:descripcion]}" end puts end # Resumen de estados puts "📊 RESUMEN DE ESTADOS:" estados = Hash.new(0) hitos.each { |h| estados[h[:estado]] += 1 } estados.each do |estado, count| porcentaje = (count * 100.0 / hitos.size).round(1) puts " • #{estado}: #{count} hitos (#{porcentaje}%)" end end def mostrar_estructura(content) puts "🏗️ ESTRUCTURA DEL DASHBOARD" puts "=" * 60 # Mostrar secciones principales puts "📂 SECCIONES PRINCIPALES:" secciones = [ { nombre: 'Head', inicio: '', fin: '' }, { nombre: 'Body', inicio: '', fin: '' }, { nombre: 'Header', inicio: 'class="header"', fin: nil }, { nombre: 'Timeline', inicio: 'class="timeline"', fin: '
' }, { nombre: 'Footer', inicio: 'class="footer"', fin: '' } ] secciones.each do |seccion| presente = content.include?(seccion[:inicio]) puts " • #{seccion[:nombre]}: #{presente ? '✅ Presente' : '❌ Ausente'}" if presente && seccion[:fin] && content.include?(seccion[:fin]) # Calcular tamaño aproximado de la sección inicio_idx = content.index(seccion[:inicio]) fin_idx = content.index(seccion[:fin], inicio_idx) if inicio_idx && fin_idx tamaño = fin_idx - inicio_idx + seccion[:fin].length puts " Tamaño: ~#{tamaño} bytes" end end end # Contar elementos HTML puts "\n🔢 CONTEO DE ELEMENTOS HTML:" elementos = { 'Divs' => content.scan(/
content.scan(/ content.scan(/ content.scan(/

/).size, 'Enlaces (a)' => content.scan(/]*>/, ' ').gsub(/\s+/, ' ') puts " • Caracteres totales: #{content.length}" puts " • Caracteres sin HTML: #{texto_sin_html.length}" puts " • Palabras aproximadas: #{texto_sin_html.split.size}" puts " • Líneas de código: #{content.lines.count}" # Densidad de información if hitos.any? palabras_por_hito = texto_sin_html.split.size / hitos.size.to_f puts " • Palabras por hito: #{palabras_por_hito.round(1)}" end end def extraer_hitos_unicos(content) hitos = [] content.scan(/