feat(web): maestros de clientes, proveedores y artículos (lista, formulario con pestañas, extensiones por cliente)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-16 10:24:39 -05:00
1 parent b759c7bce7
commit 9f003ee4bf
30 files changed
+1553 -23

No files matched your search

@@ -0,0 +1,26 @@
import { ARTICULOS_SCREENS } from './articulos/articulos.screens';
import { ARTICULOS_EXTENSIONS } from './articulos/articulos.extensions';
import { type MasterExtensions, applyMasterExtensions } from './master-extensions';
import { SOCIOS_EXTENSIONS } from './socios-negocio/socios.extensions';
import { SOCIOS_SCREENS } from './socios-negocio/socios.screens';
import type { MasterScreen } from './master-types';
/** Las pantallas de maestros del proyecto base, agrupadas por módulo (una carpeta cada uno). */
export const BASE_MASTER_SCREENS: readonly MasterScreen[] = [...SOCIOS_SCREENS, ...ARTICULOS_SCREENS];
/** Cada módulo solo puede extender sus propias pantallas: una ruta ajena es un error, no un descuido silencioso. */
function ownedBy(screens: readonly MasterScreen[], extensions: MasterExtensions): MasterExtensions {
for (const path of Object.keys(extensions)) {
if (!screens.some((s) => s.path === path)) throw new Error(`Extensión con la ruta «${path}», que es de otro módulo`);
}
return extensions;
}
/** Lo que el cliente agrega, reunido de los archivos de extensiones de cada módulo. */
export const MASTER_EXTENSIONS: MasterExtensions = {
...ownedBy(SOCIOS_SCREENS, SOCIOS_EXTENSIONS),
...ownedBy(ARTICULOS_SCREENS, ARTICULOS_EXTENSIONS),
};
/** Las pantallas con lo que cada cliente agrega (en `main`, igual al base). */
export const MASTER_SCREENS: readonly MasterScreen[] = applyMasterExtensions(BASE_MASTER_SCREENS, MASTER_EXTENSIONS);