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

366 lines
11 KiB
Ruby
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env ruby
# frozen_string_literal: true
# tools/orquestador/dashboard/actualizar_estados.rb
# ================================================
# Herramienta para actualizar el estado de hitos en el dashboard P2601
# Filosofía: "Menos es más" - herramienta pequeña, específica y reutilizable
require 'fileutils'
class EstadoHitosManager
ESTADOS_VALIDOS = {
'pending' => { nombre: 'Pendiente', clase: 'pending', color: '#eab308' },
'in-progress' => { nombre: 'En Progreso', clase: 'in-progress', color: '#3b82f6' },
'completed' => { nombre: 'Completado', clase: 'completed', color: '#22c55e' },
'blocked' => { nombre: 'Bloqueado', clase: 'blocked', color: '#ef4444' },
'on-hold' => { nombre: 'En Espera', clase: 'on-hold', color: '#8b5cf6' }
}.freeze
def initialize(dashboard_path = nil)
@dashboard_path = dashboard_path || default_dashboard_path
@backup_dir = File.join(File.dirname(@dashboard_path), 'backups')
end
def default_dashboard_path
File.expand_path('../../../../dashboard/index.html', __FILE__)
end
def listar_hitos
puts "📋 LISTADO DE HITOS DISPONIBLES"
puts "=" * 50
unless File.exist?(@dashboard_path)
puts "❌ Error: No se encuentra el dashboard en #{@dashboard_path}"
return false
end
content = File.read(@dashboard_path)
hitos = extraer_hitos(content)
if hitos.empty?
puts "️ No se encontraron hitos en el dashboard"
return true
end
puts "🎯 Total de hitos encontrados: #{hitos.size}"
puts
hitos.each_with_index do |hito, i|
estado_info = ESTADOS_VALIDOS[hito[:estado]] || ESTADOS_VALIDOS['pending']
puts " #{i + 1}. [#{hito[:id]}] #{hito[:titulo]}"
puts " 📊 Estado actual: #{estado_info[:nombre]} (#{hito[:estado]})"
puts " 📅 Fecha: #{hito[:fecha]}"
puts " 🏷️ Tags: #{hito[:tags].join(', ')}" if hito[:tags].any?
puts
end
mostrar_resumen_estados(hitos)
true
end
def actualizar_estado(hito_id, nuevo_estado, fecha = nil)
puts "🔄 ACTUALIZANDO ESTADO DE HITO"
puts "=" * 50
# Validar estado
unless ESTADOS_VALIDOS.key?(nuevo_estado)
puts "❌ Error: Estado '#{nuevo_estado}' no válido"
puts " Estados válidos: #{ESTADOS_VALIDOS.keys.join(', ')}"
return false
end
unless File.exist?(@dashboard_path)
puts "❌ Error: No se encuentra el dashboard"
return false
end
# Crear backup
create_backup
# Leer contenido
puts "📖 Leyendo dashboard..."
content = File.read(@dashboard_path)
# Buscar y actualizar hito
puts "🔍 Buscando hito: #{hito_id}"
nuevo_contenido, hito_encontrado = actualizar_hito_en_contenido(content, hito_id, nuevo_estado, fecha)
unless hito_encontrado
puts "❌ Error: No se encontró el hito con ID '#{hito_id}'"
puts " Use 'listar' para ver los hitos disponibles"
return false
end
# Guardar cambios
puts "💾 Guardando dashboard actualizado..."
File.write(@dashboard_path, nuevo_contenido)
# Mostrar resultados
estado_info = ESTADOS_VALIDOS[nuevo_estado]
puts "\n✅ Estado actualizado exitosamente"
puts " • Hito: #{hito_id}"
puts " • Nuevo estado: #{estado_info[:nombre]}"
puts " • Fecha: #{fecha || 'Actualizada automáticamente'}"
true
end
def actualizar_multiples(hitos_estados)
puts "🔄 ACTUALIZANDO MÚLTIPLES HITOS"
puts "=" * 50
unless File.exist?(@dashboard_path)
puts "❌ Error: No se encuentra el dashboard"
return false
end
# Validar todos los estados primero
hitos_estados.each do |hito_id, estado|
unless ESTADOS_VALIDOS.key?(estado)
puts "❌ Error: Estado '#{estado}' no válido para hito '#{hito_id}'"
return false
end
end
# Crear backup
create_backup
# Leer contenido
puts "📖 Leyendo dashboard..."
content = File.read(@dashboard_path)
nuevo_contenido = content.dup
# Actualizar cada hito
resultados = {}
hitos_estados.each do |hito_id, estado|
puts "🔍 Actualizando hito: #{hito_id} -> #{estado}"
nuevo_contenido, encontrado = actualizar_hito_en_contenido(nuevo_contenido, hito_id, estado)
resultados[hito_id] = encontrado
end
# Guardar cambios
puts "💾 Guardando dashboard actualizado..."
File.write(@dashboard_path, nuevo_contenido)
# Mostrar resultados
puts "\n📊 RESULTADOS DE ACTUALIZACIÓN:"
exitos = resultados.values.count(true)
fallos = resultados.values.count(false)
resultados.each do |hito_id, exitoso|
emoji = exitoso ? '✅' : '❌'
puts " #{emoji} #{hito_id}: #{exitoso ? 'Actualizado' : 'No encontrado'}"
end
puts "\n📈 RESUMEN:"
puts " • Hitós actualizados exitosamente: #{exitos}"
puts " • Hitós no encontrados: #{fallos}"
exitos > 0
end
def mostrar_estados_disponibles
puts "🎨 ESTADOS DISPONIBLES"
puts "=" * 50
ESTADOS_VALIDOS.each do |codigo, info|
puts " • #{codigo}: #{info[:nombre]}"
puts " Clase CSS: #{info[:clase]}"
puts " Color: #{info[:color]}"
puts
end
true
end
private
def create_backup
FileUtils.mkdir_p(@backup_dir) unless Dir.exist?(@backup_dir)
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
backup_file = File.join(@backup_dir, "dashboard_estados_#{timestamp}.html")
puts "💾 Creando backup en: #{backup_file}"
FileUtils.cp(@dashboard_path, backup_file)
puts "✅ Backup creado"
end
def extraer_hitos(content)
hitos = []
# Buscar todos los hitos
content.scan(/<div class="tl-item">([\s\S]*?)<\/div>\s*<\/div>\s*<\/div>/m) 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>/)
next unless id_match && titulo_match
hitos << {
id: id_match[1],
titulo: titulo_match[1],
estado: estado_match ? estado_match[1] : 'pending',
fecha: fecha_match ? fecha_match[1] : 'Sin fecha',
tags: hito.scan(/<span class="[^"]*tag[^"]*">([^<]+)<\/span>/).flatten,
html_completo: hito_html[0]
}
end
hitos.uniq { |h| h[:id] }
end
def actualizar_hito_en_contenido(content, hito_id, nuevo_estado, fecha = nil)
fecha_actual = fecha || Time.now.strftime('%Y-%m-%d')
estado_info = ESTADOS_VALIDOS[nuevo_estado]
# Patrón para encontrar el hito específico
patron_hito = /(<div class="tl-item">[\s\S]*?<span class="tl-id">#{Regexp.escape(hito_id)}<\/span>[\s\S]*?<\/div>\s*<\/div>\s*<\/div>)/
hito_encontrado = false
nuevo_contenido = content.gsub(patron_hito) do |hito_completo|
hito_encontrado = true
# Actualizar estado (clase del dot)
hito_actualizado = hito_completo.gsub(
/<div class="tl-dot ([^"]+)"><\/div>/,
"<div class=\"tl-dot #{nuevo_estado}\"></div>"
)
# Actualizar fecha
hito_actualizado = hito_actualizado.gsub(
/<span class="tl-date">([^<]+)<\/span>/,
"<span class=\"tl-date\">#{estado_info[:nombre]} - #{fecha_actual}</span>"
)
hito_actualizado
end
[nuevo_contenido, hito_encontrado]
end
def mostrar_resumen_estados(hitos)
return if hitos.empty?
puts "📊 RESUMEN DE ESTADOS"
puts "=" * 50
conteo_estados = Hash.new(0)
hitos.each { |h| conteo_estados[h[:estado]] += 1 }
total = hitos.size
conteo_estados.each do |estado, cantidad|
porcentaje = (cantidad * 100.0 / total).round(1)
estado_info = ESTADOS_VALIDOS[estado] || ESTADOS_VALIDOS['pending']
puts " • #{estado_info[:nombre]}: #{cantidad} (#{porcentaje}%)"
end
puts "\n💡 RECOMENDACIONES:"
if conteo_estados['pending'] && conteo_estados['pending'] > total * 0.7
puts " • Muchos hitos pendientes (#{conteo_estados['pending']}/#{total})"
puts " • Considerar avanzar algunos a 'en-progreso'"
end
if conteo_estados['completed'] && conteo_estados['completed'] < total * 0.2
puts " • Pocos hitos completados (#{conteo_estados['completed'] || 0}/#{total})"
puts " • Revisar progreso real del proyecto"
end
puts
end
end
# Interfaz de línea de comandos
if __FILE__ == $0
begin
manager = EstadoHitosManager.new
# Parsear argumentos
command = ARGV[0] || 'listar'
case command
when 'listar', 'list', 'ls'
success = manager.listar_hitos
when 'actualizar', 'update'
if ARGV.length < 3
puts "❌ Error: Se requieren ID del hito y nuevo estado"
puts " Uso: #{$0} actualizar ID_HITO NUEVO_ESTADO [FECHA]"
puts " Ejemplo: #{$0} actualizar BKP02 in-progress 2024-03-06"
success = false
else
hito_id = ARGV[1]
nuevo_estado = ARGV[2]
fecha = ARGV[3] if ARGV.length >= 4
success = manager.actualizar_estado(hito_id, nuevo_estado, fecha)
end
when 'multiples', 'batch'
if ARGV.length < 2 || ARGV[1..-1].length.odd?
puts "❌ Error: Se requieren pares ID-ESTADO"
puts " Uso: #{$0} multiples ID1 ESTADO1 ID2 ESTADO2 ..."
puts " Ejemplo: #{$0} multiples BKP02 in-progress DB02 completed"
success = false
else
hitos_estados = {}
args = ARGV[1..-1]
args.each_slice(2) do |hito_id, estado|
hitos_estados[hito_id] = estado
end
success = manager.actualizar_multiples(hitos_estados)
end
when 'estados', 'states'
success = manager.mostrar_estados_disponibles
when 'help', '--help', '-h'
puts "📖 USO:"
puts " #{$0} [comando] [argumentos...]"
puts
puts "COMANDOS:"
puts " listar, list - Listar hitos disponibles con sus estados (predeterminado)"
puts " actualizar, update ID ESTADO [FECHA] - Actualizar estado de un hito"
puts " multiples, batch ID1 ESTADO1 ID2 ESTADO2 ... - Actualizar múltiples hitos"
puts " estados, states - Mostrar estados disponibles"
puts " help - Mostrar esta ayuda"
puts
puts "ESTADOS DISPONIBLES:"
puts " pending - Pendiente (amarillo)"
puts " in-progress - En Progreso (azul)"
puts " completed - Completado (verde)"
puts " blocked - Bloqueado (rojo)"
puts " on-hold - En Espera (púrpura)"
puts
puts "EJEMPLOS:"
puts " #{$0} listar"
puts " #{$0} actualizar BKP02 in-progress"
puts " #{$0} actualizar DB02 completed 2024-03-06"
puts " #{$0} multiples BKP02 in-progress MON01 completed"
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. Revisar dashboard actualizado"
puts " 2. Verificar que los estados se muestren correctamente"
puts " 3. Actualizar bitácora del proyecto con los cambios"
puts "\n📅 #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
puts "=" * 50
else
exit 1
end
rescue => e
puts "❌ Error: #{e.message}"
puts e.backtrace if ENV['DEBUG']
exit 1
end
end