Configuration Service
Il ConfigService è il servizio centrale per la gestione della configurazione runtime di Tess UI Library. Permette di centralizzare tutte le impostazioni e supporta override tramite environment variables per deployment Docker/Kubernetes.
Panoramica
Caratteristiche
- ✅ Configurazione Centralizzata: Tutte le impostazioni in un unico punto
- ✅ Environment Override: Supporto per variabili d'ambiente runtime
- ✅ Type-Safe: Full TypeScript con interfacce
- ✅ Injection Tokens: DI-based per massima flessibilità
- ✅ Default Sensibili: Configurazione di default out-of-the-box
- ✅ Granulare: Override selettivo di singole impostazioni
Configurazione
UiFusionConfig Interface
interface UiFusionConfig {
uiKit: 'primeng' | 'bootstrap';
theme?: ThemeTokens;
i18n?: I18nConfig;
storage?: StorageConfig;
logging?: LoggingConfig;
table?: TableConfig;
}
Sub-Configurations
ThemeTokens
interface ThemeTokens {
palette?: {
primary?: string;
secondary?: string;
success?: string;
warning?: string;
danger?: string;
info?: string;
light?: string;
dark?: string;
};
radius?: {
sm?: string;
md?: string;
lg?: string;
};
spacing?: {
xs?: string;
sm?: string;
md?: string;
lg?: string;
xl?: string;
};
typography?: {
fontFamily?: string;
fontSize?: {
xs?: string;
sm?: string;
md?: string;
lg?: string;
xl?: string;
};
};
}
I18nConfig
interface I18nConfig {
locale: 'it-IT' | 'en-US';
messages?: Record<string, string>;
}
StorageConfig
interface StorageConfig {
prefix?: string; // Prefisso chiavi storage
ttlDefaultMs?: number; // TTL default (ms)
driverPriority?: ('indexeddb' | 'local' | 'session')[];
}
LoggingConfig
interface LoggingConfig {
level: 'trace' | 'debug' | 'info' | 'warn' | 'error';
provider?: any; // LoggerProvider interface
}
TableConfig
interface TableConfig {
pageSizeDefault?: number;
export?: {
csv?: boolean;
xlsx?: boolean;
json?: boolean;
};
}
Setup
Configurazione Base
import { ApplicationConfig } from '@angular/core';
import { provideTessUiLibrary } from 'tess-ui-library';
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({
uiKit: 'primeng',
i18n: {
locale: 'it-IT',
},
storage: {
prefix: 'my-app',
ttlDefaultMs: 3600000, // 1 ora
},
logging: {
level: 'info',
},
table: {
pageSizeDefault: 20,
export: {
csv: true,
xlsx: true,
json: false,
},
},
}),
],
};
Configurazione con Injection Tokens
Per controllo più granulare, usa i token specifici:
import {
UI_FUSION_CONFIG,
UI_KIT,
THEME_CONFIG,
I18N_CONFIG,
STORAGE_CONFIG,
LOGGING_CONFIG,
TABLE_CONFIG,
} from 'tess-ui-library/config';
export const appConfig: ApplicationConfig = {
providers: [
// UI Kit
{ provide: UI_KIT, useValue: 'primeng' },
// Theme personalizzato
{
provide: THEME_CONFIG,
useValue: {
palette: {
primary: '#2196F3',
secondary: '#FF9800',
},
radius: {
md: '8px',
},
},
},
// i18n
{
provide: I18N_CONFIG,
useValue: {
locale: 'it-IT',
messages: {
'common.save': 'Salva',
'common.cancel': 'Annulla',
},
},
},
// Storage
{
provide: STORAGE_CONFIG,
useValue: {
prefix: 'my-app',
driverPriority: ['indexeddb', 'local'],
},
},
// Logging
{
provide: LOGGING_CONFIG,
useValue: {
level: 'debug',
},
},
// Table
{
provide: TABLE_CONFIG,
useValue: {
pageSizeDefault: 25,
export: {
csv: true,
xlsx: true,
json: true,
},
},
},
],
};
Utilizzo nel Codice
Iniettare ConfigService
import { Component, inject } from '@angular/core';
import { ConfigService } from 'tess-ui-library/config';
@Component({
selector: 'app-my-component',
template: `
<div>
<p>UI Kit: {{ config.getUiKit() }}</p>
<p>Locale: {{ config.getI18n()?.locale }}</p>
<p>Log Level: {{ config.getLogging()?.level }}</p>
</div>
`,
})
export class MyComponent {
config = inject(ConfigService);
}
Accedere alle Configurazioni
export class MyService {
private config = inject(ConfigService);
init(): void {
// Ottieni configurazione completa
const fullConfig = this.config.getConfig();
console.log('Full config:', fullConfig);
// Ottieni singole configurazioni
const uiKit = this.config.getUiKit();
const theme = this.config.getTheme();
const i18n = this.config.getI18n();
const storage = this.config.getStorage();
const logging = this.config.getLogging();
const table = this.config.getTable();
// Usa configurazioni
if (uiKit === 'primeng') {
this.setupPrimeNG();
}
if (logging.level === 'debug') {
console.debug('Debug mode enabled');
}
}
}
Esempio Completo
import { Component, OnInit, inject } from '@angular/core';
import { ConfigService } from 'tess-ui-library/config';
import { LoggerService } from 'tess-ui-library/logging';
@Component({
selector: 'app-settings',
template: `
<div class="settings-panel">
<h2>Configurazione Applicazione</h2>
<div class="setting-group">
<h3>UI Kit</h3>
<p>{{ config.getUiKit() }}</p>
</div>
<div class="setting-group">
<h3>Internazionalizzazione</h3>
<p>Locale: {{ i18n?.locale }}</p>
</div>
<div class="setting-group">
<h3>Storage</h3>
<p>Prefix: {{ storage?.prefix }}</p>
<p>TTL: {{ storage?.ttlDefaultMs }}ms</p>
<p>Driver Priority: {{ storage?.driverPriority?.join(', ') }}</p>
</div>
<div class="setting-group">
<h3>Logging</h3>
<p>Level: {{ logging?.level }}</p>
</div>
<div class="setting-group">
<h3>DataTable</h3>
<p>Default Page Size: {{ table?.pageSizeDefault }}</p>
<p>Export CSV: {{ table?.export?.csv }}</p>
<p>Export XLSX: {{ table?.export?.xlsx }}</p>
<p>Export JSON: {{ table?.export?.json }}</p>
</div>
<tess-button
label="Test Configuration"
(clicked)="testConfig()">
</tess-button>
</div>
`,
})
export class SettingsComponent implements OnInit {
config = inject(ConfigService);
logger = inject(LoggerService);
i18n = this.config.getI18n();
storage = this.config.getStorage();
logging = this.config.getLogging();
table = this.config.getTable();
ngOnInit(): void {
this.logger.info('Settings loaded', {
config: this.config.getConfig(),
});
}
testConfig(): void {
const config = this.config.getConfig();
this.logger.debug('Full configuration:', config);
// Test theme
const theme = this.config.getTheme();
if (theme?.palette?.primary) {
this.logger.info('Primary color:', theme.palette.primary);
}
}
}
Environment Variables Override
Il ConfigService supporta override runtime tramite variabili d'ambiente:
Docker Setup
// config.service.ts implementa automaticamente:
private applyEnvironmentOverrides(): void {
if (typeof window !== 'undefined' && (window as any).ENV) {
const env = (window as any).ENV;
// Override UI Kit
if (env.UI_KIT) {
this.config.uiKit = env.UI_KIT;
}
// Override locale
if (env.LOCALE) {
this.config.i18n = {
...this.config.i18n,
locale: env.LOCALE,
};
}
// Override log level
if (env.LOG_LEVEL) {
this.config.logging = {
...this.config.logging,
level: env.LOG_LEVEL,
};
}
// Override storage prefix
if (env.STORAGE_PREFIX) {
this.config.storage = {
...this.config.storage,
prefix: env.STORAGE_PREFIX,
};
}
}
}
Inject Config at Runtime
# docker/inject-config.sh
#!/bin/sh
cat > /usr/share/nginx/html/assets/config.js << EOF
window.ENV = {
UI_KIT: "${UI_KIT:-primeng}",
LOCALE: "${LOCALE:-it-IT}",
LOG_LEVEL: "${LOG_LEVEL:-info}",
STORAGE_PREFIX: "${STORAGE_PREFIX:-tess-ui}",
API_BASE_URL: "${API_BASE_URL}",
};
EOF
index.html
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="utf-8">
<title>My App</title>
<base href="/">
<!-- Load runtime config BEFORE Angular -->
<script src="assets/config.js"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
Kubernetes ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
UI_KIT: "primeng"
LOCALE: "it-IT"
LOG_LEVEL: "debug"
STORAGE_PREFIX: "prod-app"
API_BASE_URL: "https://api.production.com"
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: my-app:latest
envFrom:
- configMapRef:
name: app-config
Default Configuration
Se non fornisci configurazione, vengono usati questi default:
const DEFAULT_UI_FUSION_CONFIG: UiFusionConfig = {
uiKit: 'primeng',
i18n: {
locale: 'it-IT',
},
storage: {
prefix: 'tess-ui',
ttlDefaultMs: 3600000, // 1 hour
driverPriority: ['indexeddb', 'local', 'session'],
},
logging: {
level: 'info',
},
table: {
pageSizeDefault: 10,
export: {
csv: true,
xlsx: true,
json: true,
},
},
};
Configurazione per Ambiente
Development
// app.config.ts
import { isDevMode } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({
uiKit: 'primeng',
logging: {
level: isDevMode() ? 'debug' : 'info',
},
storage: {
prefix: isDevMode() ? 'dev-app' : 'prod-app',
},
}),
],
};
Staging
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({
uiKit: 'primeng',
logging: {
level: 'debug', // Più logging in staging
},
storage: {
prefix: 'staging-app',
},
}),
],
};
Production
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({
uiKit: 'primeng',
logging: {
level: 'warn', // Solo warning/error in prod
},
storage: {
prefix: 'prod-app',
ttlDefaultMs: 86400000, // 24 ore in prod
},
table: {
pageSizeDefault: 50, // Più risultati in prod
},
}),
],
};
Validazione Configurazione
Puoi validare la configurazione all'avvio:
import { APP_INITIALIZER } from '@angular/core';
import { ConfigService } from 'tess-ui-library/config';
function validateConfig(config: ConfigService): () => void {
return () => {
const cfg = config.getConfig();
// Valida UI Kit
if (!['primeng', 'bootstrap'].includes(cfg.uiKit)) {
throw new Error(`Invalid UI Kit: ${cfg.uiKit}`);
}
// Valida log level
const validLevels = ['trace', 'debug', 'info', 'warn', 'error'];
if (cfg.logging && !validLevels.includes(cfg.logging.level)) {
throw new Error(`Invalid log level: ${cfg.logging.level}`);
}
console.log('✅ Configuration validated successfully');
};
}
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({ uiKit: 'primeng' }),
{
provide: APP_INITIALIZER,
useFactory: validateConfig,
deps: [ConfigService],
multi: true,
},
],
};
Best Practices
- Centralizza configurazione: Una sola fonte di verità per tutte le impostazioni
- Environment variables: Usa per configurazione runtime (Docker/K8s)
- Type-safety: Sfrutta TypeScript per type-checking
- Defaults sensibili: Fornisci default ragionevoli
- Validazione: Valida configurazione all'avvio app
- Documenta: Documenta ogni opzione configurabile
- Granularità: Permetti override selettivo via injection tokens
Troubleshooting
Configurazione non applicata
// ❌ SBAGLIATO - Order matters!
export const appConfig: ApplicationConfig = {
providers: [
{ provide: UI_KIT, useValue: 'bootstrap' },
provideTessUiLibrary({ uiKit: 'primeng' }), // Sovrascrive!
],
};
// ✅ CORRETTO
export const appConfig: ApplicationConfig = {
providers: [
provideTessUiLibrary({ uiKit: 'primeng' }),
{ provide: UI_KIT, useValue: 'bootstrap' }, // Override finale
],
};
Environment variables non funzionano
<!-- Assicurati che config.js sia caricato PRIMA di Angular -->
<script src="assets/config.js"></script>
<!-- POI carica Angular -->
<script src="main.js"></script>
Config immutabile
// ConfigService ritorna config frozen (immutabile)
const config = this.configService.getConfig();
config.uiKit = 'bootstrap'; // ❌ ERRORE: Cannot assign to read only property