- apps/captain-mobile: Mobile API service - apps/flow-ui: Flow UI application - apps/mindlink: Mindlink application - apps/storage: Storage API and workers - apps/tzzr-cli: TZZR CLI tool - deck-frontend/backups: Historical TypeScript versions - hst-frontend: Standalone HST frontend Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
171 lines
4.5 KiB
TypeScript
171 lines
4.5 KiB
TypeScript
/**
|
|
* 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<ModuleState>;
|
|
|
|
// 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<AppState>;
|
|
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<void>;
|
|
abstract unmount(): void;
|
|
abstract render(): void;
|
|
|
|
// Override para carga de datos específica
|
|
async loadData(): Promise<void> {
|
|
// 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<AppState> {
|
|
return this.ctx.store.getState();
|
|
}
|
|
|
|
protected setState(partial: Partial<AppState>): 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<BaseType, BaseConfig>, 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<BaseType, BaseConfig>
|
|
): Record<ModuleCategory, BaseConfig[]> => {
|
|
const result: Record<ModuleCategory, BaseConfig[]> = {
|
|
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<BaseType, BaseConfig>
|
|
): BaseConfig[] => {
|
|
return Object.values(configs).filter(c => c.enabled !== false);
|
|
};
|