#!/usr/bin/env ruby # frozen_string_literal: true # tools/orquestador/lib/hitos/manager.rb # ====================================== # Clase para manejo centralizado de hitos del dashboard P2601 # Filosofía: "Menos es más" - código reutilizable y modular require_relative '../dashboard_core' module DashboardCore class HitosManager < Base attr_reader :hitos_cache def initialize(dashboard_path = nil) super(dashboard_path) @hitos_cache = nil end # Métodos principales para gestión de hitos def cargar_hitos(force_reload = false) return @hitos_cache if @hitos_cache && !force_reload contenido = leer_dashboard @hitos_cache = extraer_hitos(contenido) @hitos_cache end def buscar_hito_por_id(id_hito) hitos = cargar_hitos hitos.find { |h| h[:id] == id_hito } end def buscar_hitos_por_fase(numero_fase) hitos = cargar_hitos hitos.select do |hito| info = HitoIdGenerator.parsear_id(hito[:id]) info && info[:fase] == numero_fase end end def buscar_hitos_por_estado(estado) hitos = cargar_hitos hitos.select { |h| h[:estado] == estado } end def buscar_hitos_por_tag(tag) hitos = cargar_hitos hitos.select { |h| h[:tags].include?(tag) } end def agregar_hito(hito_data) # Validar datos del hito unless hito_data[:id] && hito_data[:titulo] raise "ID y título son requeridos para agregar un hito" end # Validar formato del ID unless HitoIdGenerator.es_valido?(hito_data[:id]) raise "ID de hito inválido. Formato esperado: fNNNNN (ej: f05001)" end # Verificar que no exista ya if buscar_hito_por_id(hito_data[:id]) raise "El hito con ID #{hito_data[:id]} ya existe" end # Crear backup crear_backup('agregar_hito') # Leer contenido actual contenido = leer_dashboard # Generar HTML del hito hito_html = generar_html_hito(hito_data) # Insertar en la timeline nuevo_contenido = insertar_hitos_en_timeline(contenido, hito_html, 'append') # Guardar cambios guardar_dashboard(nuevo_contenido) # Actualizar cache @hitos_cache = nil cargar_hitos(true) puts "✅ Hito #{hito_data[:id]} agregado exitosamente" true end def actualizar_hito(id_hito, cambios) # Verificar que el hito exista hito_existente = buscar_hito_por_id(id_hito) unless hito_existente raise "Hito #{id_hito} no encontrado" end # Validar cambios permitidos cambios_permitidos = [:estado, :fecha, :titulo, :descripcion, :tags] cambios.each_key do |campo| unless cambios_permitidos.include?(campo) raise "Campo '#{campo}' no es modificable" end end # Validar estado si se está actualizando if cambios[:estado] && !Validator.validar_estado(cambios[:estado]) raise "Estado '#{cambios[:estado]}' no válido" end # Crear backup crear_backup('actualizar_hito') # Leer contenido actual contenido = leer_dashboard # Actualizar hito en el contenido nuevo_estado = cambios[:estado] || hito_existente[:estado] nueva_fecha = cambios[:fecha] || Time.now.strftime('%Y-%m-%d') nuevo_contenido, encontrado = actualizar_hito_en_contenido( contenido, id_hito, nuevo_estado, nueva_fecha ) unless encontrado raise "No se pudo encontrar el hito #{id_hito} para actualizar" end # Guardar cambios guardar_dashboard(nuevo_contenido) # Actualizar cache @hitos_cache = nil cargar_hitos(true) puts "✅ Hito #{id_hito} actualizado exitosamente" true end def eliminar_hito(id_hito) # Verificar que el hito exista unless buscar_hito_por_id(id_hito) raise "Hito #{id_hito} no encontrado" end # Crear backup crear_backup('eliminar_hito') # Leer contenido actual contenido = leer_dashboard # Patrón para encontrar y eliminar el hito específico patron_hito = /