Volver a la wiki

Help Widget — Atajos FAQ, búsqueda local y whitelist product (I4)

Help Widget — Atajos FAQ, búsqueda local y whitelist product (I4)

Iniciativa I4 del plan post-audit Supercontexto (sesión 27, tag supercontext/sesion-27-i4-done). Completa el refactor del Help Widget contextual de CreaRack Pro añadiendo tres capacidades: atajos rápidos (FAQ chips), búsqueda local de títulos cliente-side, y filtrado por producto mediante whitelist server-side.


Contexto y motivación

El Help Widget existente sólo ofrecía el modo “Ask” (IA) y el Browse por categorías. Problemas detectados en el audit Supercontexto:


Cambios implementados

1. Atajos rápidos (FAQ chips)

Archivo: static/js/alpine-components.js — componente helpWidget

Se añade el array faqs[] con 7 accesos directos preseleccionados:

LabelSlug
Primeros pasoscrearack/conceptos/primeros-pasos
Map Editorcrearack/blueprints/que-es-map-editor
Terminal SSHcrearack/terminal/que-es-terminal
Observatorycrearack/monitoring/que-es-observatory
Wirelesscrearack/monitoring/que-es-wireless
UPScrearack/monitoring/que-es-ups
Digital Signagecrearack/signage/que-es-signage

Flujo openFaq(slug):

  1. Si total === 0, carga el catálogo wiki (loadWiki()).
  2. Busca el artículo por slug dentro de categories.
  3. Si encontrado y tiene path → abre el artículo inline (openArticle(path)). Latencia 0, coste 0.
  4. Fallback: si el slug aún no está indexado en D1, cambia a tab “buscar” y lanza this.ask() con el label del FAQ como pregunta.

Los chips sólo se muestran cuando no hay categoría activa, no hay artículo abierto y no hay texto en el buscador (showFaqs getter).

CSP-safe: el handler global openHelpFaq(el) en base.js despacha el evento help-open-faq al componente Alpine, evitando onclick inline prohibidos por la Content Security Policy.

// base.js
function openHelpFaq(el) {
    var slug = el && el.dataset ? el.dataset.slug : '';
    if (slug) window.dispatchEvent(new CustomEvent('help-open-faq', { detail: { slug: slug } }));
}
<!-- base.html — Alpine listener -->
@help-open-faq.window="openFaq($event.detail.slug)"

2. Búsqueda local de títulos (cliente-side)

Archivos: alpine-components.js, templates/base.html, help.css

Comportamiento UI:

Sin latencia ni coste: el filtrado opera sobre el catálogo ya cargado en memoria del navegador.

3. Whitelist por producto (server-side)

Archivo: core/api_help.py

Antes: filtrado por blacklist de categorías (_PRIVATE_CATEGORIES = {"workspace"}), eliminando categorías completas del response.

Después: whitelist por product:

_USER_FACING_PRODUCT = "crearack"

# En help_wiki():
resp = requests.get(
    f"{WORKSPACE_URL}/biblioteca/wiki",
    headers=_workspace_headers(),
    params={"product": _USER_FACING_PRODUCT},  # ← nuevo
    timeout=TIMEOUT,
)

El workspace filtra server-side: sólo devuelve pages con product == "crearack". Pages con product = workspace-tech, product = crearack-tech o sin product quedan excluidas del Help de usuario.

Companion changes en workspace (commit 96d5238):

4. UI más limpia en respuestas de IA

// Antes
get answerMeta() { return ... + ' sources · ' + (this.answer.duration_ms || 0) + 'ms'; }
// Después
get answerMeta() { return ... + ' sources'; }

Se elimina la latencia (duration_ms) del texto visible al usuario. Sólo se muestra el número de fuentes consultadas.


Arquitectura de componentes

base.html (template)
  └─ Alpine helpWidget (alpine-components.js)
       ├─ faqs[]              → FAQ chips (openFaq)
       ├─ search              → estado búsqueda local
       ├─ filteredCategoryList → getter computed
       └─ openFaq(slug)       → resolve path o fallback ask

base.js (global handlers)
  └─ openHelpFaq(el)         → dispara CustomEvent 'help-open-faq'

core/api_help.py
  └─ GET /api/help/wiki      → proxy con ?product=crearack
       └─ workspace /biblioteca/wiki?product=crearack (CF Workers D1)

Trade-offs y deuda técnica

ItemEstado
Whitelist depende de product correctamente etiquetado en corpus⚠️ Deuda — parte de I5
Re-tagging masivo de pages sin productPendiente en I5
Fallback FAQ → modo Ask si slug no indexadoFuncional pero subóptimo hasta que D1 tenga cobertura completa

Clases CSS añadidas

ClaseUso
.help-faqsContenedor de la sección FAQ chips
.help-faqs-gridGrid flex-wrap para los chips
.help-faqChip individual (pill border-radius 999px)
.help-search-wrapWrapper del input de búsqueda
.help-search-inputInput text de búsqueda
.help-search-clearBotón × para limpiar búsqueda
.help-search-resultsContenedor de resultados en búsqueda activa
.help-search-group-labelLabel de categoría en resultados (Oswald, uppercase)

Véase también

Subir