/** * Module Registry - Tipos e interfaces para el sistema modular */ import type { Store } from '@/state/store.ts'; import type { AppState, ViewType, BaseType } from '@/types/index.ts'; // Tipos de renderizado de módulos export type ModuleRenderType = | 'standard' // Grid/Tree/Graph normal (taxonomía, atc) | 'chat' // Interfaz de chat con IA (mail, context) | 'custom'; // Interfaz completamente custom (key, mindlink) // Categorías de módulos para agrupar en UI export type ModuleCategory = | 'taxonomy' // hst, flg, itm, loc, ply | 'masters' // mst, bck | 'registry' // atc, mth | 'communication' // mail, chat | 'services'; // key, mindlink // Configuración de vistas soportadas por módulo export interface ModuleViews { grid?: boolean; tree?: boolean; graph?: boolean; custom?: string; // Nombre del componente custom a usar } // Configuración de API por módulo export interface ModuleApiConfig { schema: string | null; // PostgREST schema (null = public) table: string; // Tabla principal hasLibraries?: boolean; // ¿Soporta bibliotecas? hasGroups?: boolean; // ¿Soporta grupos (set_hst)? hasGraph?: boolean; // ¿Tiene datos de grafo? hasTree?: boolean; // ¿Tiene datos de árbol? } // Configuración completa de un módulo export interface BaseConfig { id: BaseType; name: string; // Nombre completo shortName: string; // Para botón (3-4 chars) category: ModuleCategory; renderType: ModuleRenderType; // Vistas soportadas views: ModuleViews; defaultView: ViewType | 'custom'; // API api: ModuleApiConfig; // Para módulos custom (lazy loading) customModule?: () => Promise<{ default: new (ctx: ModuleContext) => BaseModule }>; // Estado inicial específico del módulo initialState?: Partial; // Módulo habilitado (false = mostrar "Próximamente") enabled?: boolean; } // Estado específico de un módulo export interface ModuleState { loading: boolean; error: string | null; data: unknown; } // Contexto pasado a cada módulo export interface ModuleContext { container: HTMLElement; leftPanel: HTMLElement; groupsBar: HTMLElement; store: Store; config: BaseConfig; showDetail: (mrf: string) => void; } // Clase base abstracta para módulos export abstract class BaseModule { protected ctx: ModuleContext; protected mounted = false; protected unsubscribe: (() => void) | null = null; constructor(ctx: ModuleContext) { this.ctx = ctx; } // Lifecycle abstract mount(): Promise; abstract unmount(): void; abstract render(): void; // Override para carga de datos específica async loadData(): Promise { // Default: no hace nada, subclases implementan } // Override para contenido del sidebar (libraries/options) renderSidebar(): void { // Default: vacío this.ctx.leftPanel.innerHTML = ''; } // Override para barra de grupos renderGroupsBar(): void { // Default: vacío this.ctx.groupsBar.innerHTML = ''; } // Helpers protected getState(): Readonly { return this.ctx.store.getState(); } protected setState(partial: Partial): void { this.ctx.store.setState(partial); } protected getConfig(): BaseConfig { return this.ctx.config; } protected subscribe(listener: (state: AppState) => void): void { this.unsubscribe = this.ctx.store.subscribe(listener); } // Verificar si una vista está soportada protected isViewSupported(view: ViewType): boolean { return !!this.ctx.config.views[view]; } } // Helper para obtener config de módulo export const getModuleConfig = (configs: Record, base: BaseType): BaseConfig => { const config = configs[base]; if (!config) { throw new Error(`Module config not found for base: ${base}`); } return config; }; // Helper para agrupar módulos por categoría export const getModulesByCategory = ( configs: Record ): Record => { const result: Record = { taxonomy: [], masters: [], registry: [], communication: [], services: [] }; Object.values(configs).forEach(config => { result[config.category].push(config); }); return result; }; // Helper para obtener módulos habilitados export const getEnabledModules = ( configs: Record ): BaseConfig[] => { return Object.values(configs).filter(c => c.enabled !== false); };