@esfaenza/dpe-builder 20.3.2 → 20.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/esfaenza-dpe-builder.mjs +172 -65
- package/fesm2022/esfaenza-dpe-builder.mjs.map +1 -1
- package/index.d.ts +1 -1
- package/package.json +1 -1
- package/styles/dpe-builder.css +1760 -22
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"esfaenza-dpe-builder.mjs","sources":["../../../projects/dpe-builder/src/lib/api/dpe-api-error.ts","../../../projects/dpe-builder/src/lib/api/dpe-builder-api.ts","../../../projects/dpe-builder/src/lib/api/http-dpe-builder-api.ts","../../../projects/dpe-builder/src/lib/model/dpe-definition.model.ts","../../../projects/dpe-builder/src/lib/model/dpe-diagnostics.model.ts","../../../projects/dpe-builder/src/lib/model/dpe-api.model.ts","../../../projects/dpe-builder/src/lib/core/dpe-capabilities.ts","../../../projects/dpe-builder/src/lib/core/dpe-graph.ts","../../../projects/dpe-builder/src/lib/core/dpe-diagnostics.util.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-layout.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-catalog.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-factory.ts","../../../projects/dpe-builder/src/lib/core/dpe-document.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-catalog.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-layout.service.ts","../../../projects/dpe-builder/src/lib/core/dpe-metadata.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-icons.ts","../../../projects/dpe-builder/src/lib/core/dpe-validation.service.ts","../../../projects/dpe-builder/src/lib/core/dpe-viewport.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-node-icon.component.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.model.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.component.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.component.html","../../../projects/dpe-builder/src/lib/ui/diagnostics/dpe-diagnostics-panel.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-select-value.directive.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-node-inspector-base.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-aggregate-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-append-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-atomic-writeback-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-column-type-editor.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-custom-node-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-data-source-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-filter-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-forecast-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-hierarchy-path-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-join-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-expression-editor.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-transform-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-writeback-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-node-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/palette/dpe-node-palette.component.ts","../../../projects/dpe-builder/src/lib/ui/preview/dpe-sql-preview.component.ts","../../../projects/dpe-builder/src/lib/ui/schema/dpe-schema-panel.component.ts","../../../projects/dpe-builder/src/lib/ui/dpe-builder.component.ts","../../../projects/dpe-builder/src/lib/ui/dpe-builder.component.html","../../../projects/dpe-builder/src/lib/ui/catalog/dpe-catalog.component.ts","../../../projects/dpe-builder/src/lib/ui/catalog/dpe-catalog.component.html","../../../projects/dpe-builder/src/public-api.ts","../../../projects/dpe-builder/src/esfaenza-dpe-builder.ts"],"sourcesContent":["/**\r\n * Errore categorizzato del contratto verso il backend.\r\n *\r\n * L'editor si comporta in base alla **categoria**, mai leggendo il messaggio: chi implementa\r\n * {@link DpeBuilderApi} traduce l'errore di trasporto (status HTTP, payload, timeout) in un\r\n * `DpeApiError`, e da lì in poi nella libreria non esiste piu' nessuna nozione di HTTP\r\n * (ADR 0007).\r\n */\r\n\r\n/**\r\n * Le categorie sono **tre** e chiuse, perche' sono tre comportamenti diversi della UI:\r\n *\r\n * - `MissingService`: la primitiva non e' implementata su questo ambiente. Degrada il\r\n * **singolo comando** (l'anteprima SQL si disabilita), non l'editor;\r\n * - `Transport`: la chiamata non e' arrivata o non e' tornata. Si puo' ritentare;\r\n * - `Backend`: il backend ha risposto rifiutando. Non si ritenta da soli.\r\n *\r\n * Un errore di validazione **non e'** una categoria: le diagnostiche sono un *risultato*\r\n * (`DpeValidateResult.diagnostics`), non un fallimento — e' la stessa regola del backend,\r\n * dove il fallimento previsto e' un risultato e non un'eccezione.\r\n */\r\nexport type DpeApiErrorCategory = 'MissingService' | 'Transport' | 'Backend';\r\n\r\nexport class DpeApiError extends Error {\r\n constructor(\r\n readonly category: DpeApiErrorCategory,\r\n message: string,\r\n /** Payload di dettaglio dell'host, opaco per la libreria. */\r\n readonly details?: unknown,\r\n ) {\r\n super(message);\r\n this.name = 'DpeApiError';\r\n }\r\n\r\n static is(value: unknown): value is DpeApiError {\r\n return value instanceof DpeApiError;\r\n }\r\n\r\n /** Vero quando il comando corrispondente va disabilitato invece che segnalato. */\r\n static isMissingService(value: unknown): boolean {\r\n return DpeApiError.is(value) && value.category === 'MissingService';\r\n }\r\n}\r\n\r\n/** Messaggi di ripiego: il `message` dell'host, quando c'e', ha la precedenza. */\r\nexport const DPE_API_ERROR_FALLBACK_MESSAGE: Record<DpeApiErrorCategory, string> = {\r\n MissingService: 'Funzione non configurata su questo ambiente.',\r\n Transport: 'Il backend non e’ raggiungibile.',\r\n Backend: 'Il backend ha rifiutato la richiesta.',\r\n};\r\n","/**\r\n * L'unica porta verso il backend — `docs/contracts.md` §7.\r\n *\r\n * **Non esiste un documento di endpoint: il contratto e' questa classe astratta** (ADR 0007).\r\n * Fa anche da token di dependency injection: chi integra l'editor fornisce una\r\n * implementazione e la registra come provider di `DpeBuilderApi`.\r\n *\r\n * Due conseguenze da non aggirare:\r\n *\r\n * 1. **questo file non conosce HTTP.** Nessun `HttpClient`, nessun `fetch`, nessun URL qui ne'\r\n * in nessuno store o componente. L'ADR 0020 ha spostato il client HTTP **dentro** la libreria\r\n * (`lib/api/http-dpe-builder-api.ts`), quindi la regola non e' piu' «zero HTTP in\r\n * `projects/dpe-builder`» ma «zero HTTP fuori da quel file»: e' *una* implementazione fra le\r\n * possibili, non la definizione del contratto, che resta questa classe;\r\n * 2. **un dato nuovo dal backend e' un metodo nuovo qui**, mai una chiamata dentro un\r\n * componente.\r\n *\r\n * I metodi con implementazione di default rifiutano con `DpeApiError('MissingService', ...)`:\r\n * un ambiente che non li espone lascia l'editor funzionante con il singolo comando\r\n * disabilitato. Un'anteprima SQL non disponibile disabilita l'anteprima, non l'editor.\r\n *\r\n * I metodi restituiscono `Observable` perche' l'I/O del frontend e' asincrono per natura. Il\r\n * vincolo di sincronia della libreria C# riguarda il backend: qui si traduce solo nel fatto\r\n * che una chiamata occupa il chiamante finche' non termina, quindi chi la invoca mostra\r\n * l'attesa e non incatena una validazione a ogni battitura senza debounce.\r\n */\r\n\r\nimport { Observable, throwError } from 'rxjs';\r\n\r\nimport { DpeDefinition } from '../model/dpe-definition.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeDefinitionSummary,\r\n DpeEnvironment,\r\n DpeParameterValue,\r\n DpeValidateResult,\r\n TableLookupResult,\r\n TableSummary,\r\n} from '../model/dpe-api.model';\r\nimport { DpeApiError } from './dpe-api-error';\r\n// Import di **solo tipo**: `core/dpe-capabilities` importa questa classe, e senza `import type`\r\n// il ciclo sarebbe reale a runtime. Il tipo si cancella in compilazione, il ciclo no.\r\nimport type { DpeOptionalPrimitive } from '../core/dpe-capabilities';\r\n\r\n/** Ripiego dei metodi opzionali non implementati dall'host. */\r\nfunction missing(primitive: string): Observable<never> {\r\n return throwError(\r\n () => new DpeApiError('MissingService', `Primitiva non disponibile su questo ambiente: ${primitive}.`),\r\n );\r\n}\r\n\r\nexport abstract class DpeBuilderApi {\r\n /**\r\n * Primitive opzionali che **questo ambiente non serve**, dichiarate dall'ospite (ADR 0020,\r\n * `contracts.md` §7).\r\n *\r\n * Perche' esiste, dato che la rilevazione per identita' del metodo bastava: da quando la\r\n * libreria spedisce un client HTTP che implementa **tutte** le primitive\r\n * (`HttpDpeBuilderApi`), chi lo eredita non ha modo di *dis*-sovrascrivere un metodo. Si\r\n * ritroverebbe comandi attivi su endpoint che il suo backend non serve — esattamente il\r\n * difetto che la regola dell'identita' esisteva per prevenire.\r\n *\r\n * E' **solo sottrattiva**: non rende disponibile cio' che non e' implementato, e il tipo\r\n * `DpeOptionalPrimitive` le impedisce di nominare le tre primitive obbligatorie. Vuoto per\r\n * default, cosi' un'implementazione che non la tocca conserva esattamente il comportamento\r\n * di prima.\r\n *\r\n * Chi la usa deve anche rigettare la primitiva con `DpeApiError('MissingService', ...)`\r\n * **senza emettere la richiesta**: sapere in anticipo che un servizio non c'e' e chiederglielo\r\n * comunque e' il difetto che questa dichiarazione evita.\r\n */\r\n readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[] = [];\r\n\r\n /**\r\n * `IDpeService.Validate` — **non produce SQL e non legge dati** (`contracts.md` §5). E' la\r\n * primitiva del feedback durante l'editing: diagnostiche, schemi di ogni nodo, ordine di\r\n * esecuzione e sequenza dei writeback in una sola risposta.\r\n *\r\n * Prende la definizione **in lavorazione**, non quella salvata: cio' che l'editor mostra\r\n * deve riferirsi a cio' che l'utente sta scrivendo. Va invocata con debounce.\r\n */\r\n abstract validate(definition: DpeDefinition): Observable<DpeValidateResult>;\r\n\r\n /**\r\n * `IDpeService.GetTables` — passaggio diretto al provider di metadati dell'host, **non ai\r\n * cataloghi del database** (`contracts.md` §2). L'elenco puo' essere grande: chi lo consuma\r\n * carica in modo asincrono e filtra, non lo riversa in un `<select>`.\r\n */\r\n abstract getTables(): Observable<TableSummary[]>;\r\n\r\n /**\r\n * `IDpeService.GetTable` — i **tre** esiti dell'ADR 0004 restano distinti fino alla UI:\r\n * `Declared`, `DeclaredWithoutFields` (\"la tabella c'e', i campi non li so\") e `Unknown`.\r\n * Appiattirli e' esattamente cio' che il contratto vieta.\r\n */\r\n abstract getTable(tableName: string): Observable<TableLookupResult>;\r\n\r\n /**\r\n * `IDpeService.Compile` — l'anteprima dell'SQL generato, in sola lettura.\r\n *\r\n * Opzionale: senza di essa il comando di anteprima si disabilita e il resto dell'editor\r\n * continua a funzionare.\r\n *\r\n * `parameterValues` e' opzionale e corrisponde a `DpeCompileRequest.ParameterValues`.\r\n * Ometterlo e' un comportamento **dichiarato**, non un ripiego: l'anteprima usa allora i\r\n * `defaultValue` dei parametri. Passarli serve perche' senza di essi l'anteprima resterebbe\r\n * muta proprio sui parametri **privi** di default, cioe' quelli che l'utente vuole provare.\r\n */\r\n compilePreview(\r\n definition: DpeDefinition,\r\n parameterValues?: DpeParameterValue[],\r\n ): Observable<DpeCompileResult> {\r\n void definition;\r\n void parameterValues;\r\n return missing('compilePreview');\r\n }\r\n\r\n /**\r\n * Caricamento di una definizione per nome. Opzionale: dove non c'e', l'editor lavora sulla\r\n * definizione che gli viene passata dall'ospite.\r\n *\r\n * La deserializzazione (`IDpeService.Deserialize`) resta del backend: qui arriva un\r\n * documento già letto, con le sue eventuali diagnostiche già emesse.\r\n */\r\n load(name: string): Observable<DpeDefinition> {\r\n void name;\r\n return missing('load');\r\n }\r\n\r\n /** Salvataggio. Opzionale: un editor in sola lettura e' un uso legittimo. */\r\n save(definition: DpeDefinition): Observable<void> {\r\n void definition;\r\n return missing('save');\r\n }\r\n\r\n /**\r\n * La dichiarazione dell'ambiente (ADR 0017). Oggi porta **solo** il dialetto del database di\r\n * destinazione, che e' un fatto dell'installazione e non una preferenza dell'autore della\r\n * definizione: per questo l'editor non offre nessun comando per cambiarlo.\r\n *\r\n * Cosa l'editor fa con la risposta, e cosa non fa: mostra il dialetto in sola lettura e, se\r\n * differisce da quello della definizione (ADR 0009: e' li' che vive, ed e' da li' che il\r\n * backend lo legge), **lo segnala senza correggere**. Riscrivere `definition.dialect` sarebbe\r\n * una migrazione silenziosa di tutte le espressioni SQL native (ADR 0006), per giunta eseguita\r\n * all'apertura e capace di marcare come «modificata» una definizione che nessuno ha toccato.\r\n *\r\n * Opzionale come le altre: dove manca, l'editor mostra il dialetto della definizione e non\r\n * dice nient'altro.\r\n */\r\n getEnvironment(): Observable<DpeEnvironment> {\r\n return missing('getEnvironment');\r\n }\r\n\r\n /**\r\n * Elenco delle definizioni disponibili — **catalogo** (ADR 0019). Opzionale: dove manca, un\r\n * catalogo montato dall'ospite mostra il perche' invece di un elenco vuoto.\r\n *\r\n * **Nessun oggetto di interrogazione**, di proposito: niente ricerca, niente paginazione. Il\r\n * filtro di testo del catalogo e' locale sui sommari ricevuti, e aggiungere una query in\r\n * seguito e' additivo. Un parametro che nessuno esercita e' un parametro che nessuno verifica.\r\n *\r\n * L'ospite e' tenuto a restituire i sommari in un **ordine stabile**: il catalogo non riordina,\r\n * perche' riordinare lato client combatterebbe una scelta che l'ospite ha gia' fatto.\r\n */\r\n listDefinitions(): Observable<DpeDefinitionSummary[]> {\r\n return missing('listDefinitions');\r\n }\r\n\r\n /**\r\n * Creazione di una definizione. Opzionale.\r\n *\r\n * **Restituisce il sommario, non `void`**: l'ospite puo' aver normalizzato il nome, e chi crea\r\n * apre **il nome tornato**, non quello digitato. Il risultato di una scrittura non si crede\r\n * sulla parola.\r\n *\r\n * Distinta da `save` per una ragione di merito: `save(definition)` significa «scrivi questa\r\n * definizione» e non distingue inserimento da aggiornamento, quindi farle significare anche\r\n * «creala» toglierebbe all'ospite l'unico posto in cui puo' **rifiutare un nome duplicato**.\r\n *\r\n * Non esiste una primitiva di duplicazione: duplicare e' `load` piu' `createDefinition`, e il\r\n * comando vive nel catalogo.\r\n */\r\n createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary> {\r\n void definition;\r\n return missing('createDefinition');\r\n }\r\n\r\n /**\r\n * Cancellazione per nome. Opzionale: un catalogo di sola lettura e' un uso legittimo.\r\n *\r\n * Non esiste una primitiva di rinomina: rinominare cambia la chiave, quindi e'\r\n * creare-e-cancellare, cioe' una decisione di storage che e' dell'ospite (ADR 0019).\r\n */\r\n deleteDefinition(name: string): Observable<void> {\r\n void name;\r\n return missing('deleteDefinition');\r\n }\r\n}\r\n","/**\r\n * Implementazione HTTP di {@link DpeBuilderApi}, sulle rotte **normative** di\r\n * `docs/contracts.md` §7-bis.\r\n *\r\n * Vive nella libreria per decisione del committente (ADR 0020, che revisiona la sola clausola\r\n * dell'ADR 0007 sulla collocazione): l'integrazione e' due righe invece che un file da copiare.\r\n * Il prezzo, accettato e scritto: **le rotte sono contratto pubblico**, e cambiarne una e' un\r\n * breaking change. Da qui in poi questa classe non e' «un esempio» — una classe esportata da una\r\n * libreria viene usata in produzione a prescindere da come la chiamiamo nel commento, e chiamarla\r\n * esempio servirebbe solo a esentarla dai test.\r\n *\r\n * Resta vero cio' che conta dell'ADR 0007: **il contratto e' la classe astratta**, non questo\r\n * client. Nessun componente e nessuno store della libreria lo importa. Chi ha rotte diverse ha due\r\n * strade, e nessuna tocca l'editor:\r\n *\r\n * 1. **estendere questa classe** e sovrascrivere i soli metodi divergenti. I punti di estensione\r\n * sono `protected` di proposito: `url()` per il prefisso e la forma del percorso, `segment()`\r\n * per la codifica, i quattro verbi per il trasporto, `fail()` per la traduzione degli errori,\r\n * `request()` per cio' che avvolge ogni chiamata;\r\n * 2. **scrivere un'altra implementazione di `DpeBuilderApi` da zero** — legittima e supportata.\r\n *\r\n * Le tre cose che chi legge questo file deve sapere, e che nessun compilatore gli dira':\r\n *\r\n * 1. **il corpo e' il documento nudo** dove il backend analizza o archivia la definizione\r\n * (`validate`, `createDefinition`, `save`). L'unico involucro e' `compilePreview`, perche' li'\r\n * il corpo porta anche i valori dei parametri. Sbagliare involucro **non produce nessun\r\n * errore**: un backend che deserializza una `DpeDefinition` da `{definition: …}` non riconosce\r\n * nessuna proprieta', risponde `200`, e l'editor mostra la validazione di una definizione\r\n * vuota;\r\n * 2. **la serializzazione e' camelCase.** I tipi TypeScript sono allineati a mano ai record C#: un\r\n * backend che risponde in PascalCase non produce nessun errore, produce campi `undefined`;\r\n * 3. **l'errore di trasporto diventa una categoria.** L'editor si comporta in base alla categoria\r\n * e non legge mai il messaggio: `MissingService` disabilita un comando, `Transport` e'\r\n * ritentabile, `Backend` no.\r\n *\r\n * Cosa questo client **non** fa, e non per dimenticanza: nessun `retry`, nessun `shareReplay`,\r\n * nessuna cache, nessun debounce, nessuna intestazione propria. Traduce trasporto ed errori e\r\n * nient'altro — la cache vive negli store, il debounce nel chiamante, i tentativi e\r\n * l'autenticazione negli interceptor dell'ospite. E non tocca `definition.dialect` in nessun\r\n * metodo (ADR 0009 e 0017): sarebbe una migrazione silenziosa delle espressioni SQL native.\r\n */\r\n\r\nimport { HttpClient, HttpErrorResponse } from '@angular/common/http';\r\nimport {\r\n EnvironmentProviders,\r\n InjectionToken,\r\n Injectable,\r\n inject,\r\n makeEnvironmentProviders,\r\n} from '@angular/core';\r\nimport { Observable, catchError, defer, throwError } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from './dpe-builder-api';\r\nimport { DpeApiError, DpeApiErrorCategory } from './dpe-api-error';\r\nimport { DpeDefinition } from '../model/dpe-definition.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeDefinitionSummary,\r\n DpeEnvironment,\r\n DpeParameterValue,\r\n DpeValidateResult,\r\n TableLookupResult,\r\n TableSummary,\r\n} from '../model/dpe-api.model';\r\nimport type { DpeOptionalPrimitive } from '../core/dpe-capabilities';\r\n\r\n/**\r\n * Configurazione del client. Iniettata e non cablata: in una libreria una costante non e' una\r\n * scelta, e `const BASE = '/api/dpe'` in un file di libreria toglierebbe all'ospite la sua.\r\n */\r\nexport interface DpeBuilderHttpConfig {\r\n /** Prefisso comune degli endpoint, es. `/api/dpe` o `https://host/api/dpe`. Senza slash finale. */\r\n baseUrl?: string;\r\n /**\r\n * Primitive opzionali che questo ambiente **non serve** (`contracts.md` §7, dichiarazione\r\n * sottrattiva). E' l'unico modo che ha l'ospite di spegnere una primitiva che questo client\r\n * implementa per forza: conoscendo tutti e dieci gli endpoint, li dichiarerebbe altrimenti tutti\r\n * disponibili, e un comando attivo su un endpoint non servito fallisce alla pressione.\r\n */\r\n unsupported?: readonly DpeOptionalPrimitive[];\r\n}\r\n\r\n/** Base di default delle rotte, in un solo posto: token e funzione di registrazione la condividono. */\r\nconst DPE_BUILDER_DEFAULT_BASE_URL = '/api/dpe';\r\n\r\nexport const DPE_BUILDER_HTTP_CONFIG = new InjectionToken<DpeBuilderHttpConfig>(\r\n 'DPE_BUILDER_HTTP_CONFIG',\r\n { factory: () => ({ baseUrl: DPE_BUILDER_DEFAULT_BASE_URL }) },\r\n);\r\n\r\n@Injectable()\r\nexport class HttpDpeBuilderApi extends DpeBuilderApi {\r\n protected readonly http = inject(HttpClient);\r\n protected readonly config = inject(DPE_BUILDER_HTTP_CONFIG);\r\n\r\n /**\r\n * Deriva da `DpeBuilderHttpConfig.unsupported`: e' il ponte fra la configurazione e la regola\r\n * di `contracts.md` §7. Non e' un doppione della configurazione — e' il campo che\r\n * `core/dpe-capabilities.ts` legge, e leggerlo dal token li' significherebbe portare la\r\n * configurazione HTTP dentro il calcolo delle capacita'.\r\n */\r\n override readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[] =\r\n this.config.unsupported ?? [];\r\n\r\n // --- punti di estensione ---------------------------------------------------\r\n\r\n /**\r\n * Composizione dell'URL. Sovrascriverlo basta a spostare tutte e dieci le rotte sotto un altro\r\n * prefisso senza toccare un metodo.\r\n *\r\n * `?? ''` e non un default: `baseUrl: ''` e' una configurazione **valida** e significa «rotte\r\n * relative alla radice», quindi non va rimpiazzata dal default del token. Il percorso porta\r\n * sempre lo slash iniziale, cosi' non nasce un doppio slash.\r\n */\r\n protected url(path: string): string {\r\n return `${this.config.baseUrl ?? ''}${path}`;\r\n }\r\n\r\n /** Codifica di un segmento variabile. Un nome di definizione puo' contenere `/`, spazi, `&`. */\r\n protected segment(value: string): string {\r\n return encodeURIComponent(value);\r\n }\r\n\r\n /**\r\n * Cio' che avvolge **ogni** chiamata, e l'unico posto in cui si decide se una chiamata parte.\r\n *\r\n * `defer` non e' un vezzo: rende l'`Observable` **freddo** anche per il controllo delle\r\n * primitive non servite, cosi' chi non sottoscrive non valuta nulla e chi si disiscrive annulla\r\n * davvero la richiesta HTTP. E' la proprieta' per cui il contratto §7 e' `Observable` e non\r\n * `Promise` — l'editor la usa per non accumulare validazioni in volo.\r\n *\r\n * Il rigetto per primitiva non servita sta **fuori** dal `catchError`: passandogli dentro, un\r\n * `DpeApiError('MissingService')` verrebbe riclassificato `Transport` da `fail()`, che tratta\r\n * come guasto di rete tutto cio' che non e' una `HttpErrorResponse`.\r\n */\r\n protected request<T>(primitive: DpeOptionalPrimitive | string, call: () => Observable<T>): Observable<T> {\r\n return defer(() => {\r\n if (this.isUnsupported(primitive)) {\r\n return this.missing(primitive);\r\n }\r\n return call().pipe(catchError((error: unknown) => this.fail(error, primitive)));\r\n });\r\n }\r\n\r\n /** Vero se l'ospite ha dichiarato di non servire questa primitiva. */\r\n protected isUnsupported(primitive: string): boolean {\r\n return (this.unsupportedPrimitives as readonly string[]).includes(primitive);\r\n }\r\n\r\n /**\r\n * Rigetto di una primitiva dichiarata non servita, **senza toccare la rete**: sapere in anticipo\r\n * che un servizio non c'e' e chiederglielo comunque e' il difetto che `unsupportedPrimitives`\r\n * esiste per evitare, ed e' il motivo per cui il `501` -> `MissingService` non basta da solo.\r\n */\r\n protected missing(primitive: string): Observable<never> {\r\n return throwError(\r\n () =>\r\n new DpeApiError(\r\n 'MissingService',\r\n `Primitiva non servita da questo ambiente: ${primitive}.`,\r\n ),\r\n );\r\n }\r\n\r\n /**\r\n * `501 Not Implemented` diventa `MissingService`: e' cosi' che un ambiente incompleto degrada\r\n * **un comando** invece di rompere l'editor. Uno `0` (rete assente, CORS) e' `Transport`, come\r\n * qualunque errore che non sia una `HttpErrorResponse`; tutto il resto e' `Backend`.\r\n *\r\n * Il `404` resta deliberatamente `Backend` e non ha un ramo suo: qui non e' «primitiva assente»\r\n * ma «risorsa assente» — una definizione cancellata da altri, un nome che non esiste piu'. Chi\r\n * volesse distinguerlo lo mappi su una categoria propria, non su `MissingService`: disabilitare\r\n * un comando perche' un singolo nome non e' stato trovato sarebbe la reazione sbagliata.\r\n *\r\n * Il messaggio si prende in ordine — corpo dell'errore, messaggio della risposta, ripiego che\r\n * nomina la primitiva — e serve solo all'umano: l'editor guarda la categoria.\r\n */\r\n protected fail(error: unknown, primitive: string): Observable<never> {\r\n const response = error instanceof HttpErrorResponse ? error : undefined;\r\n let category: DpeApiErrorCategory = 'Backend';\r\n if (response?.status === 501) {\r\n category = 'MissingService';\r\n } else if (!response || response.status === 0) {\r\n category = 'Transport';\r\n }\r\n const message =\r\n (response?.error as { message?: string } | undefined)?.message ??\r\n response?.message ??\r\n `Chiamata ${primitive} fallita.`;\r\n return throwError(() => new DpeApiError(category, message, error));\r\n }\r\n\r\n // --- verbi ----------------------------------------------------------------\r\n // Sovrascriverne uno cambia il trasporto di tutte le rotte che lo usano: e' il livello a cui\r\n // agisce chi deve aggiungere `withCredentials` o un `responseType` diverso.\r\n\r\n protected httpGet<T>(path: string): Observable<T> {\r\n return this.http.get<T>(this.url(path));\r\n }\r\n\r\n protected httpPost<T>(path: string, body: unknown): Observable<T> {\r\n return this.http.post<T>(this.url(path), body);\r\n }\r\n\r\n protected httpPut<T>(path: string, body: unknown): Observable<T> {\r\n return this.http.put<T>(this.url(path), body);\r\n }\r\n\r\n protected httpDelete<T>(path: string): Observable<T> {\r\n return this.http.delete<T>(this.url(path));\r\n }\r\n\r\n // --- primitive obbligatorie -----------------------------------------------\r\n\r\n override validate(definition: DpeDefinition): Observable<DpeValidateResult> {\r\n // Il documento va **nudo** nel body: e' la definizione in lavorazione, non un involucro.\r\n return this.request('validate', () =>\r\n this.httpPost<DpeValidateResult>('/validate', definition),\r\n );\r\n }\r\n\r\n override getTables(): Observable<TableSummary[]> {\r\n return this.request('getTables', () => this.httpGet<TableSummary[]>('/tables'));\r\n }\r\n\r\n override getTable(tableName: string): Observable<TableLookupResult> {\r\n return this.request('getTable', () =>\r\n this.httpGet<TableLookupResult>(`/tables/${this.segment(tableName)}`),\r\n );\r\n }\r\n\r\n // --- primitive opzionali --------------------------------------------------\r\n\r\n /** L'**unica** rotta con involucro: il corpo porta anche i valori dei parametri (§7-bis). */\r\n override compilePreview(\r\n definition: DpeDefinition,\r\n parameterValues?: DpeParameterValue[],\r\n ): Observable<DpeCompileResult> {\r\n return this.request('compilePreview', () =>\r\n this.httpPost<DpeCompileResult>('/compile', { definition, parameterValues }),\r\n );\r\n }\r\n\r\n override load(name: string): Observable<DpeDefinition> {\r\n return this.request('load', () =>\r\n this.httpGet<DpeDefinition>(`/definitions/${this.segment(name)}`),\r\n );\r\n }\r\n\r\n override save(definition: DpeDefinition): Observable<void> {\r\n return this.request('save', () =>\r\n this.httpPut<void>(`/definitions/${this.segment(definition.name)}`, definition),\r\n );\r\n }\r\n\r\n /**\r\n * La dichiarazione dell'ambiente (ADR 0017). Questo client la implementa perche' conosce\r\n * l'endpoint, non perche' sappia se l'ospite lo serve — ed e' precisamente la ragione per cui\r\n * l'ADR 0020 ha aggiunto `unsupportedPrimitives`.\r\n *\r\n * Non e' un dettaglio: l'abilitazione della creazione nel catalogo (ADR 0019) dipende da questa\r\n * primitiva, quindi un ambiente che non la serve deve lasciare il comando disabilitato **con il\r\n * motivo**. Da qui i **tre** rami, che sono tre cose diverse e vanno tenute distinte:\r\n *\r\n * - **primitiva non implementata**: il metodo non viene sovrascritto, e il `MissingService` lo\r\n * produce l'identita' stessa del metodo. E' la strada di chi scrive la propria\r\n * implementazione di `DpeBuilderApi`, non di chi eredita questo client;\r\n * - **primitiva implementata ma non servita da questo ambiente**: e' il ramo centrale, quello\r\n * che questo file rende necessario. L'ospite mette `'getEnvironment'` in\r\n * `DpeBuilderHttpConfig.unsupported`, il comando resta disabilitato con il motivo, e **nessuna\r\n * richiesta parte**. Un metodo ereditato non si puo' dis-sovrascrivere: senza questa\r\n * dichiarazione il comando risulterebbe attivo;\r\n * - **primitiva servita che fallisce**: l'endpoint risponde male, e l'errore e' `Transport` o\r\n * `Backend`. Un ambiente rotto, non un ambiente incompleto.\r\n *\r\n * Rispondere `501` da questo endpoint per significare «non lo dichiaro» arriva allo stesso posto\r\n * nel modo sbagliato: costa un giro di rete a ogni apertura dell'editor per comunicare un fatto\r\n * che si conosce a tempo di configurazione.\r\n *\r\n * Cio' che l'editor fa della risposta resta suo: mostra il dialetto in sola lettura e segnala\r\n * senza correggere se differisce da quello della definizione.\r\n */\r\n override getEnvironment(): Observable<DpeEnvironment> {\r\n return this.request('getEnvironment', () => this.httpGet<DpeEnvironment>('/environment'));\r\n }\r\n\r\n // --- catalogo (ADR 0019) --------------------------------------------------\r\n\r\n /** Nessun parametro di interrogazione: il filtro del catalogo e' locale, di proposito. */\r\n override listDefinitions(): Observable<DpeDefinitionSummary[]> {\r\n return this.request('listDefinitions', () =>\r\n this.httpGet<DpeDefinitionSummary[]>('/definitions'),\r\n );\r\n }\r\n\r\n /**\r\n * `POST` e non `PUT`: e' una **creazione**, quindi il backend puo' rifiutare un nome duplicato —\r\n * ed e' l'unica ragione per cui questa primitiva esiste separata da `save`. La risposta e' il\r\n * **sommario**, che chi crea deve adottare: il nome puo' essere stato normalizzato.\r\n */\r\n override createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary> {\r\n return this.request('createDefinition', () =>\r\n this.httpPost<DpeDefinitionSummary>('/definitions', definition),\r\n );\r\n }\r\n\r\n override deleteDefinition(name: string): Observable<void> {\r\n return this.request('deleteDefinition', () =>\r\n this.httpDelete<void>(`/definitions/${this.segment(name)}`),\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Registra il client e la sua configurazione: l'integrazione in una riga che l'ADR 0020 chiedeva.\r\n *\r\n * **Non** chiama `provideHttpClient()`, e non e' una dimenticanza: il backend (`withFetch`), gli\r\n * interceptor, l'autenticazione e i cookie sono scelte dell'applicazione ospite, e una libreria\r\n * che le prende al posto suo la costringe a disfarle.\r\n *\r\n * `baseUrl` omesso ricade sul default, `baseUrl: ''` **no**: la stringa vuota e' una\r\n * configurazione valida («rotte relative alla radice») e un `||` la scambierebbe per assente.\r\n */\r\nexport function provideDpeBuilderHttpApi(config?: DpeBuilderHttpConfig): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n {\r\n provide: DPE_BUILDER_HTTP_CONFIG,\r\n useValue: {\r\n baseUrl: config?.baseUrl ?? DPE_BUILDER_DEFAULT_BASE_URL,\r\n unsupported: config?.unsupported ?? [],\r\n } satisfies DpeBuilderHttpConfig,\r\n },\r\n { provide: DpeBuilderApi, useClass: HttpDpeBuilderApi },\r\n ]);\r\n}\r\n","/**\r\n * Modello della definizione DPE — traduzione **letterale** dei record C# di\r\n * `docs/domain-model.md`.\r\n *\r\n * Questi tipi sono allineati **a mano** ai record di `Jace.DPE.Model` (ADR 0007: nessun\r\n * generatore di tipi, nessuno JSON Schema). Sono due modelli in due linguaggi e il\r\n * compilatore non dira' mai quando divergono: la fonte di verita' e' `docs/contracts.md` +\r\n * `docs/domain-model.md`, e chi cambia un record C# aggiorna questo file nello stesso\r\n * momento.\r\n *\r\n * Convenzioni, tutte conseguenza del contratto:\r\n *\r\n * - proprieta' in **camelCase**, perche' il JSON prodotto dal backend e' camelCase\r\n * (`domain-model.md`, convenzioni generali);\r\n * - gli enum C# diventano **unioni di stringhe letterali** con i nomi esatti dei valori: un\r\n * `enum` TypeScript non e' assegnabile da una stringa arrivata dalla rete, e un valore\r\n * numerico non e' cio' che il backend serializza;\r\n * - le collezioni nel backend non sono mai nulle, ma il JSON le **omette quando vuote**\r\n * (ADR 0003): qui sono opzionali e chi legge non presume che esistano;\r\n * - `extensionData` esiste su **ogni** record (**I7**): sono proprieta' JSON non riconosciute,\r\n * con valori **opachi**. L'editor le trasporta senza interpretarle.\r\n *\r\n * Nessuna regola di dominio vive qui: obbligatorieta' condizionali, unicita' dei nomi e\r\n * compatibilita' dei tipi sono del backend. Le note `condiz.` nei commenti sono descrittive\r\n * e servono a chi costruira' gli ispettori, non sono validazione.\r\n */\r\n\r\n/** Proprieta' JSON non riconosciute, conservate verbatim (**I7**). Valori opachi. */\r\nexport type DpeExtensionData = Record<string, unknown>;\r\n\r\n/** Base di ogni record del modello: `ExtensionData` sta su tutti, non solo sulla radice. */\r\nexport interface DpeExtensible {\r\n extensionData?: DpeExtensionData;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 1. Elementi trasversali\r\n// ---------------------------------------------------------------------------\r\n\r\n/** I sei tipi logici, nessun altro valore mai (ADR 0002). */\r\nexport type LogicalType = 'String' | 'Number' | 'Integer' | 'DateTime' | 'Boolean' | 'Enum';\r\n\r\nexport interface ColumnType extends DpeExtensible {\r\n kind: LogicalType;\r\n /** Condiz.: richiesto per `String` nei campi dichiarati. */\r\n length?: number;\r\n /** Solo `Number`. */\r\n precision?: number;\r\n /** Condiz.: richiesto per `Number` nei campi dichiarati. */\r\n scale?: number;\r\n /** Condiz.: non vuoto quando `kind === 'Enum'`. */\r\n allowedValues?: string[];\r\n}\r\n\r\nexport type SortDirection = 'Ascending' | 'Descending';\r\n\r\nexport interface OrderByField extends DpeExtensible {\r\n /** Alias della colonna a monte. */\r\n columnName: string;\r\n /** Default `Ascending`. */\r\n direction?: SortDirection;\r\n}\r\n\r\nexport type AggregateFunction =\r\n | 'Count'\r\n | 'CountDistinct'\r\n | 'Sum'\r\n | 'Min'\r\n | 'Max'\r\n | 'Avg'\r\n | 'StdDev'\r\n | 'StdDevPop'\r\n | 'Variance'\r\n | 'VariancePop';\r\n\r\n/** Base di tutti i nodi. `name` e' univoco nell'intera definizione (**I1**). */\r\nexport interface DpeNode extends DpeExtensible {\r\n name: string;\r\n label: string;\r\n description?: string;\r\n}\r\n\r\n/**\r\n * I riferimenti a un nodo a monte sono dichiarati **opzionali** anche dove\r\n * `domain-model.md` li marca obbligatori, e non e' un ammorbidimento del contratto: e' cio'\r\n * che il contratto dice. In C# sono `string` con default `null`, l'obbligatorieta' e'\r\n * verificata dalla validazione e \"un modello incompleto e' un fatto normale (l'editor ne\r\n * produce uno a ogni tasto)\". Un nodo appena creato o appena scollegato **non ha** una\r\n * sorgente: rappresentarla con la stringa vuota sarebbe un valore magico che il backend\r\n * legge diversamente da un'assenza.\r\n */\r\n\r\n\r\n// ---------------------------------------------------------------------------\r\n// 2. Radice\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type SqlDialectKind = 'Sqlite' | 'SqlServer' | 'PostgreSql' | 'Oracle';\r\nexport type DefinitionStatus = 'Active' | 'Inactive';\r\nexport type DefinitionRunMode = 'Batch' | 'OnDemand';\r\n\r\nexport interface DpeDefinition extends DpeExtensible {\r\n /** Default `1`, sempre serializzato per primo. */\r\n formatVersion: number;\r\n name: string;\r\n label: string;\r\n description?: string;\r\n /** Il dialetto e' **parte della definizione** (ADR 0009): cambiarlo e' una migrazione. */\r\n dialect: SqlDialectKind;\r\n /** Default `Inactive`. */\r\n status?: DefinitionStatus;\r\n /** Default `Batch`. */\r\n runMode?: DefinitionRunMode;\r\n /** Default `false`. */\r\n isTemplate?: boolean;\r\n parameters?: DpeParameter[];\r\n /** Obbligatoria (>=1) in una definizione valida; assente in una in lavorazione. */\r\n dataSources?: DataSourceNode[];\r\n filters?: FilterNode[];\r\n joins?: JoinNode[];\r\n aggregates?: AggregateNode[];\r\n transforms?: TransformNode[];\r\n appends?: AppendNode[];\r\n hierarchyPaths?: HierarchyPathNode[];\r\n /** Modellati, non compilabili in v1 (`DPE_NODE_NOT_COMPILABLE`). */\r\n forecasts?: ForecastNode[];\r\n /** Modellati, non compilabili in v1. */\r\n customNodes?: CustomNode[];\r\n /** Obbligatoria (>=1) in una definizione valida. */\r\n writebacks?: WritebackNode[];\r\n atomicWritebacks?: AtomicWritebackNode[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 3. Parametri\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type ParameterRole = 'Value' | 'Filter' | 'Expression';\r\n\r\nexport interface DpeParameter extends DpeExtensible {\r\n name: string;\r\n label: string;\r\n description?: string;\r\n role: ParameterRole;\r\n /** Condiz.: richiesto quando `role === 'Value'`. */\r\n valueType?: ColumnType;\r\n /** Testo, interpretato secondo `valueType`, cultura invariante. */\r\n defaultValue?: string;\r\n /** Default `false`; ammesso solo per `role === 'Value'`. */\r\n isMultiValue?: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 4. Nodi sorgente\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type DataSourceKind = 'Table' | 'Csv' | 'ExternalDataset';\r\nexport type CsvDelimiter = 'Comma' | 'Semicolon' | 'Tab' | 'Pipe' | 'Caret' | 'Backquote';\r\n\r\nexport interface CsvSourceOptions extends DpeExtensible {\r\n /** Default `Comma`. */\r\n delimiter?: CsvDelimiter;\r\n /** Default `true`. */\r\n hasHeaderRow?: boolean;\r\n /** Identificatore opaco risolto dall'host. */\r\n location: string;\r\n}\r\n\r\nexport interface DataSourceField extends DpeExtensible {\r\n /** Nome del campo nella tabella/file di origine. */\r\n name: string;\r\n /** Quando assente l'alias **e'** `name`: la normalizzazione e' del backend. */\r\n alias?: string;\r\n /** Condiz.: richiesto per `Csv`/`ExternalDataset`; per `Table` **ignorato**. */\r\n declaredType?: ColumnType;\r\n /** Default `false`. */\r\n isPrimaryKey?: boolean;\r\n}\r\n\r\nexport interface DataSourceNode extends DpeNode {\r\n kind: DataSourceKind;\r\n /** Condiz.: richiesto per `kind === 'Table'`; nome noto al provider di metadati. */\r\n tableName?: string;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: DataSourceField[];\r\n /** Condiz.: richiesto per `kind === 'Csv'`. */\r\n csvOptions?: CsvSourceOptions;\r\n /** Condiz.: richiesto per `kind === 'ExternalDataset'`. */\r\n externalDatasetName?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 5. Nodi di trasformazione\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type FilterOperator =\r\n | 'Equals'\r\n | 'NotEquals'\r\n | 'GreaterThan'\r\n | 'GreaterThanOrEqual'\r\n | 'LessThan'\r\n | 'LessThanOrEqual'\r\n | 'StartsWith'\r\n | 'EndsWith'\r\n | 'Contains'\r\n | 'DoesNotContain'\r\n | 'IsNull'\r\n | 'IsNotNull'\r\n | 'In'\r\n | 'NotIn';\r\n\r\nexport interface FilterCriterion extends DpeExtensible {\r\n /** >=1, univoco nel nodo, referenziato da `condition`. */\r\n sequence: number;\r\n /** Alias a monte. */\r\n sourceFieldName: string;\r\n operator: FilterOperator;\r\n /** Condiz.: richiesto salvo `IsNull`/`IsNotNull` e salvo `inputVariable` presente. */\r\n value?: string;\r\n /** Nome di un `DpeParameter` con `role === 'Value'`; esclusivo con `value`. */\r\n inputVariable?: string;\r\n}\r\n\r\nexport interface FilterNode extends DpeNode {\r\n sourceName?: string;\r\n /** Default `false`. */\r\n isDynamic?: boolean;\r\n /** Condiz.: richiesto (>=1) quando `isDynamic` e' falso. */\r\n criteria?: FilterCriterion[];\r\n /**\r\n * Condiz.: richiesto quando `isDynamic` e' falso. Combinazione booleana dei `sequence`\r\n * dei criteri (`1 AND (2 OR 3)`), **non** un'espressione SQL: e' l'unico linguaggio che il\r\n * backend parsifica davvero.\r\n */\r\n condition?: string;\r\n /** Condiz.: richiesto quando `isDynamic`; riferisce un parametro con `role === 'Filter'`. */\r\n filterParameterName?: string;\r\n}\r\n\r\nexport type JoinKind = 'Inner' | 'LeftOuter' | 'RightOuter' | 'FullOuter' | 'Lookup';\r\n\r\nexport interface JoinKey extends DpeExtensible {\r\n primaryFieldName: string;\r\n secondaryFieldName: string;\r\n}\r\n\r\nexport interface JoinResultField extends DpeExtensible {\r\n /** Deve essere `primarySourceName` o `secondarySourceName` del nodo. */\r\n sourceName: string;\r\n sourceFieldName: string;\r\n /** Univoco nel nodo (**I1**). */\r\n alias: string;\r\n}\r\n\r\nexport interface JoinNode extends DpeNode {\r\n primarySourceName?: string;\r\n secondarySourceName?: string;\r\n kind: JoinKind;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n keys?: JoinKey[];\r\n /** Lo schema di output e' **esplicito**: solo questi campi. */\r\n fields?: JoinResultField[];\r\n /** Default `false`; significativo solo per `kind === 'Lookup'`. */\r\n allowsMultipleLookupValues?: boolean;\r\n}\r\n\r\nexport interface AggregateField extends DpeExtensible {\r\n /** Alias a monte; assente **solo** per `Count` (conteggio righe). */\r\n sourceFieldName?: string;\r\n function: AggregateFunction;\r\n alias: string;\r\n}\r\n\r\nexport interface AggregateNode extends DpeNode {\r\n sourceName?: string;\r\n /** Alias a monte; vuoto = aggregazione globale su una riga. */\r\n groupBy?: string[];\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: AggregateField[];\r\n}\r\n\r\nexport type TransformKind = 'Expression' | 'Slice' | 'ComputeRelative';\r\n\r\nexport interface ExpressionField extends DpeExtensible {\r\n alias: string;\r\n /** **SQL nativo del dialetto della definizione** (ADR 0006): passa verbatim. */\r\n expression: string;\r\n /** **Autorevole e non verificato** (ADR 0006). */\r\n declaredType: ColumnType;\r\n}\r\n\r\nexport interface TransformNode extends DpeNode {\r\n sourceName?: string;\r\n kind: TransformKind;\r\n /** Condiz.: richiesto (>=1) per `Expression`/`ComputeRelative`, vuoto per `Slice`. */\r\n expressionFields?: ExpressionField[];\r\n /** Condiz.: richiesto (>=1) per `Slice`, vuoto altrimenti. */\r\n droppedFields?: string[];\r\n /** Solo `ComputeRelative`. */\r\n partitionBy?: string[];\r\n /** Solo `ComputeRelative`. */\r\n orderBy?: OrderByField[];\r\n}\r\n\r\nexport interface AppendNode extends DpeNode {\r\n /** Obbligatorio (>=2) in un nodo valido. */\r\n sources?: string[];\r\n /** Default `false`. */\r\n allowsDisjointSchema?: boolean;\r\n}\r\n\r\nexport interface HierarchyPathNode extends DpeNode {\r\n sourceName?: string;\r\n /** Chiave del nodo corrente. */\r\n selfFieldName?: string;\r\n /** Riferimento al padre. */\r\n parentFieldName?: string;\r\n /** Alias della colonna di percorso prodotta (`String`). */\r\n pathFieldName?: string;\r\n /** Default `true`. */\r\n includesSelfValue?: boolean;\r\n /** Condiz.: richiesto (>=1) quando `isAggregationRequired`. */\r\n aggregateFields?: AggregateField[];\r\n /** Default `false`. */\r\n isAggregationRequired?: boolean;\r\n rollupPercentageFieldName?: string;\r\n}\r\n\r\nexport type ForecastPeriodType =\r\n | 'Year'\r\n | 'YearQuarter'\r\n | 'YearMonth'\r\n | 'YearWeek'\r\n | 'YearMonthDay'\r\n | 'FiscalYear'\r\n | 'FiscalYearQuarter'\r\n | 'FiscalYearMonth'\r\n | 'FiscalYearWeek';\r\n\r\nexport type ForecastModelType = 'Auto' | 'Additive' | 'Multiplicative';\r\nexport type ForecastAccuracy = 'None' | 'Eighty' | 'NinetyFive';\r\n\r\nexport type DatePart =\r\n | 'Second'\r\n | 'Minute'\r\n | 'Hour'\r\n | 'Day'\r\n | 'Week'\r\n | 'Month'\r\n | 'Quarter'\r\n | 'Year';\r\n\r\nexport interface ForecastAggregationField extends DpeExtensible {\r\n fieldName: string;\r\n function: AggregateFunction;\r\n resultAlias: string;\r\n}\r\n\r\nexport interface ForecastGroupField extends DpeExtensible {\r\n fieldName: string;\r\n /** Condiz.: richiesto quando il campo e' `DateTime`. */\r\n datePart?: DatePart;\r\n}\r\n\r\n/** Modellato per intero, **non compilabile in v1** (`DPE_NODE_NOT_COMPILABLE`). */\r\nexport interface ForecastNode extends DpeNode {\r\n sourceName?: string;\r\n dateFieldName?: string;\r\n periodType?: ForecastPeriodType;\r\n /** Default `1`, ammesso 1..100. */\r\n periodCount?: number;\r\n /** Alias della colonna di inizio periodo prodotta. */\r\n periodStartFieldName?: string;\r\n /** Default `Auto`. */\r\n modelType?: ForecastModelType;\r\n /** `null`/assente = automatica; ammesso 2..24. */\r\n seasonality?: number;\r\n /** Default `None`. */\r\n accuracyPercent?: ForecastAccuracy;\r\n /** Default `false`. */\r\n excludesLastPeriod?: boolean;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n aggregationFields?: ForecastAggregationField[];\r\n groupFields?: ForecastGroupField[];\r\n}\r\n\r\n/** Usato dove uno schema si **dichiara** invece di derivarlo. */\r\nexport interface DeclaredField extends DpeExtensible {\r\n name: string;\r\n type: ColumnType;\r\n}\r\n\r\nexport interface CustomNodeParameter extends DpeExtensible {\r\n name: string;\r\n value: string;\r\n}\r\n\r\n/** Modellato per intero, **non compilabile in v1**. */\r\nexport interface CustomNode extends DpeNode {\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n sources?: string[];\r\n extensionName: string;\r\n extensionNamespace?: string;\r\n parameters?: CustomNodeParameter[];\r\n /**\r\n * Obbligatorio (>=1): senza schema dichiarato la propagazione (**I4**) si interrompe e\r\n * tutto cio' che sta a valle diventa invalidabile.\r\n */\r\n outputFields?: DeclaredField[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 6. Nodi sink\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type WritebackTargetKind = 'Database' | 'Json' | 'Csv';\r\nexport type WritebackOperation = 'Insert' | 'Update' | 'Upsert' | 'Delete';\r\nexport type WritebackFieldRole = 'Value' | 'PrimaryKey' | 'QualifierKey';\r\n\r\nexport interface WritebackFieldMapping extends DpeExtensible {\r\n /** Condiz.: alias a monte; assente quando `runtimeParameterName` e' presente. */\r\n sourceFieldName?: string;\r\n targetFieldName: string;\r\n /** Il valore viene da un parametro, non dalla riga; esclusivo con `sourceFieldName`. */\r\n runtimeParameterName?: string;\r\n /** Default `Value`. */\r\n role?: WritebackFieldRole;\r\n relationshipName?: string;\r\n /** Condiz.: richiesto quando `relationshipName` e' presente. */\r\n parentName?: string;\r\n /** Default `false`; se `true`, `sourceFieldName` non e' richiesto. */\r\n isAutoGenerated?: boolean;\r\n}\r\n\r\n/**\r\n * Opzioni dell'artefatto JSON (`contracts.md` §2, «Opzioni degli artefatti»). Sono **solo**\r\n * scelte di formato, mai di destinazione (ADR 0010).\r\n */\r\nexport interface JsonArtifactOptions extends DpeExtensible {\r\n /** Default `false`: JSON compatto, array di oggetti. */\r\n indented?: boolean;\r\n}\r\n\r\n/**\r\n * Opzioni dell'artefatto CSV. Il quoting **non e' configurabile** di proposito: si quota\r\n * quando serve e si raddoppiano le virgolette, perche' un quoting opzionale produce file che\r\n * qualcuno non riesce a rileggere.\r\n */\r\nexport interface CsvArtifactOptions extends DpeExtensible {\r\n /** Default `Comma`. */\r\n delimiter?: CsvDelimiter;\r\n /** Default `true`. */\r\n includesHeaderRow?: boolean;\r\n}\r\n\r\nexport interface WritebackNode extends DpeNode {\r\n sourceName?: string;\r\n /** **Determina l'artefatto prodotto**. */\r\n target: WritebackTargetKind;\r\n /** >=1, univoco fra tutti i writeback e gli atomic writeback. */\r\n sequence: number;\r\n /** Condiz.: richiesto per `target === 'Database'`. */\r\n tableName?: string;\r\n /** Condiz.: richiesto per `target === 'Database'`; assente per `Json`/`Csv`. */\r\n operation?: WritebackOperation;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: WritebackFieldMapping[];\r\n /** Espressione SQL nativa applicata al risultato (ADR 0006). */\r\n filterCondition?: string;\r\n /** Condiz.: richiesto per `operation === 'Upsert'`. */\r\n externalIdFieldName?: string;\r\n /** Default `false`. */\r\n onlyChangedRows?: boolean;\r\n /** Solo `target === 'Json'`. */\r\n jsonOptions?: JsonArtifactOptions;\r\n /** Solo `target === 'Csv'`. */\r\n csvOptions?: CsvArtifactOptions;\r\n}\r\n\r\nexport interface AtomicWritebackRelationship extends DpeExtensible {\r\n /** Nome di un `WritebackNode` con `target === 'Database'`. */\r\n parentWritebackName?: string;\r\n parentFieldName?: string;\r\n childWritebackName?: string;\r\n childFieldName?: string;\r\n relationshipName?: string;\r\n /** Ordine dentro il gruppo atomico. */\r\n sequence: number;\r\n}\r\n\r\nexport interface AtomicWritebackNode extends DpeNode {\r\n /** Nello stesso spazio di numerazione dei `WritebackNode`. */\r\n sequence: number;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n relationships?: AtomicWritebackRelationship[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Collezioni di nodi: la mappa nome-collezione -> tipo di nodo\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Le collezioni di nodi della radice, con il tipo che ciascuna contiene.\r\n *\r\n * Esiste perche' ogni utility che cammina il documento (derivazione degli archi, rinomina,\r\n * catalogo della palette) deve nominare le collezioni **una volta sola**: una collezione\r\n * dimenticata in uno dei tre posti non produce nessun errore, produce un arco che non\r\n * compare o un riferimento che resta rotto dopo una rinomina.\r\n */\r\nexport interface DpeNodeCollectionMap {\r\n dataSources: DataSourceNode;\r\n filters: FilterNode;\r\n joins: JoinNode;\r\n aggregates: AggregateNode;\r\n transforms: TransformNode;\r\n appends: AppendNode;\r\n hierarchyPaths: HierarchyPathNode;\r\n forecasts: ForecastNode;\r\n customNodes: CustomNode;\r\n writebacks: WritebackNode;\r\n atomicWritebacks: AtomicWritebackNode;\r\n}\r\n\r\nexport type DpeNodeCollectionName = keyof DpeNodeCollectionMap;\r\n\r\n/** Qualunque nodo della definizione. */\r\nexport type DpeAnyNode = DpeNodeCollectionMap[DpeNodeCollectionName];\r\n\r\n/**\r\n * L'elenco dei nomi di collezione in forma di valore, nell'ordine in cui i nodi si leggono\r\n * (sorgenti -> trasformazioni -> sink). `keyof` non produce un array a runtime: questo\r\n * elenco e' l'unico posto in cui vive l'ordine.\r\n */\r\nexport const DPE_NODE_COLLECTIONS: readonly DpeNodeCollectionName[] = [\r\n 'dataSources',\r\n 'filters',\r\n 'joins',\r\n 'aggregates',\r\n 'transforms',\r\n 'appends',\r\n 'hierarchyPaths',\r\n 'forecasts',\r\n 'customNodes',\r\n 'writebacks',\r\n 'atomicWritebacks',\r\n];\r\n","/**\r\n * Diagnostiche — traduzione letterale di `Jace.DPE.Diagnostics` (`docs/contracts.md` §1).\r\n *\r\n * Tipi allineati **a mano** ai record C# (ADR 0007). L'editor **consuma** queste\r\n * diagnostiche e non ne produce: nessuna regola di dominio vive nel frontend, quindi in\r\n * questo file non ci sono ne' codici inventati ne' messaggi ricomposti. Il `message` arriva\r\n * dal backend, che e' l'unico posto in cui un messaggio viene composto.\r\n */\r\n\r\nexport type DiagnosticSeverity = 'Info' | 'Warning' | 'Error';\r\n\r\nexport interface DiagnosticPathSegment {\r\n /** `\"filters\"`, `\"criteria\"`, `\"fields\"`, ... */\r\n collection?: string;\r\n /** Nome del nodo/alias, se applicabile. */\r\n name?: string;\r\n /** Indice nella collezione, se applicabile. */\r\n index?: number;\r\n}\r\n\r\n/**\r\n * Percorso strutturato del rilievo.\r\n *\r\n * **Due forme, entrambe da gestire** (`contracts.md` §1, limite dichiarato): in\r\n * deserializzazione i nomi dei nodi non sono ancora noti e i segmenti portano solo l'indice\r\n * (`filters[0].sourceName`); dalla validazione portano il nome (`filters/OnlyActive`). Chi\r\n * naviga fino al campo deve accettare tutt'e due, altrimenti le diagnostiche del caricamento\r\n * di un file non sono cliccabili.\r\n */\r\nexport interface DiagnosticPath {\r\n segments?: DiagnosticPathSegment[];\r\n /** Nome della proprieta' in causa, camelCase. */\r\n field?: string;\r\n}\r\n\r\n/**\r\n * `arguments` e' un dizionario di stringhe con **chiavi canoniche** (`contracts.md` §1):\r\n * `node`, `field`, `column`, `alias`, `name`, `table`, `parameter`, `dialect`, `construct`,\r\n * `expected`, `actual`, `value`, `sequence`, `condition`, `token`, `truncated`. L'editor le\r\n * legge per costruire etichette, non per riscrivere il messaggio.\r\n */\r\nexport interface Diagnostic {\r\n /** `DiagnosticCodes.*` del backend. Il frontend non ne dichiara l'elenco: e' del backend. */\r\n code: string;\r\n severity: DiagnosticSeverity;\r\n path?: DiagnosticPath;\r\n arguments?: Record<string, string>;\r\n /** Derivato da `code` + `arguments`, cultura invariante. */\r\n message: string;\r\n}\r\n\r\n/**\r\n * L'unico codice che significa \"hai fatto bene, siamo noi\": nodo valido ma non ancora\r\n * compilabile (`Forecast`, `CustomNode`, costrutto non supportato — **I10**). Va distinto\r\n * visivamente dai `DPE_MODEL_*`, che invece l'utente deve correggere.\r\n *\r\n * E' l'unica costante di codice diagnostico che la libreria dichiara, e non e' una\r\n * duplicazione del dominio: e' la sola distinzione che cambia **come si rende** un rilievo.\r\n */\r\nexport const DPE_NODE_NOT_COMPILABLE = 'DPE_NODE_NOT_COMPILABLE';\r\n\r\n/** Rappresentazione testuale del percorso, nella forma usata dai messaggi del backend. */\r\nexport function diagnosticPathToString(path: DiagnosticPath | undefined): string {\r\n if (!path) {\r\n return '';\r\n }\r\n const segments = path.segments ?? [];\r\n let text = '';\r\n for (const segment of segments) {\r\n if (segment.collection) {\r\n text += text.length > 0 ? `/${segment.collection}` : segment.collection;\r\n }\r\n if (segment.name) {\r\n text += `/${segment.name}`;\r\n } else if (segment.index !== undefined) {\r\n text += `[${segment.index}]`;\r\n }\r\n }\r\n if (path.field) {\r\n text += text.length > 0 ? `.${path.field}` : path.field;\r\n }\r\n return text;\r\n}\r\n","/**\r\n * Tipi di richiesta/risposta del service DPE — traduzione letterale di `docs/contracts.md`\r\n * §2 (provider di metadati), §3 (SQL emesso) e §5 (il service).\r\n *\r\n * Allineati **a mano** ai record C# (ADR 0007). Cio' che non e' trasportabile non c'e':\r\n * `DpeContext` porta i provider dell'host (`ITableMetadataProvider`, `IDataQueryProvider`,\r\n * `IArtifactSink`, `ILogger`, `IClock`) e vive **dentro** il backend, quindi non ha un\r\n * corrispettivo TypeScript. Lo stesso vale per `Execute`: l'editor non esegue, non\r\n * materializza artefatti e non ha bisogno di `DpeExecuteResult`.\r\n */\r\n\r\nimport {\r\n ColumnType,\r\n DefinitionRunMode,\r\n DefinitionStatus,\r\n LogicalType,\r\n SqlDialectKind,\r\n WritebackFieldRole,\r\n WritebackOperation,\r\n WritebackTargetKind,\r\n} from './dpe-definition.model';\r\nimport { Diagnostic } from './dpe-diagnostics.model';\r\n\r\n// ---------------------------------------------------------------------------\r\n// §7 La dichiarazione dell'ambiente (ADR 0017)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cio' che l'ambiente ospite **dichiara** all'editor. Non e' un tipo del backend C#: `IDpeService`\r\n * non cambia (ADR 0017), e l'host lo compone con cio' che gia' sa della propria installazione.\r\n *\r\n * Nasce con un solo campo e si estende **per aggiunta**: e' il posto previsto per i fatti\r\n * dell'ambiente, non un contenitore da riempire in anticipo.\r\n */\r\nexport interface DpeEnvironment {\r\n /** Il dialetto del database di destinazione. Dichiarato, mai scelto dall'utente dell'editor. */\r\n readonly dialect: SqlDialectKind;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §7 Catalogo delle definizioni (ADR 0019)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Riga di catalogo: identita' e fatti che l'ospite conosce **senza** caricare la definizione.\r\n *\r\n * Distinto da `DpeDefinition` per costruzione, e non per comodita': elencare non deve costare N\r\n * caricamenti completi. Non ha un corrispettivo in `IDpeService` e non deve averlo — il service\r\n * valida, compila ed esegue; dove le definizioni vivano e' dell'ospite (ADR 0007), che non ha\r\n * ne' orologio ne' archiviazione lato libreria.\r\n *\r\n * I quattro campi in coda sono facoltativi in senso pieno: assenti, la riga **non li mostra e\r\n * non li stima**. Contare i nodi lato client vorrebbe dire caricare tutte le definizioni per\r\n * disegnare un elenco, e dedurre `updatedAt` e' impossibile.\r\n */\r\nexport interface DpeDefinitionSummary {\r\n /** La chiave. Non esiste un id distinto dal nome (ADR 0019): rinominare e' cambiare chiave. */\r\n name: string;\r\n label: string;\r\n description?: string;\r\n dialect: SqlDialectKind;\r\n status?: DefinitionStatus;\r\n runMode?: DefinitionRunMode;\r\n isTemplate?: boolean;\r\n /** ISO 8601. Lo scrive l'ospite: la libreria non ha orologio. Assente = non mostrato. */\r\n updatedAt?: string;\r\n updatedBy?: string;\r\n /** Numero di nodi. Lo conta l'ospite, **mai** il client. Assente = non mostrato. */\r\n nodeCount?: number;\r\n /**\r\n * Esito dell'ultima validazione **noto all'ospite**: riportato, non ricalcolato. Puo' essere\r\n * vecchio, quindi la riga lo mostra come stato noto e non come verita' — il frontend non\r\n * valida nulla, e dedurlo qui sarebbe una validazione fatta dal client per interposta persona.\r\n */\r\n hasErrors?: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §2 Provider di metadati\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Tre esiti, **non due** (ADR 0004): \"dichiarata\", \"dichiarata senza campi\" e\r\n * \"sconosciuta\" sono situazioni diverse e l'editor le mostra diverse. Chi implementa\r\n * l'interfaccia non appiattisce `Unknown` in una lista di campi vuota.\r\n */\r\nexport type TableLookupOutcome = 'Declared' | 'DeclaredWithoutFields' | 'Unknown';\r\n\r\nexport interface TableSummary {\r\n name: string;\r\n description?: string;\r\n}\r\n\r\nexport interface FieldRelationship {\r\n targetTableName: string;\r\n targetFieldName: string;\r\n}\r\n\r\nexport interface FieldDescriptor {\r\n name: string;\r\n description?: string;\r\n type: ColumnType;\r\n isKey: boolean;\r\n isNullable: boolean;\r\n /** Assente quando il campo non e' una relazione. */\r\n relationship?: FieldRelationship;\r\n}\r\n\r\nexport interface TableDescriptor {\r\n name: string;\r\n description?: string;\r\n fields?: FieldDescriptor[];\r\n}\r\n\r\nexport interface TableLookupResult {\r\n outcome: TableLookupOutcome;\r\n /** Presente solo con `outcome === 'Declared'`. */\r\n table?: TableDescriptor;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §3 SQL emesso\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface SqlParameterValue {\r\n /** Senza prefisso di dialetto: `\"p0\"`, `\"param_StartDate\"`. */\r\n name: string;\r\n type: LogicalType;\r\n /** `null` ammesso. Valore opaco per l'editor, che lo mostra e non lo interpreta. */\r\n value: unknown;\r\n}\r\n\r\nexport interface SqlStatement {\r\n /** Porta i marcatori nella forma del dialetto (`@p0`, `:p0`, `$1`). */\r\n text: string;\r\n parameters?: SqlParameterValue[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §5 Il service: Validate\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface DpeColumnInfo {\r\n name: string;\r\n type: ColumnType;\r\n /**\r\n * Informativa (**I4**): serve alla vista dello schema, non blocca la compilazione. Il\r\n * frontend non la calcola — arriva da qui.\r\n */\r\n isNullable: boolean;\r\n}\r\n\r\nexport interface DpeNodeSchemaInfo {\r\n nodeName: string;\r\n columns?: DpeColumnInfo[];\r\n /**\r\n * `false` = nodo **valido ma non compilabile** (**I10**): e' un limite nostro, non un\r\n * errore dell'utente, e va reso diverso da un nodo invalido.\r\n */\r\n isCompilable: boolean;\r\n}\r\n\r\nexport interface DpeWritebackStep {\r\n writebackName: string;\r\n sequence: number;\r\n target: WritebackTargetKind;\r\n /** Assente per i target `Json`/`Csv`. */\r\n operation?: WritebackOperation;\r\n tableName?: string;\r\n /**\r\n * Campo di corrispondenza dell'`Upsert`; assente per ogni altra operazione. E' un\r\n * `targetFieldName`: si ritrova in `targetMapping` per risalire alla colonna del result set\r\n * (ADR 0016).\r\n */\r\n externalIdFieldName?: string;\r\n /** Presente se il writeback appartiene a un gruppo atomico. */\r\n atomicGroupName?: string;\r\n /**\r\n * Dichiarato, **non implementato dalla libreria**: il change tracking e' dell'host\r\n * (ADR 0011) e non influenza l'SQL generato. Va mostrato come una dichiarazione che l'host\r\n * deve onorare, non come una cosa che il motore fa.\r\n */\r\n onlyChangedRows?: boolean;\r\n}\r\n\r\nexport interface DpeValidateResult {\r\n hasErrors: boolean;\r\n /** Esaustive (**I6**): l'elenco completo, non il primo rilievo. */\r\n diagnostics?: Diagnostic[];\r\n /** Ordine topologico. */\r\n schemas?: DpeNodeSchemaInfo[];\r\n executionOrder?: string[];\r\n writebackSequence?: DpeWritebackStep[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §5 Il service: Compile\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Valore di un parametro di runtime per una compilazione (`DpeParameterValue`).\r\n *\r\n * `value` e' **opaco**: il tipo dichiarato del parametro lo conosce il backend, che lo\r\n * interpreta secondo `ColumnType` in cultura invariante. L'editor lo trasporta e lo mostra,\r\n * non lo converte.\r\n */\r\nexport interface DpeParameterValue {\r\n name: string;\r\n value: unknown;\r\n}\r\n\r\n/**\r\n * Cio' che serve all'host per **eseguire** la scrittura che la libreria non esegue\r\n * (`contracts.md` §2, «`DpeFieldMappingInfo`»): senza, l'host riceve un result set e non sa\r\n * quale colonna va in quale campo ne' quale sia la chiave.\r\n */\r\nexport interface DpeFieldMappingInfo {\r\n /** Nome della colonna nel result set dello `SqlStatement`. */\r\n resultColumnName?: string;\r\n targetFieldName: string;\r\n role: WritebackFieldRole;\r\n /** Presente: il valore viene da un parametro, non dalla riga. */\r\n runtimeParameterName?: string;\r\n /** La destinazione genera il valore: non e' nel result set. */\r\n isAutoGenerated?: boolean;\r\n relationshipName?: string;\r\n parentName?: string;\r\n}\r\n\r\nexport interface DpeCompiledWriteback {\r\n writebackName: string;\r\n sequence: number;\r\n statement: SqlStatement;\r\n resultColumns?: DpeColumnInfo[];\r\n /** Vedi {@link DpeFieldMappingInfo}: forma provvisoria. */\r\n targetMapping?: DpeFieldMappingInfo[];\r\n}\r\n\r\nexport interface DpeCompileResult {\r\n hasErrors: boolean;\r\n diagnostics?: Diagnostic[];\r\n databaseWritebacks?: DpeCompiledWriteback[];\r\n /** SQL di lettura, non ancora eseguito. */\r\n fileWritebacks?: DpeCompiledWriteback[];\r\n writebackSequence?: DpeWritebackStep[];\r\n}\r\n","/**\r\n * Quali primitive **opzionali** l'ospite implementa davvero — `contracts.md` §7, normativo.\r\n *\r\n * La rilevazione e' per **identita' del metodo**: se il metodo dell'istanza e' ancora quello del\r\n * prototipo di `DpeBuilderApi`, l'ospite non lo ha sovrascritto e la primitiva non c'e'. E'\r\n * esatta, non richiede una primitiva di interrogazione e non aggiunge un giro di rete.\r\n *\r\n * Perche' un solo posto: la disponibilita' va saputa **prima del clic**. Lo schema precedente —\r\n * partire da «disponibile» e scoprire l'assenza dal primo `MissingService` — mostra un comando\r\n * attivo che fallisce alla pressione, cioe' insegna a non fidarsi dei bottoni, e per giunta\r\n * costringe ogni consumatore a ripetere lo stesso trattamento dell'errore.\r\n *\r\n * Regola per chi implementa un host (normativa, `contracts.md` §7): **chi non supporta una\r\n * primitiva non la sovrascrive**. Una sovrascrittura che lancia subito non equivale all'assenza —\r\n * l'editor la considera disponibile e mostra il comando attivo.\r\n *\r\n * **Dichiarazione sottrattiva (ADR 0020).** Da quando la libreria spedisce un client HTTP che\r\n * implementa tutte e dieci le primitive, l'identita' da sola non basta: chi eredita quel client\r\n * non puo' dis-sovrascrivere un metodo. Disponibile diventa quindi «**sovrascritta** e **non\r\n * elencata** in `unsupportedPrimitives`». La seconda meta' e' solo sottrattiva — non rende\r\n * disponibile cio' che non e' implementato — e resta calcolata in questo file e in nessun altro.\r\n */\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\n\r\n/** Le primitive che un ambiente ospite puo' legittimamente non offrire. */\r\nexport type DpeOptionalPrimitive =\r\n | 'compilePreview'\r\n | 'load'\r\n | 'save'\r\n | 'getEnvironment'\r\n | 'listDefinitions'\r\n | 'createDefinition'\r\n | 'deleteDefinition';\r\n\r\ntype MethodBag = Record<string, unknown>;\r\n\r\nexport function dpeIsPrimitiveAvailable(\r\n api: DpeBuilderApi,\r\n primitive: DpeOptionalPrimitive,\r\n): boolean {\r\n // Prima la dichiarazione dell'ospite: se il servizio non c'e', non conta chi ha scritto il\r\n // metodo. E' l'unico modo per un ospite di spegnere una primitiva che ha **ereditato**.\r\n if (api.unsupportedPrimitives?.includes(primitive)) {\r\n return false;\r\n }\r\n const base = DpeBuilderApi.prototype as unknown as MethodBag;\r\n const implementation = (api as unknown as MethodBag)[primitive];\r\n return typeof implementation === 'function' && implementation !== base[primitive];\r\n}\r\n\r\n/** L'insieme delle primitive disponibili: comodo per fotografarlo una volta alla costruzione. */\r\nexport interface DpeCapabilities {\r\n readonly compilePreview: boolean;\r\n readonly load: boolean;\r\n readonly save: boolean;\r\n readonly getEnvironment: boolean;\r\n readonly listDefinitions: boolean;\r\n readonly createDefinition: boolean;\r\n readonly deleteDefinition: boolean;\r\n}\r\n\r\nexport function dpeReadCapabilities(api: DpeBuilderApi): DpeCapabilities {\r\n return {\r\n compilePreview: dpeIsPrimitiveAvailable(api, 'compilePreview'),\r\n load: dpeIsPrimitiveAvailable(api, 'load'),\r\n save: dpeIsPrimitiveAvailable(api, 'save'),\r\n getEnvironment: dpeIsPrimitiveAvailable(api, 'getEnvironment'),\r\n listDefinitions: dpeIsPrimitiveAvailable(api, 'listDefinitions'),\r\n createDefinition: dpeIsPrimitiveAvailable(api, 'createDefinition'),\r\n deleteDefinition: dpeIsPrimitiveAvailable(api, 'deleteDefinition'),\r\n };\r\n}\r\n\r\n/**\r\n * Disponibilita' di un comando, con **il motivo** quando manca: un bottone disabilitato che non\r\n * dice perche' manda a cercare un guasto che non c'e'.\r\n */\r\nexport interface DpeCommandAvailability {\r\n readonly isAvailable: boolean;\r\n /** Presente **solo** quando il comando non e' disponibile. Va nel `title` del bottone. */\r\n readonly reason?: string;\r\n}\r\n\r\n/**\r\n * Il comando di **creazione** e' l'unico che dipende da **due** primitive\r\n * (`contracts.md` §7, normativo): `createDefinition` per scrivere, e `getEnvironment` perche' il\r\n * dialetto della definizione nuova viene dall'ambiente (ADR 0017).\r\n *\r\n * Perche' senza `getEnvironment` si disabilita invece di ripiegare su un dialetto qualsiasi: una\r\n * definizione creata per il dialetto sbagliato porta espressioni SQL native (ADR 0006) da\r\n * riscrivere tutte, e chiederlo all'utente e' proprio la scelta che l'ADR 0017 ha tolto. Un\r\n * comando disabilitato che dice perche' e' meglio di entrambe; il rimedio per l'ospite e' una\r\n * riga, implementare `getEnvironment`.\r\n *\r\n * Sta qui e non dentro un componente per la stessa ragione delle altre: la disponibilita' si sa\r\n * **prima del clic**, e in un solo posto.\r\n */\r\nexport function dpeCreateCommandAvailability(\r\n capabilities: DpeCapabilities,\r\n): DpeCommandAvailability {\r\n const missing: string[] = [];\r\n if (!capabilities.createDefinition) {\r\n missing.push('createDefinition');\r\n }\r\n if (!capabilities.getEnvironment) {\r\n missing.push('getEnvironment');\r\n }\r\n if (missing.length === 0) {\r\n return { isAvailable: true };\r\n }\r\n return {\r\n isAvailable: false,\r\n reason:\r\n missing.length === 2\r\n ? 'Creazione non disponibile: questo ambiente non implementa createDefinition ne’ getEnvironment. ' +\r\n 'Senza la dichiarazione dell’ambiente il dialetto non si sceglie per ripiego (ADR 0017).'\r\n : missing[0] === 'createDefinition'\r\n ? 'Creazione non disponibile: questo ambiente non implementa createDefinition.'\r\n : 'Creazione non disponibile: questo ambiente non dichiara l’ambiente (getEnvironment), ' +\r\n 'quindi il dialetto della definizione nuova non e’ noto e non si sceglie per ripiego (ADR 0017).',\r\n };\r\n}\r\n","/**\r\n * Il grafo della definizione: **un solo posto** costruisce gli id di nodi, porte e archi, e\r\n * **un solo elenco** descrive dove vivono i riferimenti fra nodi.\r\n *\r\n * Perche' sta tutto qui. Un id di porta costruito in due modi diversi (canvas da un lato,\r\n * derivazione degli archi dall'altro) fa sparire un arco **senza nessun errore**: e' il\r\n * difetto piu' difficile da trovare in un editor a canvas. Allo stesso modo, un riferimento\r\n * dimenticato nell'elenco degli slot fa restare incoerente il documento dopo una rinomina,\r\n * anche lì in silenzio.\r\n *\r\n * Cosa **non** sta qui: nessuna regola di dominio. Questo file dice *dove* stanno i nomi dei\r\n * nodi a monte, non se un riferimento e' valido, se il grafo ha cicli (**I2**), se un nodo e'\r\n * a valle (**I3**) o quali colonne produca (**I4**). Quelle risposte arrivano da\r\n * `DpeBuilderApi.validate`.\r\n */\r\n\r\nimport {\r\n AggregateNode,\r\n AppendNode,\r\n AtomicWritebackNode,\r\n CustomNode,\r\n DataSourceNode,\r\n DPE_NODE_COLLECTIONS,\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n FilterNode,\r\n ForecastNode,\r\n HierarchyPathNode,\r\n JoinNode,\r\n TransformNode,\r\n WritebackNode,\r\n} from '../model/dpe-definition.model';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Id — l'unico posto che li costruisce\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Separatore dei componenti di un id. Un nome di nodo non lo contiene mai: i nomi sono\r\n * identificatori del modello e il backend li usa come identificatori SQL.\r\n */\r\nconst SEP = '::';\r\n\r\nexport function dpeNodeId(nodeName: string): string {\r\n return `node${SEP}${nodeName}`;\r\n}\r\n\r\n/**\r\n * Porta di ingresso. Una porta **per slot** (e per indice, sugli slot a lista): un `JoinNode`\r\n * ha due ingressi distinti e attaccare l'arco alla porta sbagliata scambia primaria e\r\n * secondaria, che e' un join diverso.\r\n */\r\nexport function dpeInputPortId(nodeName: string, slot: string, index?: number): string {\r\n const suffix = index === undefined ? '' : `${SEP}${index}`;\r\n return `in${SEP}${nodeName}${SEP}${slot}${suffix}`;\r\n}\r\n\r\n/** Porta di uscita: una sola per nodo, lo schema prodotto e' uno. */\r\nexport function dpeOutputPortId(nodeName: string): string {\r\n return `out${SEP}${nodeName}`;\r\n}\r\n\r\n/**\r\n * Id dell'arco: identifica la **destinazione** (nodo, slot, indice), non la coppia di nodi.\r\n * Due archi possono unire gli stessi due nodi su slot diversi — la primaria e la secondaria\r\n * di un self-join — e con un id per coppia uno dei due sparirebbe.\r\n */\r\nexport function dpeEdgeId(targetNodeName: string, slot: string, index?: number): string {\r\n const suffix = index === undefined ? '' : `${SEP}${index}`;\r\n return `edge${SEP}${targetNodeName}${SEP}${slot}${suffix}`;\r\n}\r\n\r\n/**\r\n * Gli inversi. Stanno **accanto** ai costruttori e non nel canvas: la libreria di canvas\r\n * restituisce gli id nei suoi eventi, e chi li legge deve tornare al nome del nodo con la\r\n * stessa convenzione con cui li ha scritti. Separarli e' il modo con cui un giorno cambierebbe\r\n * uno solo dei due.\r\n */\r\nexport function dpeParseNodeId(id: string): string | undefined {\r\n return id.startsWith(`node${SEP}`) ? id.slice(4 + SEP.length) : undefined;\r\n}\r\n\r\nexport function dpeParseOutputPortId(id: string): string | undefined {\r\n return id.startsWith(`out${SEP}`) ? id.slice(3 + SEP.length) : undefined;\r\n}\r\n\r\nexport function dpeParseInputPortId(\r\n id: string,\r\n): { nodeName: string; slot: string; index?: number } | undefined {\r\n if (!id.startsWith(`in${SEP}`)) {\r\n return undefined;\r\n }\r\n const parts = id.slice(2 + SEP.length).split(SEP);\r\n if (parts.length < 2) {\r\n return undefined;\r\n }\r\n const [nodeName, slot, rawIndex] = parts;\r\n const index = rawIndex === undefined ? undefined : Number(rawIndex);\r\n return {\r\n nodeName,\r\n slot,\r\n index: index === undefined || Number.isNaN(index) ? undefined : index,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Slot dei riferimenti — l'unico elenco\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Uno slot e' un punto del nodo che contiene il nome di **un altro nodo**.\r\n *\r\n * `read` e `write` sono **posizionali e di lunghezza stabile**: `write(node, read(node))` non\r\n * cambia il nodo. E' la proprieta' che permette di implementare la rinomina come\r\n * `write(node, read(node).map(rinomina))` — cioe' con un solo cammino di codice, invece di\r\n * due elenchi (uno per leggere gli archi, uno per rinominare) che al primo campo aggiunto\r\n * diventano due elenchi diversi.\r\n */\r\nexport interface DpeSourceSlot<TNode> {\r\n readonly slot: string;\r\n /**\r\n * `true` quando lo slot e' un **arco del DAG** (il flusso dei dati). `false` per i\r\n * riferimenti che sono altro: i `sourceName` dei `JoinResultField` ripetono le sorgenti del\r\n * join, e le relazioni di un gruppo atomico dichiarano una transazione dell'host, non un\r\n * flusso di dati (l'ordinamento dei sink e' esplicito e separato dal DAG).\r\n */\r\n readonly isEdge: boolean;\r\n read(node: TNode): readonly (string | undefined)[];\r\n write(node: TNode, names: readonly (string | undefined)[]): TNode;\r\n}\r\n\r\nfunction single<TNode, TKey extends keyof TNode>(\r\n slot: string,\r\n key: TKey,\r\n isEdge = true,\r\n): DpeSourceSlot<TNode> {\r\n return {\r\n slot,\r\n isEdge,\r\n read: (node) => [node[key] as unknown as string | undefined],\r\n // Il cast copre solo la chiave calcolata: TypeScript non sa che `key` di `TNode` porta una\r\n // stringa, e la mappa dei tipi non e' esprimibile senza questo passaggio.\r\n write: (node, names) => ({ ...node, [key]: names[0] }) as unknown as TNode,\r\n };\r\n}\r\n\r\nfunction list<TNode, TKey extends keyof TNode>(\r\n slot: string,\r\n key: TKey,\r\n isEdge = true,\r\n): DpeSourceSlot<TNode> {\r\n return {\r\n slot,\r\n isEdge,\r\n read: (node) => ((node[key] as unknown as string[] | undefined) ?? []).slice(),\r\n // Uno slot a lista non si accorcia in scrittura: `write` riscrive i nomi al loro posto.\r\n // Aggiungere o togliere una sorgente e' una mutazione dello store, non una riscrittura.\r\n write: (node, names) =>\r\n ({ ...node, [key]: names.map((name) => name ?? '') }) as unknown as TNode,\r\n };\r\n}\r\n\r\nconst JOIN_RESULT_FIELDS_SLOT: DpeSourceSlot<JoinNode> = {\r\n slot: 'resultFields',\r\n isEdge: false,\r\n read: (node) => (node.fields ?? []).map((field) => field.sourceName),\r\n write: (node, names) =>\r\n node.fields === undefined\r\n ? node\r\n : {\r\n ...node,\r\n fields: node.fields.map((field, index) => ({ ...field, sourceName: names[index] ?? '' })),\r\n },\r\n};\r\n\r\n/**\r\n * Le relazioni di un gruppo atomico portano **due** nomi di writeback ciascuna, padre e\r\n * figlio. Sono letti e riscritti in coppia e in ordine: se questo slot mancasse, rinominare\r\n * un writeback lascerebbe il gruppo atomico che punta a un nome che non esiste piu' — senza\r\n * nessun errore lato editor, e con un rifiuto del backend che parla di un nodo che l'utente\r\n * non ha toccato.\r\n */\r\nconst ATOMIC_RELATIONSHIPS_SLOT: DpeSourceSlot<AtomicWritebackNode> = {\r\n slot: 'relationships',\r\n isEdge: false,\r\n read: (node) =>\r\n (node.relationships ?? []).flatMap((relationship) => [\r\n relationship.parentWritebackName,\r\n relationship.childWritebackName,\r\n ]),\r\n write: (node, names) =>\r\n node.relationships === undefined\r\n ? node\r\n : {\r\n ...node,\r\n relationships: node.relationships.map((relationship, index) => ({\r\n ...relationship,\r\n parentWritebackName: names[index * 2],\r\n childWritebackName: names[index * 2 + 1],\r\n })),\r\n },\r\n};\r\n\r\n/** Gli slot di ogni collezione. Aggiungere un nodo significa aggiungere una riga qui. */\r\nexport const DPE_SOURCE_SLOTS: {\r\n readonly [K in DpeNodeCollectionName]: readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];\r\n} = {\r\n // Le sorgenti sono i punti d'ingresso del grafo: non riferiscono nessun nodo a monte.\r\n dataSources: [] as readonly DpeSourceSlot<DataSourceNode>[],\r\n filters: [single<FilterNode, 'sourceName'>('source', 'sourceName')],\r\n joins: [\r\n single<JoinNode, 'primarySourceName'>('primary', 'primarySourceName'),\r\n single<JoinNode, 'secondarySourceName'>('secondary', 'secondarySourceName'),\r\n JOIN_RESULT_FIELDS_SLOT,\r\n ],\r\n aggregates: [single<AggregateNode, 'sourceName'>('source', 'sourceName')],\r\n transforms: [single<TransformNode, 'sourceName'>('source', 'sourceName')],\r\n appends: [list<AppendNode, 'sources'>('sources', 'sources')],\r\n hierarchyPaths: [single<HierarchyPathNode, 'sourceName'>('source', 'sourceName')],\r\n forecasts: [single<ForecastNode, 'sourceName'>('source', 'sourceName')],\r\n customNodes: [list<CustomNode, 'sources'>('sources', 'sources')],\r\n writebacks: [single<WritebackNode, 'sourceName'>('source', 'sourceName')],\r\n atomicWritebacks: [ATOMIC_RELATIONSHIPS_SLOT],\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Lettura del documento\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Un nodo con la collezione da cui viene: senza, non si sa quali slot leggere. */\r\nexport interface DpeLocatedNode<K extends DpeNodeCollectionName = DpeNodeCollectionName> {\r\n collection: K;\r\n index: number;\r\n node: DpeNodeCollectionMap[K];\r\n}\r\n\r\n/** Tutti i nodi, nell'ordine delle collezioni (sorgenti -> trasformazioni -> sink). */\r\nexport function dpeAllNodes(definition: DpeDefinition): DpeLocatedNode[] {\r\n const result: DpeLocatedNode[] = [];\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = (definition[collection] ?? []) as DpeAnyNode[];\r\n nodes.forEach((node, index) => {\r\n result.push({ collection, index, node } as DpeLocatedNode);\r\n });\r\n }\r\n return result;\r\n}\r\n\r\nexport function dpeFindNode(definition: DpeDefinition, nodeName: string): DpeLocatedNode | undefined {\r\n return dpeAllNodes(definition).find((located) => located.node.name === nodeName);\r\n}\r\n\r\nexport interface DpeSourceReference {\r\n /** Nodo che contiene il riferimento (la destinazione dell'arco). */\r\n targetNodeName: string;\r\n collection: DpeNodeCollectionName;\r\n slot: string;\r\n /** Presente solo sugli slot a lista. */\r\n index?: number;\r\n isEdge: boolean;\r\n /** Nome riferito; assente quando lo slot e' vuoto (nodo non collegato). */\r\n sourceName?: string;\r\n}\r\n\r\n/** I riferimenti di un singolo nodo, in ordine di slot. */\r\nexport function dpeNodeSourceReferences(located: DpeLocatedNode): DpeSourceReference[] {\r\n const slots = DPE_SOURCE_SLOTS[located.collection] as readonly DpeSourceSlot<DpeAnyNode>[];\r\n const references: DpeSourceReference[] = [];\r\n for (const slot of slots) {\r\n const names = slot.read(located.node);\r\n const isPositional = names.length > 1 || slotIsPositional(slot);\r\n names.forEach((name, index) => {\r\n references.push({\r\n targetNodeName: located.node.name,\r\n collection: located.collection,\r\n slot: slot.slot,\r\n index: isPositional ? index : undefined,\r\n isEdge: slot.isEdge,\r\n sourceName: name === '' ? undefined : name,\r\n });\r\n });\r\n }\r\n return references;\r\n}\r\n\r\n/**\r\n * Uno slot a lista porta l'indice **anche** quando contiene un solo elemento: l'id della\r\n * porta e dell'arco non deve cambiare forma quando l'utente aggiunge la seconda sorgente a\r\n * un `AppendNode`, altrimenti la selezione dell'arco salta e la posizione della porta cambia\r\n * sotto il puntatore.\r\n */\r\nfunction slotIsPositional(slot: DpeSourceSlot<DpeAnyNode>): boolean {\r\n return slot.slot === 'sources' || slot.slot === 'resultFields' || slot.slot === 'relationships';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Archi\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface DpeGraphNode {\r\n id: string;\r\n name: string;\r\n collection: DpeNodeCollectionName;\r\n outputPortId: string;\r\n}\r\n\r\nexport interface DpeGraphEdge {\r\n id: string;\r\n /** Nome del nodo a monte, come scritto nel documento. */\r\n fromNodeName: string;\r\n toNodeName: string;\r\n slot: string;\r\n index?: number;\r\n fromPortId: string;\r\n toPortId: string;\r\n /**\r\n * `false` quando il nome a monte non corrisponde a nessun nodo della definizione. L'arco\r\n * **si mostra comunque**: la topologia mostrata e' quella reale, e un riferimento rotto va\r\n * visto, non nascosto. La diagnostica che lo qualifica (`DPE_REF_UNKNOWN_NODE`) arriva dal\r\n * backend.\r\n */\r\n isResolved: boolean;\r\n}\r\n\r\nexport interface DpeGraph {\r\n nodes: DpeGraphNode[];\r\n edges: DpeGraphEdge[];\r\n}\r\n\r\n/**\r\n * Deriva nodi e archi dalla definizione, per riferimento di nome. Funzione pura: nessuna\r\n * lettura di stato, nessuna dipendenza da Angular, testabile senza DOM.\r\n */\r\nexport function dpeBuildGraph(definition: DpeDefinition): DpeGraph {\r\n const located = dpeAllNodes(definition);\r\n const known = new Set(located.map((entry) => entry.node.name));\r\n\r\n const nodes: DpeGraphNode[] = located.map((entry) => ({\r\n id: dpeNodeId(entry.node.name),\r\n name: entry.node.name,\r\n collection: entry.collection,\r\n outputPortId: dpeOutputPortId(entry.node.name),\r\n }));\r\n\r\n const edges: DpeGraphEdge[] = [];\r\n for (const entry of located) {\r\n for (const reference of dpeNodeSourceReferences(entry)) {\r\n if (!reference.isEdge || reference.sourceName === undefined) {\r\n continue;\r\n }\r\n edges.push({\r\n id: dpeEdgeId(reference.targetNodeName, reference.slot, reference.index),\r\n fromNodeName: reference.sourceName,\r\n toNodeName: reference.targetNodeName,\r\n slot: reference.slot,\r\n index: reference.index,\r\n fromPortId: dpeOutputPortId(reference.sourceName),\r\n toPortId: dpeInputPortId(reference.targetNodeName, reference.slot, reference.index),\r\n isResolved: known.has(reference.sourceName),\r\n });\r\n }\r\n }\r\n\r\n return { nodes, edges };\r\n}\r\n\r\n/** Le porte di ingresso di un nodo, nell'ordine in cui vanno disegnate. */\r\nexport interface DpeInputPort {\r\n id: string;\r\n slot: string;\r\n index?: number;\r\n /** Nome collegato, assente se la porta e' libera. */\r\n sourceName?: string;\r\n}\r\n\r\nexport function dpeInputPorts(located: DpeLocatedNode): DpeInputPort[] {\r\n return dpeNodeSourceReferences(located)\r\n .filter((reference) => reference.isEdge)\r\n .map((reference) => ({\r\n id: dpeInputPortId(reference.targetNodeName, reference.slot, reference.index),\r\n slot: reference.slot,\r\n index: reference.index,\r\n sourceName: reference.sourceName,\r\n }));\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Riscrittura dei riferimenti\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Riscrive un riferimento in **uno** slot di **un** nodo. E' il mattone di `connect` e\r\n * `disconnect` dello store: passando `undefined` la porta torna libera.\r\n */\r\nexport function dpeWriteSourceReference<K extends DpeNodeCollectionName>(\r\n collection: K,\r\n node: DpeNodeCollectionMap[K],\r\n slotName: string,\r\n index: number | undefined,\r\n sourceName: string | undefined,\r\n): DpeNodeCollectionMap[K] {\r\n const slots = DPE_SOURCE_SLOTS[collection] as readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];\r\n const slot = slots.find((candidate) => candidate.slot === slotName);\r\n if (!slot) {\r\n return node;\r\n }\r\n const names = slot.read(node).slice();\r\n const position = index ?? 0;\r\n // Uno slot a lista puo' non avere ancora la posizione richiesta: la si apre, altrimenti\r\n // collegare la seconda sorgente di un Append non avrebbe nessun effetto e nessun errore.\r\n while (names.length <= position) {\r\n names.push(undefined);\r\n }\r\n names[position] = sourceName;\r\n return slot.write(node, names);\r\n}\r\n\r\n/**\r\n * **Rinominare un nodo e' un refactoring globale, non locale** (**I5**).\r\n *\r\n * Questa e' l'unica funzione che rinomina: aggiorna il `name` del nodo e **ogni** riferimento\r\n * a valle, passando dall'unico elenco di slot — `sourceName`, `sources`,\r\n * `primarySourceName`/`secondarySourceName`, i `sourceName` dei `JoinResultField` e i nomi\r\n * dentro i gruppi atomici. Se una collezione di riferimenti sfuggisse, il documento\r\n * diventerebbe silenziosamente incoerente: e' il difetto che questa funzione esiste per non\r\n * avere.\r\n *\r\n * Cosa **non** fa, di proposito: non rinomina gli **alias di colonna** (sono un altro spazio\r\n * di nomi) e non decide se il nuovo nome sia lecito o già usato — l'unicita' e' **I1**, la\r\n * verifica il backend.\r\n *\r\n * Il confronto e' **esatto**, non case-insensitive: `domain-model.md` dichiara il confronto\r\n * `OrdinalIgnoreCase` per gli **alias di colonna** e non dice nulla sui nomi dei nodi.\r\n * Rinominare anche le occorrenze con capitalizzazione diversa significherebbe, se il backend\r\n * risolvesse i nomi in modo esatto, riscrivere il riferimento a un nodo **diverso**.\r\n */\r\nexport function dpeRenameNode(\r\n definition: DpeDefinition,\r\n oldName: string,\r\n newName: string,\r\n): DpeDefinition {\r\n if (oldName === newName) {\r\n return definition;\r\n }\r\n\r\n const next: DpeDefinition = { ...definition };\r\n\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = definition[collection] as DpeAnyNode[] | undefined;\r\n if (!nodes || nodes.length === 0) {\r\n continue;\r\n }\r\n const slots = DPE_SOURCE_SLOTS[collection] as readonly DpeSourceSlot<DpeAnyNode>[];\r\n const rewritten = nodes.map((node) => {\r\n let result = node;\r\n for (const slot of slots) {\r\n const names = slot.read(result);\r\n if (!names.some((name) => name === oldName)) {\r\n continue;\r\n }\r\n result = slot.write(\r\n result,\r\n names.map((name) => (name === oldName ? newName : name)),\r\n );\r\n }\r\n if (result.name === oldName) {\r\n result = { ...result, name: newName };\r\n }\r\n return result;\r\n });\r\n // L'assegnazione per nome di collezione non e' esprimibile in modo tipato senza un cast:\r\n // la mappa collezione -> tipo di nodo esiste, ma TypeScript non correla la chiave con il\r\n // valore dentro un ciclo. Il cast e' confinato a questa riga.\r\n (next as unknown as Record<string, unknown>)[collection] = rewritten;\r\n }\r\n\r\n return next;\r\n}\r\n\r\n/** Quante occorrenze toccherebbe una rinomina: serve a dirlo prima, non dopo. */\r\nexport function dpeCountReferences(definition: DpeDefinition, nodeName: string): number {\r\n let count = 0;\r\n for (const located of dpeAllNodes(definition)) {\r\n for (const reference of dpeNodeSourceReferences(located)) {\r\n if (reference.sourceName === nodeName) {\r\n count += 1;\r\n }\r\n }\r\n }\r\n return count;\r\n}\r\n","/**\r\n * Utility pure sulle diagnostiche **ricevute** dal backend: raggruppamento per nodo, gravita'\r\n * peggiore, e la distinzione fra \"da correggere\" e \"non ancora compilabile\".\r\n *\r\n * Qui non nasce nessuna diagnostica e non si giudica nessuna definizione: si legge cio' che il\r\n * backend ha detto e si decide **come renderlo**. La sola informazione interpretata e' il\r\n * `DiagnosticPath`, che il contratto pubblica in **due forme** (con nome del nodo dalla\r\n * validazione, con solo indice dalla deserializzazione): chi legge deve accettarle entrambe,\r\n * altrimenti le diagnostiche del caricamento di un file non sono navigabili.\r\n */\r\n\r\nimport { Diagnostic, DiagnosticSeverity, DPE_NODE_NOT_COMPILABLE } from '../model/dpe-diagnostics.model';\r\nimport { DpeDefinition, DpeNodeCollectionName } from '../model/dpe-definition.model';\r\nimport { dpeAllNodes } from './dpe-graph';\r\n\r\n/**\r\n * Il nodo a cui una diagnostica si riferisce, se ricavabile.\r\n *\r\n * Tre strade, nell'ordine: il nome nel primo segmento del percorso; l'argomento canonico\r\n * `node`; l'indice del primo segmento risolto nella collezione corrispondente della\r\n * definizione — che e' il caso della deserializzazione, dove i nomi non sono ancora noti.\r\n * Senza la terza, un `filters[0].sourceName` resterebbe una riga non cliccabile.\r\n */\r\nexport function dpeDiagnosticNodeName(\r\n diagnostic: Diagnostic,\r\n definition?: DpeDefinition,\r\n): string | undefined {\r\n const first = diagnostic.path?.segments?.[0];\r\n if (first?.name) {\r\n return first.name;\r\n }\r\n const fromArguments = diagnostic.arguments?.['node'];\r\n if (fromArguments) {\r\n return fromArguments;\r\n }\r\n if (!definition || !first?.collection || first.index === undefined) {\r\n return undefined;\r\n }\r\n const collection = definition[first.collection as DpeNodeCollectionName];\r\n if (!Array.isArray(collection)) {\r\n return undefined;\r\n }\r\n return collection[first.index]?.name;\r\n}\r\n\r\n/** Il campo in causa, per evidenziarlo nell'ispettore. */\r\nexport function dpeDiagnosticField(diagnostic: Diagnostic): string | undefined {\r\n return diagnostic.path?.field;\r\n}\r\n\r\n/**\r\n * `true` per l'unico codice che significa \"hai fatto bene, siamo noi\" (**I10**, ADR 0005):\r\n * `Forecast`, `CustomNode`, costrutto non supportato dal dialetto scelto. Non va mescolato\r\n * con i `DPE_MODEL_*`, che l'utente deve correggere.\r\n */\r\nexport function dpeIsNotCompilable(diagnostic: Diagnostic): boolean {\r\n return diagnostic.code === DPE_NODE_NOT_COMPILABLE;\r\n}\r\n\r\n/**\r\n * `true` quando la diagnostica riguarda le **capacita' del dialetto** e non la definizione in\r\n * se': l'interfaccia deve dire «questo dialetto non lo supporta», perche' lo stesso documento\r\n * su un altro dialetto sarebbe compilabile.\r\n */\r\nexport function dpeIsDialectDiagnostic(diagnostic: Diagnostic): boolean {\r\n return diagnostic.code.startsWith('DPE_DIALECT_');\r\n}\r\n\r\nexport interface DpeNodeDiagnostics {\r\n /** Diagnostiche ancorate al nodo, nell'ordine ricevuto (**I6**: l'elenco e' esaustivo). */\r\n diagnostics: Diagnostic[];\r\n /** La gravita' peggiore fra quelle presenti. */\r\n severity?: DiagnosticSeverity;\r\n /**\r\n * Il nodo e' **valido ma non compilabile**: stato distinto da \"non valido\", e l'unico per\r\n * cui la UI non deve chiedere all'utente di correggere niente.\r\n */\r\n isNotCompilable: boolean;\r\n}\r\n\r\nconst SEVERITY_RANK: Readonly<Record<DiagnosticSeverity, number>> = {\r\n Info: 1,\r\n Warning: 2,\r\n Error: 3,\r\n};\r\n\r\nexport function dpeWorstSeverity(diagnostics: readonly Diagnostic[]): DiagnosticSeverity | undefined {\r\n let worst: DiagnosticSeverity | undefined;\r\n for (const diagnostic of diagnostics) {\r\n if (!worst || SEVERITY_RANK[diagnostic.severity] > SEVERITY_RANK[worst]) {\r\n worst = diagnostic.severity;\r\n }\r\n }\r\n return worst;\r\n}\r\n\r\n/** Raggruppa per nodo. Le diagnostiche non ancorabili a un nodo non si perdono: vedi sotto. */\r\nexport function dpeGroupDiagnosticsByNode(\r\n diagnostics: readonly Diagnostic[],\r\n definition?: DpeDefinition,\r\n): Map<string, DpeNodeDiagnostics> {\r\n const grouped = new Map<string, DpeNodeDiagnostics>();\r\n for (const diagnostic of diagnostics) {\r\n const nodeName = dpeDiagnosticNodeName(diagnostic, definition);\r\n if (nodeName === undefined) {\r\n continue;\r\n }\r\n const entry = grouped.get(nodeName) ?? { diagnostics: [], isNotCompilable: false };\r\n entry.diagnostics.push(diagnostic);\r\n entry.isNotCompilable = entry.isNotCompilable || dpeIsNotCompilable(diagnostic);\r\n entry.severity = dpeWorstSeverity(entry.diagnostics);\r\n grouped.set(nodeName, entry);\r\n }\r\n return grouped;\r\n}\r\n\r\n/**\r\n * Le diagnostiche che **non** appartengono a nessun nodo (radice, parametri, sequenza dei\r\n * writeback, grafo intero). Esistono come funzione a se' perche' il pannello deve mostrarle:\r\n * un `DPE_GRAPH_NO_WRITEBACK` che scompare perche' non ha un nodo a cui attaccarsi sarebbe la\r\n * diagnostica piu' importante di tutte a non arrivare all'utente.\r\n */\r\nexport function dpeDefinitionLevelDiagnostics(\r\n diagnostics: readonly Diagnostic[],\r\n definition?: DpeDefinition,\r\n): Diagnostic[] {\r\n return diagnostics.filter(\r\n (diagnostic) => dpeDiagnosticNodeName(diagnostic, definition) === undefined,\r\n );\r\n}\r\n\r\n/** Testo leggibile del percorso, per la riga del pannello. */\r\nexport function dpeDiagnosticLocationLabel(\r\n diagnostic: Diagnostic,\r\n definition?: DpeDefinition,\r\n): string {\r\n const node = dpeDiagnosticNodeName(diagnostic, definition);\r\n const segments = diagnostic.path?.segments ?? [];\r\n const tail = segments\r\n .slice(1)\r\n .map((segment) => {\r\n const index = segment.index === undefined ? '' : `[${segment.index}]`;\r\n return `${segment.collection ?? ''}${segment.name ? `/${segment.name}` : index}`;\r\n })\r\n .filter((part) => part.length > 0);\r\n const field = diagnostic.path?.field;\r\n return [node ?? 'definizione', ...tail, field].filter(Boolean).join(' › ');\r\n}\r\n\r\n/** I nomi dei nodi presenti nella definizione: serve a chi naviga dal pannello al canvas. */\r\nexport function dpeKnownNodeNames(definition: DpeDefinition): Set<string> {\r\n return new Set(dpeAllNodes(definition).map((located) => located.node.name));\r\n}\r\n","/**\r\n * Le coordinate di un nodo sul canvas — ADR 0013.\r\n *\r\n * Vivono in `extensionData` sotto la chiave namespaced `dpe:layout`, forma `{x, y}`. Il\r\n * backend le conserva senza interpretarle (**I7**), la validazione non le guarda, il\r\n * compilatore non le vede: l'unico livello che gli da' significato e' l'editor.\r\n *\r\n * Due regole dell'ADR sono implementate qui, e sono le sole che contano:\r\n *\r\n * - le coordinate sono **opzionali**: una definizione scritta a mano non le ha e resta\r\n * valida; in loro assenza si esegue dagre;\r\n * - un `dpe:layout` **malformato o parziale si ignora**. Un documento arrivato da un'altra\r\n * versione non deve poter rompere il canvas, e \"meta' coordinata\" non e' una posizione:\r\n * accettarla metterebbe il nodo a `x` giusta e `y` zero, cioe' in un posto che nessuno ha\r\n * scelto.\r\n */\r\n\r\nimport { DpeAnyNode, DpeExtensionData } from '../model/dpe-definition.model';\r\n\r\n/** La chiave e' namespaced perche' `extensionData` e' anche dove atterrano i campi futuri. */\r\nexport const DPE_LAYOUT_KEY = 'dpe:layout';\r\n\r\nexport interface DpeNodePosition {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/** Legge la posizione, oppure `undefined` se assente o non utilizzabile. */\r\nexport function dpeReadNodePosition(node: DpeAnyNode): DpeNodePosition | undefined {\r\n const raw = node.extensionData?.[DPE_LAYOUT_KEY];\r\n if (raw === null || typeof raw !== 'object') {\r\n return undefined;\r\n }\r\n const candidate = raw as { x?: unknown; y?: unknown };\r\n // `Number.isFinite` e non `typeof === 'number'`: `NaN` e `Infinity` sono numeri per\r\n // TypeScript e coordinate impossibili per il canvas, dove finirebbero in una trasform CSS\r\n // invalida — il nodo semplicemente non si vede, senza nessun errore.\r\n if (!Number.isFinite(candidate.x) || !Number.isFinite(candidate.y)) {\r\n return undefined;\r\n }\r\n return { x: candidate.x as number, y: candidate.y as number };\r\n}\r\n\r\n/** Scrive la posizione producendo un nuovo nodo: il documento resta immutabile. */\r\nexport function dpeWriteNodePosition<TNode extends DpeAnyNode>(\r\n node: TNode,\r\n position: DpeNodePosition,\r\n): TNode {\r\n const extensionData: DpeExtensionData = {\r\n ...(node.extensionData ?? {}),\r\n [DPE_LAYOUT_KEY]: { x: Math.round(position.x), y: Math.round(position.y) },\r\n };\r\n return { ...node, extensionData };\r\n}\r\n\r\n/** Vero quando **tutti** i nodi hanno una posizione: se no, il canvas rifa' il layout. */\r\nexport function dpeHasCompleteLayout(nodes: readonly DpeAnyNode[]): boolean {\r\n return nodes.length > 0 && nodes.every((node) => dpeReadNodePosition(node) !== undefined);\r\n}\r\n","/**\r\n * Catalogo delle categorie di nodo: etichetta italiana, collezione JSON di appartenenza,\r\n * numero di sorgenti ammesse.\r\n *\r\n * **Descrittivo, non normativo.** Serve alla palette e alle etichette dell'interfaccia. Non\r\n * e' validazione: che un `AppendNode` con una sola sorgente sia sbagliato lo dice il backend,\r\n * non questo file, e i due non devono mai diventare due fonti di verita' in disaccordo. I\r\n * conteggi qui sotto servono a decidere **quante porte disegnare**, che e' una domanda di\r\n * rendering.\r\n */\r\n\r\nimport { DpeNodeCollectionName } from '../model/dpe-definition.model';\r\n\r\nexport interface DpeNodeCategory {\r\n /** Collezione JSON della radice: e' anche la chiave con cui si legge il documento. */\r\n collection: DpeNodeCollectionName;\r\n /** Etichetta breve, per la palette e per l'intestazione della card sul canvas. */\r\n label: string;\r\n /** Una riga di spiegazione, per il tooltip della palette. */\r\n description: string;\r\n /** Numero minimo di sorgenti che il nodo dichiara (0 per i punti d'ingresso). */\r\n minSources: number;\r\n /** Numero massimo, `undefined` = illimitato (`Append`, `CustomNode`). */\r\n maxSources?: number;\r\n /** Vero per i punti d'ingresso del grafo. */\r\n isSource: boolean;\r\n /** Vero per i sink: producono l'artefatto, non uno schema. */\r\n isSink: boolean;\r\n /**\r\n * Vero dove il backend rifiuta la compilazione pur accettando il modello (**I10**): la UI\r\n * deve poter avvisare **prima** che l'utente costruisca la pipeline intorno a un nodo che\r\n * non arrivera' all'SQL. Non e' una regola di dominio riprodotta: e' l'informazione che\r\n * `docs/domain-model.md` dichiara esplicitamente per queste due categorie, e la\r\n * diagnostica autorevole resta `DPE_NODE_NOT_COMPILABLE` del backend.\r\n */\r\n isNotCompilableInV1: boolean;\r\n}\r\n\r\nexport const DPE_NODE_CATEGORIES: readonly DpeNodeCategory[] = [\r\n {\r\n collection: 'dataSources',\r\n label: 'Sorgente',\r\n description: 'Punto d’ingresso: tabella del provider di metadati, CSV o dataset esterno.',\r\n minSources: 0,\r\n maxSources: 0,\r\n isSource: true,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'filters',\r\n label: 'Filtro',\r\n description: 'Seleziona le righe con criteri combinati, oppure con un filtro dinamico da parametro.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'joins',\r\n label: 'Join',\r\n description: 'Unisce due sorgenti su una o piu’ chiavi; lo schema di uscita e’ esplicito.',\r\n minSources: 2,\r\n maxSources: 2,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'aggregates',\r\n label: 'Aggregazione',\r\n description: 'Raggruppa e calcola funzioni di aggregazione; senza raggruppamento produce una riga.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'transforms',\r\n label: 'Trasformazione',\r\n description: 'Aggiunge colonne calcolate, ne elimina, oppure calcola valori relativi a una partizione.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'appends',\r\n label: 'Unione',\r\n description: 'Impila N sorgenti; con schemi disgiunti le colonne mancanti diventano nulle.',\r\n minSources: 2,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'hierarchyPaths',\r\n label: 'Percorso gerarchico',\r\n description: 'Risale una gerarchia padre/figlio e produce la colonna di percorso; richiede CTE ricorsive.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'forecasts',\r\n label: 'Previsione',\r\n description: 'Modellata per intero ma non traducibile in SQL nella versione 1.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: true,\r\n },\r\n {\r\n collection: 'customNodes',\r\n label: 'Nodo personalizzato',\r\n description: 'Estensione esterna con schema di uscita dichiarato; non traducibile in SQL nella versione 1.',\r\n minSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: true,\r\n },\r\n {\r\n collection: 'writebacks',\r\n label: 'Scrittura',\r\n description: 'Sink: produce l’istruzione SQL per l’host, oppure un file JSON o CSV.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: true,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'atomicWritebacks',\r\n label: 'Gruppo atomico',\r\n description: 'Dichiara che alcune scritture vanno applicate dall’host nella stessa transazione.',\r\n minSources: 0,\r\n isSource: false,\r\n isSink: true,\r\n isNotCompilableInV1: false,\r\n },\r\n];\r\n\r\nconst BY_COLLECTION = new Map<DpeNodeCollectionName, DpeNodeCategory>(\r\n DPE_NODE_CATEGORIES.map((category) => [category.collection, category]),\r\n);\r\n\r\nexport function dpeNodeCategory(collection: DpeNodeCollectionName): DpeNodeCategory {\r\n const category = BY_COLLECTION.get(collection);\r\n if (!category) {\r\n // Non raggiungibile: la mappa copre `DpeNodeCollectionName` per costruzione. Il ripiego\r\n // esiste perche' aggiungere una collezione al modello senza aggiungerla qui non deve\r\n // produrre una card senza etichetta e senza spiegazione.\r\n return {\r\n collection,\r\n label: collection,\r\n description: '',\r\n minSources: 0,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n };\r\n }\r\n return category;\r\n}\r\n\r\n/** Nomi dei dialetti per il selettore. La libreria conosce **solo** il nome (ADR 0009). */\r\nexport const DPE_DIALECT_LABELS: Readonly<Record<string, string>> = {\r\n Sqlite: 'SQLite',\r\n SqlServer: 'SQL Server',\r\n PostgreSql: 'PostgreSQL',\r\n Oracle: 'Oracle',\r\n};\r\n","/**\r\n * Creazione di un nodo nuovo: nome candidato e valori iniziali per categoria.\r\n *\r\n * Non e' validazione e non e' dominio. Serve a una cosa sola: un nodo appena rilasciato sul\r\n * canvas deve essere **rappresentabile** e distinguibile, cioe' avere un nome e un'etichetta.\r\n * Tutto il resto lo compila l'utente nell'ispettore, e cosa sia obbligatorio lo dice il\r\n * backend.\r\n *\r\n * Il nome candidato e' unico rispetto ai nomi già presenti con confronto **esatto**\r\n * (`contracts.md` §2: unicita' verificata `OrdinalIgnoreCase`, risoluzione `Ordinal`). Qui il\r\n * confronto e' insensibile al caso di proposito: proporre `Filtro2` accanto a un `filtro2`\r\n * esistente creerebbe un `DPE_MODEL_NAME_DUPLICATE` a nome dell'editor, non dell'utente.\r\n */\r\n\r\nimport {\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n} from '../model/dpe-definition.model';\r\nimport { dpeAllNodes } from './dpe-graph';\r\nimport { dpeNodeCategory } from './dpe-node-catalog';\r\n\r\n/** Radice del nome proposto per categoria: identificatori, quindi senza spazi ne' accenti. */\r\nconst NAME_STEM: Readonly<Record<DpeNodeCollectionName, string>> = {\r\n dataSources: 'Sorgente',\r\n filters: 'Filtro',\r\n joins: 'Join',\r\n aggregates: 'Aggregazione',\r\n transforms: 'Trasformazione',\r\n appends: 'Unione',\r\n hierarchyPaths: 'Gerarchia',\r\n forecasts: 'Previsione',\r\n customNodes: 'NodoCustom',\r\n writebacks: 'Scrittura',\r\n atomicWritebacks: 'GruppoAtomico',\r\n};\r\n\r\n/** Il primo nome libero della forma `<radice><n>`. */\r\nexport function dpeProposeNodeName(\r\n definition: DpeDefinition,\r\n collection: DpeNodeCollectionName,\r\n): string {\r\n const used = new Set(dpeAllNodes(definition).map((located) => located.node.name.toLowerCase()));\r\n const stem = NAME_STEM[collection];\r\n let index = 1;\r\n while (used.has(`${stem}${index}`.toLowerCase())) {\r\n index += 1;\r\n }\r\n return `${stem}${index}`;\r\n}\r\n\r\n/**\r\n * Il nodo iniziale di una categoria. I campi obbligatori senza un valore sensato restano\r\n * **assenti**, non riempiti con un segnaposto: un `tableName` finto passerebbe la forma e\r\n * fallirebbe sul provider di metadati con un errore che l'utente non ha causato.\r\n */\r\nexport function dpeCreateNode<K extends DpeNodeCollectionName>(\r\n definition: DpeDefinition,\r\n collection: K,\r\n): DpeNodeCollectionMap[K] {\r\n const name = dpeProposeNodeName(definition, collection);\r\n const label = `${dpeNodeCategory(collection).label} ${name.replace(/^\\D+/, '')}`;\r\n const base = { name, label };\r\n\r\n switch (collection) {\r\n case 'dataSources':\r\n return { ...base, kind: 'Table', fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'joins':\r\n return { ...base, kind: 'Inner', keys: [], fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'aggregates':\r\n return { ...base, fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'transforms':\r\n return { ...base, kind: 'Expression', expressionFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'appends':\r\n // Due posizioni vuote: un'unione nasce con due ingressi da collegare, ed e' anche cio'\r\n // che fa comparire due porte sul canvas invece di nessuna.\r\n return { ...base, sources: ['', ''] } as unknown as DpeNodeCollectionMap[K];\r\n case 'customNodes':\r\n return { ...base, sources: [''], extensionName: '', outputFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'forecasts':\r\n return { ...base, aggregationFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'writebacks':\r\n return {\r\n ...base,\r\n target: 'Database',\r\n operation: 'Insert',\r\n sequence: dpeProposeWritebackSequence(definition),\r\n fields: [],\r\n } as unknown as DpeNodeCollectionMap[K];\r\n case 'atomicWritebacks':\r\n return {\r\n ...base,\r\n sequence: dpeProposeWritebackSequence(definition),\r\n relationships: [],\r\n } as unknown as DpeNodeCollectionMap[K];\r\n default:\r\n return base as unknown as DpeNodeCollectionMap[K];\r\n }\r\n}\r\n\r\n/**\r\n * La sequenza dei sink e' univoca fra writeback e gruppi atomici: si propone la prima libera.\r\n * L'unicita' la verifica il backend (`DPE_WRITEBACK_SEQUENCE_DUPLICATE`) — questo e' solo un\r\n * valore iniziale che non collide, non un controllo.\r\n */\r\nexport function dpeProposeWritebackSequence(definition: DpeDefinition): number {\r\n const used = new Set<number>();\r\n for (const node of [...(definition.writebacks ?? []), ...(definition.atomicWritebacks ?? [])]) {\r\n used.add(node.sequence);\r\n }\r\n let sequence = 1;\r\n while (used.has(sequence)) {\r\n sequence += 1;\r\n }\r\n return sequence;\r\n}\r\n\r\n/** Etichetta di sintesi mostrata sulla card del nodo, sotto il nome. */\r\nexport function dpeNodeSubtitle(collection: DpeNodeCollectionName, node: DpeAnyNode): string | null {\r\n const record = node as unknown as Record<string, unknown>;\r\n switch (collection) {\r\n case 'dataSources':\r\n return (record['tableName'] as string) || (record['externalDatasetName'] as string) || null;\r\n case 'joins':\r\n return (record['kind'] as string) || null;\r\n case 'transforms':\r\n return (record['kind'] as string) || null;\r\n case 'aggregates': {\r\n const fields = (record['fields'] as unknown[] | undefined)?.length ?? 0;\r\n return fields ? `${fields} ${fields === 1 ? 'funzione' : 'funzioni'}` : null;\r\n }\r\n case 'filters':\r\n return record['isDynamic'] === true ? 'dinamico' : (record['condition'] as string) || null;\r\n case 'writebacks': {\r\n const target = record['target'] as string | undefined;\r\n const table = record['tableName'] as string | undefined;\r\n return [target, table].filter(Boolean).join(' · ') || null;\r\n }\r\n case 'atomicWritebacks': {\r\n const relationships = (record['relationships'] as unknown[] | undefined)?.length ?? 0;\r\n return relationships ? `${relationships} relazioni` : null;\r\n }\r\n default:\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Lo stato dell'editor: la definizione in memoria e' **la fonte di verita'**.\r\n *\r\n * `@Injectable()` **senza `providedIn`**: e' un provider del componente radice dell'editor,\r\n * non della root. Due editor sulla stessa pagina devono poter editare due definizioni\r\n * indipendenti, e con un servizio in root ne condividerebbero una — compresi undo/redo e\r\n * selezione.\r\n *\r\n * Stato **immutabile e unidirezionale**: ogni mutazione produce un nuovo valore della\r\n * definizione, nessuno muta l'oggetto in luogo. Da lì viene gratis l'undo/redo (istantanee\r\n * JSON), che non e' una funzionalita' aggiunta dopo ma una conseguenza.\r\n *\r\n * Cosa **non** fa questo store, e non e' una dimenticanza: non valida, non calcola schemi,\r\n * non risolve riferimenti, non sa cosa un dialetto supporti. Diagnostiche, schemi, ordine di\r\n * esecuzione e sequenza dei writeback **arrivano dal backend** e qui si depositano\r\n * (`applyValidateResult`). L'unica logica presente e' strutturale: dove vivono i riferimenti\r\n * e come si riscrivono, che sta in `dpe-graph.ts`.\r\n */\r\n\r\nimport { Injectable, computed, signal } from '@angular/core';\r\n\r\nimport {\r\n DPE_NODE_COLLECTIONS,\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n SqlDialectKind,\r\n} from '../model/dpe-definition.model';\r\nimport { Diagnostic } from '../model/dpe-diagnostics.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeNodeSchemaInfo,\r\n DpeValidateResult,\r\n DpeWritebackStep,\r\n} from '../model/dpe-api.model';\r\nimport {\r\n DpeGraph,\r\n dpeAllNodes,\r\n dpeBuildGraph,\r\n dpeCountReferences,\r\n dpeFindNode,\r\n dpeRenameNode,\r\n dpeWriteSourceReference,\r\n} from './dpe-graph';\r\nimport {\r\n DpeNodeDiagnostics,\r\n dpeDefinitionLevelDiagnostics,\r\n dpeGroupDiagnosticsByNode,\r\n} from './dpe-diagnostics.util';\r\nimport { DpeNodePosition, dpeReadNodePosition, dpeWriteNodePosition } from './dpe-node-layout';\r\nimport { dpeCreateNode } from './dpe-node-factory';\r\n\r\n/** Profondita' della cronologia: oltre, le istantanee piu' vecchie si buttano. */\r\nconst HISTORY_LIMIT = 100;\r\n\r\n/** Una definizione vuota ma **leggibile**: `formatVersion` e `dialect` non sono opzionali. */\r\nexport function dpeEmptyDefinition(\r\n name: string,\r\n label: string,\r\n dialect: SqlDialectKind,\r\n): DpeDefinition {\r\n return { formatVersion: 1, name, label, dialect };\r\n}\r\n\r\n@Injectable()\r\nexport class DpeDocumentStore {\r\n private readonly _definition = signal<DpeDefinition>(dpeEmptyDefinition('', '', 'Sqlite'));\r\n private readonly _validateResult = signal<DpeValidateResult | undefined>(undefined);\r\n private readonly _compileResult = signal<DpeCompileResult | undefined>(undefined);\r\n /**\r\n * I nodi selezionati, in ordine di gesto. E' una **lista** e non un nome singolo perche' il\r\n * canvas sa selezionare piu' nodi (riquadro, `Ctrl+A`) e trascinarli insieme: tenere qui un solo\r\n * nome costringerebbe la libreria a conservare gli altri, cioe' a essere di nuovo autorevole\r\n * sulla selezione.\r\n */\r\n private readonly _selectedNodeNames = signal<readonly string[]>([]);\r\n private readonly _past = signal<readonly string[]>([]);\r\n private readonly _future = signal<readonly string[]>([]);\r\n /**\r\n * Istantanea di riferimento: l'ultimo stato **salvato**. Non e' un contatore di operazioni.\r\n * Contare le mutazioni sembra equivalente e non lo e': dopo un `undo` il contatore sale, cioe'\r\n * dichiara piu' modifiche di prima proprio quando l'utente ne ha disfatta una. Serve a decidere\r\n * se salvare, quindi deve rispondere alla domanda giusta — \"differisce da cio' che e' salvato?\"\r\n * — e tornare a \"no\" quando si annulla fino allo stato di partenza.\r\n */\r\n private readonly _savedSnapshot = signal<string>(\r\n JSON.stringify(dpeEmptyDefinition('', '', 'Sqlite')),\r\n );\r\n\r\n /** La definizione corrente: unica fonte di verita' per canvas, ispettori e pannelli. */\r\n readonly definition = this._definition.asReadonly();\r\n\r\n /** Nodi e archi derivati dalla definizione. Ricalcolati solo quando la definizione cambia. */\r\n readonly graph = computed<DpeGraph>(() => dpeBuildGraph(this._definition()));\r\n\r\n readonly selectedNodeNames = this._selectedNodeNames.asReadonly();\r\n\r\n /** Insieme dei selezionati: il canvas lo interroga una volta per nodo a ogni render. */\r\n readonly selectedNodeNameSet = computed<ReadonlySet<string>>(\r\n () => new Set(this._selectedNodeNames()),\r\n );\r\n\r\n /**\r\n * Il nodo che l'ispettore mostra: il **primo** della selezione. Un ispettore per piu' nodi\r\n * insieme mostrerebbe campi che appartengono a nodi diversi, che e' peggio di non mostrarne.\r\n */\r\n readonly selectedNodeName = computed<string | undefined>(() => this._selectedNodeNames().at(0));\r\n\r\n readonly selectedNode = computed<DpeAnyNode | undefined>(() => {\r\n const name = this.selectedNodeName();\r\n return name === undefined ? undefined : dpeFindNode(this._definition(), name)?.node;\r\n });\r\n\r\n // --- cio' che arriva dal backend ------------------------------------------\r\n\r\n readonly validateResult = this._validateResult.asReadonly();\r\n readonly compileResult = this._compileResult.asReadonly();\r\n\r\n readonly diagnostics = computed<readonly Diagnostic[]>(\r\n () => this._validateResult()?.diagnostics ?? [],\r\n );\r\n\r\n readonly schemas = computed<readonly DpeNodeSchemaInfo[]>(\r\n () => this._validateResult()?.schemas ?? [],\r\n );\r\n\r\n readonly executionOrder = computed<readonly string[]>(\r\n () => this._validateResult()?.executionOrder ?? [],\r\n );\r\n\r\n readonly writebackSequence = computed<readonly DpeWritebackStep[]>(\r\n () => this._validateResult()?.writebackSequence ?? [],\r\n );\r\n\r\n /** Schema per nome di nodo: la vista dello schema lo cerca per nodo, non per posizione. */\r\n readonly schemaByNode = computed<ReadonlyMap<string, DpeNodeSchemaInfo>>(() => {\r\n const map = new Map<string, DpeNodeSchemaInfo>();\r\n for (const schema of this.schemas()) {\r\n map.set(schema.nodeName, schema);\r\n }\r\n return map;\r\n });\r\n\r\n /**\r\n * Diagnostiche raggruppate per nodo, piu' quelle che **non** appartengono a nessun nodo\r\n * (radice, parametri, grafo intero): tenerle separate e' l'unico modo perche' un\r\n * `DPE_GRAPH_NO_WRITEBACK` non scompaia solo perche' non ha un nodo a cui attaccarsi.\r\n */\r\n readonly diagnosticsByNode = computed<ReadonlyMap<string, DpeNodeDiagnostics>>(() =>\r\n dpeGroupDiagnosticsByNode(this.diagnostics(), this._definition()),\r\n );\r\n\r\n readonly definitionDiagnostics = computed<readonly Diagnostic[]>(() =>\r\n dpeDefinitionLevelDiagnostics(this.diagnostics(), this._definition()),\r\n );\r\n\r\n /** Posizioni lette da `dpe:layout` (ADR 0013): assenti dove il documento non le porta. */\r\n readonly positions = computed<ReadonlyMap<string, DpeNodePosition>>(() => {\r\n const map = new Map<string, DpeNodePosition>();\r\n for (const located of dpeAllNodes(this._definition())) {\r\n const position = dpeReadNodePosition(located.node);\r\n if (position) {\r\n map.set(located.node.name, position);\r\n }\r\n }\r\n return map;\r\n });\r\n\r\n readonly canUndo = computed(() => this._past().length > 0);\r\n readonly canRedo = computed(() => this._future().length > 0);\r\n\r\n /**\r\n * Vero quando il documento differisce dall'ultimo salvataggio. Il confronto e' fra istantanee\r\n * JSON — la stessa moneta dell'undo/redo — e **non** un conteggio di differenze: un elenco di\r\n * differenze costa quanto un diff strutturale, e nessuno lo legge come numero.\r\n *\r\n * Confronto testuale, quindi sensibile all'ordine delle chiavi. Le mutazioni producono nuovi\r\n * valori per spread, che l'ordine lo conserva, e l'undo riparte dalla stessa serializzazione:\r\n * l'unico esito possibile di una divergenza d'ordine sarebbe un falso \"modificata\", cioe' un\r\n * salvataggio in piu' e mai una perdita.\r\n */\r\n readonly isDirty = computed(() => JSON.stringify(this._definition()) !== this._savedSnapshot());\r\n\r\n // -------------------------------------------------------------------------\r\n // Caricamento e risultati del backend\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Sostituisce la definizione. Azzera la cronologia: le istantanee della definizione\r\n * precedente non sono passi di quella nuova, e un undo che riportasse a un altro documento\r\n * sarebbe una perdita di dati che l'utente non ha chiesto.\r\n */\r\n load(definition: DpeDefinition): void {\r\n this._definition.set(definition);\r\n // Cio' che e' appena arrivato **e'** lo stato salvato: aprire un documento non lo sporca.\r\n this._savedSnapshot.set(JSON.stringify(definition));\r\n this._past.set([]);\r\n this._future.set([]);\r\n this._selectedNodeNames.set([]);\r\n this._validateResult.set(undefined);\r\n this._compileResult.set(undefined);\r\n }\r\n\r\n /** Deposita il risultato della validazione. Nessuna interpretazione: si mostra cio' che c'e'. */\r\n applyValidateResult(result: DpeValidateResult | undefined): void {\r\n this._validateResult.set(result);\r\n }\r\n\r\n applyCompileResult(result: DpeCompileResult | undefined): void {\r\n this._compileResult.set(result);\r\n }\r\n\r\n /**\r\n * L'ospite ha salvato: da qui in poi il riferimento e' il documento **effettivamente\r\n * persistito**, che si passa come argomento.\r\n *\r\n * Il parametro non e' un vezzo: un salvataggio e' asincrono, e nel frattempo l'utente puo'\r\n * avere continuato a scrivere. Fissando il riferimento sullo stato *corrente* si dichiarerebbe\r\n * salvato anche cio' che e' stato scritto dopo l'invio, cioe' esattamente il lavoro che si\r\n * perderebbe. Omesso, vale lo stato corrente: e' il caso di chi salva in modo sincrono.\r\n */\r\n markSaved(saved?: DpeDefinition): void {\r\n this._savedSnapshot.set(JSON.stringify(saved ?? this._definition()));\r\n }\r\n\r\n /**\r\n * **L'unico** punto che decide quale nodo e' selezionato. La selezione ha una sola fonte di\r\n * verita', come la definizione: la classe nel DOM e lo stato di selezione della libreria di\r\n * canvas ne **derivano**, non la stabiliscono. Due scritture indipendenti sullo stesso fatto\r\n * producono due nodi selezionati insieme e un utente che non sa su cosa sta agendo.\r\n */\r\n select(nodeName: string | undefined): void {\r\n this._selectedNodeNames.set(nodeName === undefined ? [] : [nodeName]);\r\n }\r\n\r\n /** Selezione multipla (riquadro, `Ctrl+A`): la lista che arriva dal gesto, senza duplicati. */\r\n selectMany(nodeNames: readonly string[]): void {\r\n this._selectedNodeNames.set(Array.from(new Set(nodeNames)));\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Mutazioni — sincrone e granulari\r\n // -------------------------------------------------------------------------\r\n\r\n /** Proprieta' della radice: etichetta, descrizione, dialetto, parametri. */\r\n patchDefinition(patch: Partial<DpeDefinition>): void {\r\n this.commit({ ...this._definition(), ...patch });\r\n }\r\n\r\n addNode<K extends DpeNodeCollectionName>(collection: K, node: DpeNodeCollectionMap[K]): void {\r\n const definition = this._definition();\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n this.commit(this.withCollection(definition, collection, [...existing, node]));\r\n }\r\n\r\n updateNode<K extends DpeNodeCollectionName>(\r\n collection: K,\r\n nodeName: string,\r\n patch: Partial<DpeNodeCollectionMap[K]>,\r\n ): void {\r\n const definition = this._definition();\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n let changed = false;\r\n const next = existing.map((node) => {\r\n if (node.name !== nodeName) {\r\n return node;\r\n }\r\n changed = true;\r\n // `name` non si cambia da qui: rinominare e' un refactoring globale e passa da\r\n // `renameNode`. Lasciarlo passare in un patch produrrebbe un documento con tutti i\r\n // riferimenti a valle rotti e nessun segnale.\r\n const { name: _ignored, ...rest } = patch as Partial<DpeNodeCollectionMap[K]> & { name?: string };\r\n void _ignored;\r\n return { ...node, ...rest };\r\n });\r\n if (!changed) {\r\n return;\r\n }\r\n this.commit(this.withCollection(definition, collection, next));\r\n }\r\n\r\n /**\r\n * Rimuove un nodo. I riferimenti a valle **restano** e diventano riferimenti rotti: e' cio'\r\n * che il documento dice davvero, e il backend li segnala (`DPE_REF_UNKNOWN_NODE`). Pulirli\r\n * qui vorrebbe dire decidere al posto dell'utente che quel filtro non serve piu'.\r\n */\r\n removeNode(nodeName: string): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, nodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.filter((node) => node.name !== nodeName);\r\n this.commit(this.withCollection(definition, located.collection, next));\r\n // Un nome che non esiste piu' non puo' restare selezionato: sarebbe una selezione che punta\r\n // al vuoto. Si riscrive solo se serve, perche' un nuovo array uguale al precedente farebbe\r\n // ripartire per nulla chi osserva la selezione.\r\n const selected = this._selectedNodeNames();\r\n if (selected.includes(nodeName)) {\r\n this._selectedNodeNames.set(selected.filter((name) => name !== nodeName));\r\n }\r\n }\r\n\r\n /**\r\n * L'**unico** punto che rinomina un nodo (**I5**): delega alla funzione pura, che aggiorna\r\n * ogni riferimento a valle passando dall'unico elenco di slot.\r\n */\r\n renameNode(oldName: string, newName: string): void {\r\n if (oldName === newName || newName.length === 0) {\r\n return;\r\n }\r\n this.commit(dpeRenameNode(this._definition(), oldName, newName));\r\n // La selezione segue la rinomina: identifica un nodo per nome, e il nome e' cambiato.\r\n const selected = this._selectedNodeNames();\r\n if (selected.includes(oldName)) {\r\n this._selectedNodeNames.set(selected.map((name) => (name === oldName ? newName : name)));\r\n }\r\n }\r\n\r\n /** Quante occorrenze toccherebbe una rinomina: si dice prima, non dopo. */\r\n countReferences(nodeName: string): number {\r\n return dpeCountReferences(this._definition(), nodeName);\r\n }\r\n\r\n /**\r\n * Crea un nodo della categoria data nella posizione indicata e restituisce il nome\r\n * assegnato, cosi' chi lo ha creato puo' selezionarlo subito.\r\n */\r\n createNodeAt<K extends DpeNodeCollectionName>(collection: K, position: DpeNodePosition): string {\r\n const definition = this._definition();\r\n const node = dpeWriteNodePosition(dpeCreateNode(definition, collection), position);\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n this.commit(this.withCollection(definition, collection, [...existing, node]));\r\n return node.name;\r\n }\r\n\r\n /**\r\n * Sposta un nodo scrivendo `dpe:layout`. `silent` non aggiunge un passo di cronologia:\r\n * trascinare cinque nodi insieme e' **un** gesto, e cinque passi di undo per un solo\r\n * trascinamento sono cinque passi che l'utente non ha fatto.\r\n */\r\n moveNode(nodeName: string, position: DpeNodePosition, options?: { silent?: boolean }): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, nodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.map((node) =>\r\n node.name === nodeName ? dpeWriteNodePosition(node, position) : node,\r\n );\r\n const updated = this.withCollection(definition, located.collection, next);\r\n if (options?.silent) {\r\n this._definition.set(updated);\r\n return;\r\n }\r\n this.commit(updated);\r\n }\r\n\r\n /**\r\n * Applica un layout calcolato **su comando dell'utente** («Riordina»): un passo di cronologia\r\n * per l'intero riordino, e il documento risulta modificato, perche' lo e'.\r\n */\r\n applyPositions(positions: ReadonlyMap<string, DpeNodePosition>): void {\r\n this.commit(this.withPositions(this._definition(), positions));\r\n }\r\n\r\n /**\r\n * Layout **iniziale** di un documento che non porta coordinate (ADR 0013: sono opzionali).\r\n *\r\n * Non e' una modifica dell'utente: non entra nella cronologia e **ri-fissa l'istantanea di\r\n * riferimento**, cosi' aprire un documento non produce «modificata». Un indicatore che dice\r\n * «modificata» appena si apre insegna a ignorarlo, e un indicatore ignorato e' peggio di\r\n * nessun indicatore. Il prezzo accettato: chi chiude senza salvare perde le coordinate\r\n * calcolate, che dagre rigenera in modo deterministico.\r\n *\r\n * Il riferimento si sposta **solo** se il documento non era gia' modificato: se l'utente ha\r\n * scritto qualcosa, un layout non puo' dichiarare salvato il suo lavoro.\r\n */\r\n applyInitialPositions(positions: ReadonlyMap<string, DpeNodePosition>): void {\r\n const wasClean = !this.isDirty();\r\n const next = this.withPositions(this._definition(), positions);\r\n this._definition.set(next);\r\n if (wasClean) {\r\n this._savedSnapshot.set(JSON.stringify(next));\r\n }\r\n }\r\n\r\n /**\r\n * Collega una porta di ingresso di `targetNodeName` al nodo `sourceName`. Non verifica che\r\n * il collegamento sia lecito: cicli (**I2**) e riferimenti a valle (**I3**) li rifiuta il\r\n * backend, e l'errore compare subito perche' la validazione parte dopo la mutazione.\r\n */\r\n connect(\r\n targetNodeName: string,\r\n slot: string,\r\n sourceName: string,\r\n index?: number,\r\n ): void {\r\n this.writeReference(targetNodeName, slot, index, sourceName);\r\n }\r\n\r\n /** Scollega una porta: lo slot torna vuoto, non a stringa vuota. */\r\n disconnect(targetNodeName: string, slot: string, index?: number): void {\r\n this.writeReference(targetNodeName, slot, index, undefined);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Cronologia\r\n // -------------------------------------------------------------------------\r\n\r\n undo(): void {\r\n const past = this._past();\r\n if (past.length === 0) {\r\n return;\r\n }\r\n const snapshot = past[past.length - 1];\r\n this._past.set(past.slice(0, -1));\r\n this._future.set([...this._future(), JSON.stringify(this._definition())]);\r\n this._definition.set(JSON.parse(snapshot) as DpeDefinition);\r\n }\r\n\r\n redo(): void {\r\n const future = this._future();\r\n if (future.length === 0) {\r\n return;\r\n }\r\n const snapshot = future[future.length - 1];\r\n this._future.set(future.slice(0, -1));\r\n this._past.set([...this._past(), JSON.stringify(this._definition())]);\r\n this._definition.set(JSON.parse(snapshot) as DpeDefinition);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Interno\r\n // -------------------------------------------------------------------------\r\n\r\n private writeReference(\r\n targetNodeName: string,\r\n slot: string,\r\n index: number | undefined,\r\n sourceName: string | undefined,\r\n ): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, targetNodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.map((node) =>\r\n node.name === targetNodeName\r\n ? dpeWriteSourceReference(located.collection, node, slot, index, sourceName)\r\n : node,\r\n );\r\n this.commit(this.withCollection(definition, located.collection, next));\r\n }\r\n\r\n /** Scrive le posizioni su tutte le collezioni producendo una nuova definizione. */\r\n private withPositions(\r\n definition: DpeDefinition,\r\n positions: ReadonlyMap<string, DpeNodePosition>,\r\n ): DpeDefinition {\r\n let next = definition;\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = next[collection] as DpeAnyNode[] | undefined;\r\n if (!nodes || nodes.length === 0) {\r\n continue;\r\n }\r\n const updated = nodes.map((node) => {\r\n const position = positions.get(node.name);\r\n return position ? dpeWriteNodePosition(node, position) : node;\r\n });\r\n next = this.withCollection(next, collection, updated);\r\n }\r\n return next;\r\n }\r\n\r\n /**\r\n * Sostituisce una collezione producendo una nuova definizione. Il cast e' confinato qui:\r\n * TypeScript non correla la chiave di collezione con il tipo di nodo dentro un accesso\r\n * dinamico, e la mappa dei tipi serve ai chiamanti, non a questa riga.\r\n */\r\n private withCollection(\r\n definition: DpeDefinition,\r\n collection: DpeNodeCollectionName,\r\n nodes: readonly unknown[],\r\n ): DpeDefinition {\r\n return { ...definition, [collection]: nodes.slice() } as DpeDefinition;\r\n }\r\n\r\n private commit(next: DpeDefinition): void {\r\n const snapshot = JSON.stringify(this._definition());\r\n const past = [...this._past(), snapshot];\r\n this._past.set(past.length > HISTORY_LIMIT ? past.slice(past.length - HISTORY_LIMIT) : past);\r\n // Una nuova mutazione chiude il ramo di redo: tenerlo sarebbe una cronologia ad albero,\r\n // che nessun comando dell'editor sa percorrere.\r\n this._future.set([]);\r\n this._definition.set(next);\r\n }\r\n}\r\n","/**\r\n * Lo stato del **catalogo** delle definizioni (ADR 0019): elenco, esiti delle chiamate, comandi.\r\n *\r\n * `@Injectable()` **senza `providedIn`**, come gli altri store: e' un provider del componente\r\n * radice della schermata di catalogo, non della root dell'applicazione. Due cataloghi in due\r\n * punti dell'ospite sono due elenchi indipendenti.\r\n *\r\n * Sta in `core/` e **non conosce il DOM**: e' il posto in cui un difetto e' silenzioso — una\r\n * chiamata mancata, un `refresh` che non parte dopo una scrittura, un errore assorbito — e quindi\r\n * il posto che ha bisogno di essere testabile senza browser.\r\n *\r\n * Cosa questo store **non** fa, e non e' una dimenticanza:\r\n *\r\n * - **non riordina** i sommari: l'ordine e' quello che l'ospite ha restituito (`contracts.md` §7),\r\n * e riordinarlo lato client combatterebbe una scelta che l'ospite ha gia' fatto;\r\n * - **non filtra**: il filtro di testo e' locale al componente, sui sommari gia' ricevuti;\r\n * - **non calcola** `nodeCount` ne' `hasErrors`: sono fatti riportati dall'ospite, e dedurli qui\r\n * sarebbe una validazione fatta dal client per interposta persona;\r\n * - **non carica documenti**: aprire e' dell'ospite, che potrebbe instradare o controllare\r\n * permessi. Il catalogo emette un nome.\r\n */\r\n\r\nimport { DestroyRef, Injectable, computed, inject, signal } from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EMPTY, Observable, catchError, switchMap, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { DpeApiError } from '../api/dpe-api-error';\r\nimport { DpeDefinitionSummary } from '../model/dpe-api.model';\r\nimport { SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { dpeCreateCommandAvailability, dpeReadCapabilities } from './dpe-capabilities';\r\nimport { dpeEmptyDefinition } from './dpe-document.store';\r\n\r\n@Injectable()\r\nexport class DpeCatalogStore {\r\n private readonly api = inject(DpeBuilderApi);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n /**\r\n * Le primitive disponibili, fotografate **alla costruzione** per identita' del metodo\r\n * (`dpe-capabilities.ts`). La disponibilita' si sa prima del clic: un comando che sembra attivo\r\n * e fallisce alla pressione insegna a non fidarsi dei bottoni.\r\n */\r\n readonly capabilities = dpeReadCapabilities(this.api);\r\n\r\n /** Il comando di creazione dipende da **due** primitive, e il motivo va mostrato. */\r\n readonly createCommand = dpeCreateCommandAvailability(this.capabilities);\r\n\r\n private readonly _summaries = signal<readonly DpeDefinitionSummary[]>([]);\r\n private readonly _isLoading = signal(false);\r\n private readonly _isMutating = signal(false);\r\n private readonly _error = signal<DpeApiError | null>(null);\r\n private readonly _hasLoaded = signal(false);\r\n private readonly _environmentDialect = signal<SqlDialectKind | undefined>(undefined);\r\n\r\n /** Nell'ordine restituito dall'ospite, mai riordinato. */\r\n readonly summaries = this._summaries.asReadonly();\r\n\r\n /**\r\n * Due stati distinti e non uno: **elencare** e **scrivere** si vedono diversi. Un unico\r\n * \"occupato\" farebbe lampeggiare l'elenco a ogni cancellazione, e nasconderebbe il fatto che\r\n * dopo una scrittura l'elenco si ricarica.\r\n */\r\n readonly isLoading = this._isLoading.asReadonly();\r\n readonly isMutating = this._isMutating.asReadonly();\r\n\r\n readonly error = this._error.asReadonly();\r\n\r\n /** Vero dopo la prima risposta: prima, un elenco vuoto non significa «nessuna definizione». */\r\n readonly hasLoaded = this._hasLoaded.asReadonly();\r\n\r\n /**\r\n * Il dialetto **dichiarato dall'ambiente** (ADR 0017), che e' quello con cui nasce una\r\n * definizione creata da qui. Non si chiede all'utente e non si sceglie per ripiego: senza\r\n * dichiarazione il comando di creazione resta spento (`createCommand`).\r\n */\r\n readonly environmentDialect = this._environmentDialect.asReadonly();\r\n\r\n readonly isEmpty = computed(() => this._hasLoaded() && this._summaries().length === 0);\r\n\r\n constructor() {\r\n // L'elenco si chiede all'apertura: un catalogo che mostra righe solo dopo un clic su\r\n // «Aggiorna» e' un catalogo che sembra vuoto.\r\n this.refresh();\r\n\r\n // La dichiarazione dell'ambiente e' un fatto dell'installazione: si chiede una volta. Un\r\n // guasto qui non e' un errore del catalogo — resta il comportamento di `getEnvironment`\r\n // assente, cioe' creazione spenta.\r\n if (this.capabilities.getEnvironment) {\r\n this.api\r\n .getEnvironment()\r\n .pipe(\r\n tap((environment) => this._environmentDialect.set(environment.dialect)),\r\n catchError(() => EMPTY),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Ricarica l'elenco. Senza `listDefinitions` non e' un errore: e' un ambiente che non offre il\r\n * catalogo, e chi rende lo dice guardando `capabilities.listDefinitions`.\r\n */\r\n refresh(): void {\r\n if (!this.capabilities.listDefinitions) {\r\n return;\r\n }\r\n this._isLoading.set(true);\r\n this._error.set(null);\r\n this.api\r\n .listDefinitions()\r\n .pipe(\r\n tap((summaries) => {\r\n this._summaries.set(summaries);\r\n this._isLoading.set(false);\r\n this._hasLoaded.set(true);\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isLoading.set(false))),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /**\r\n * Crea una definizione **subito**, non al primo salvataggio: `save` significa «scrivi questa\r\n * definizione» e non distingue inserimento da aggiornamento, quindi solo `createDefinition` da'\r\n * all'ospite il punto in cui rifiutare un nome duplicato. Una definizione che esiste solo nel\r\n * browser e' inoltre uno stato che l'elenco non puo' mostrare.\r\n *\r\n * Il dialetto arriva dall'ambiente e non dall'utente (ADR 0017): lo passa il chiamante, che lo\r\n * legge da `environmentDialect`.\r\n *\r\n * L'osservabile e' **freddo**: chi comanda si iscrive **una volta** e riceve il sommario che\r\n * l'ospite ha restituito — non quello costruito qui, perche' il nome puo' essere stato\r\n * normalizzato.\r\n */\r\n create(name: string, label: string, dialect: SqlDialectKind): Observable<DpeDefinitionSummary> {\r\n return this.mutate(this.api.createDefinition(dpeEmptyDefinition(name, label, dialect)));\r\n }\r\n\r\n /**\r\n * Duplica: `load` **e poi** `createDefinition`. Non esiste una primitiva di duplicazione sul\r\n * contratto, e non deve esistere — si comporrebbe di queste due comunque, e una primitiva\r\n * dedicata dovrebbe ridecidere lato host cosa cambia.\r\n *\r\n * Il dialetto e' quello della **definizione di partenza**, non quello dell'ambiente: le\r\n * espressioni sono SQL nativo (ADR 0006) e cambiare dialetto duplicando sarebbe una migrazione\r\n * silenziosa.\r\n */\r\n duplicate(\r\n sourceName: string,\r\n name: string,\r\n label: string,\r\n ): Observable<DpeDefinitionSummary> {\r\n return this.mutate(\r\n this.api\r\n .load(sourceName)\r\n .pipe(switchMap((source) => this.api.createDefinition({ ...source, name, label }))),\r\n );\r\n }\r\n\r\n /** Cancella per nome e ricarica l'elenco. La conferma e' della schermata, non dello store. */\r\n remove(name: string): void {\r\n if (!this.capabilities.deleteDefinition) {\r\n return;\r\n }\r\n this._isMutating.set(true);\r\n this._error.set(null);\r\n this.api\r\n .deleteDefinition(name)\r\n .pipe(\r\n tap(() => {\r\n this._isMutating.set(false);\r\n this.refresh();\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isMutating.set(false))),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n dismissError(): void {\r\n this._error.set(null);\r\n }\r\n\r\n /**\r\n * Il tratto comune delle due scritture: stato di attesa, **`refresh` dopo il successo** — un\r\n * elenco che omette cio' che l'utente ha appena creato e' un elenco che mente — ed errore nel\r\n * signal invece che propagato. Chi comanda non deve trattare l'errore due volte.\r\n */\r\n private mutate(source: Observable<DpeDefinitionSummary>): Observable<DpeDefinitionSummary> {\r\n this._error.set(null);\r\n return source.pipe(\r\n tap({\r\n subscribe: () => this._isMutating.set(true),\r\n next: () => {\r\n this._isMutating.set(false);\r\n this.refresh();\r\n },\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isMutating.set(false))),\r\n );\r\n }\r\n\r\n /** Un errore del provider finisce in `error()` e **non lancia**: nessuno lo raccoglierebbe. */\r\n private fail(error: unknown, reset: () => void): Observable<never> {\r\n reset();\r\n this._error.set(this.toApiError(error));\r\n return EMPTY;\r\n }\r\n\r\n /** Cio' che l'host non categorizza diventa `Transport`, la categoria \"riprovabile\". */\r\n private toApiError(error: unknown): DpeApiError {\r\n if (DpeApiError.is(error)) {\r\n return error;\r\n }\r\n const message = error instanceof Error ? error.message : 'Errore inatteso dal backend.';\r\n return new DpeApiError('Transport', message, error);\r\n }\r\n}\r\n","/**\r\n * Layout automatico del DAG con dagre.\r\n *\r\n * Due cose non ovvie, ed entrambe sono il motivo per cui esiste questo involucro invece di\r\n * chiamare dagre dai componenti:\r\n *\r\n * 1. **dagre ragiona in centri**, il canvas vuole l'angolo in alto a sinistra. La conversione\r\n * sta qui, una volta: fatta a valle, in ogni chiamante, sbaglia di mezzo nodo e il\r\n * disallineamento si nota solo a occhio;\r\n * 2. **dagre non e' ESM**: sta in `allowedCommonJsDependencies` di `angular.json`, altrimenti\r\n * la build avvisa a ogni compilazione.\r\n *\r\n * Input minimale di proposito: nomi e misure, piu' gli archi. Il servizio non conosce il\r\n * documento e non lo scrive — restituisce le posizioni, e chi lo invoca decide cosa farne.\r\n */\r\n\r\nimport { Injectable } from '@angular/core';\r\nimport dagre from 'dagre';\r\n\r\nexport interface DpeLayoutNodeInput {\r\n name: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface DpeLayoutEdgeInput {\r\n /** Nome del nodo a monte. */\r\n from: string;\r\n /** Nome del nodo a valle. */\r\n to: string;\r\n /** Identificatore dell'arco: dagre ne ha bisogno per ammettere archi paralleli. */\r\n id: string;\r\n}\r\n\r\nexport interface DpeLayoutPosition {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport type DpeLayoutDirection = 'TB' | 'LR';\r\n\r\nexport interface DpeLayoutOptions {\r\n /** Default `TB`: i dati scendono dalle sorgenti ai sink. */\r\n direction?: DpeLayoutDirection;\r\n /** Distanza fra i livelli. */\r\n rankSeparation?: number;\r\n /** Distanza fra i nodi dello stesso livello. */\r\n nodeSeparation?: number;\r\n /** Angolo in alto a sinistra del grafo risultante. */\r\n origin?: DpeLayoutPosition;\r\n}\r\n\r\n@Injectable()\r\nexport class DpeLayoutService {\r\n /**\r\n * Calcola le posizioni. La chiave della mappa e' il **nome** del nodo, non il suo id sul\r\n * canvas: il nome e' cio' che identifica un nodo nel documento, e passare dall'id\r\n * costringerebbe questo servizio a conoscere la costruzione degli id.\r\n */\r\n layout(\r\n nodes: readonly DpeLayoutNodeInput[],\r\n edges: readonly DpeLayoutEdgeInput[],\r\n options?: DpeLayoutOptions,\r\n ): Map<string, DpeLayoutPosition> {\r\n const origin = options?.origin ?? { x: 60, y: 60 };\r\n\r\n const graph = new dagre.graphlib.Graph({ multigraph: true, compound: false });\r\n graph.setGraph({\r\n rankdir: options?.direction ?? 'TB',\r\n ranksep: options?.rankSeparation ?? 90,\r\n nodesep: options?.nodeSeparation ?? 60,\r\n marginx: 0,\r\n marginy: 0,\r\n });\r\n graph.setDefaultEdgeLabel(() => ({}));\r\n\r\n const known = new Set<string>();\r\n for (const node of nodes) {\r\n graph.setNode(node.name, { width: node.width, height: node.height });\r\n known.add(node.name);\r\n }\r\n\r\n for (const edge of edges) {\r\n // Un arco con un capo sconosciuto e' un riferimento rotto: si disegna comunque sul\r\n // canvas, ma non vincola il layout — dagre creerebbe un nodo fantasma con misure zero.\r\n if (!known.has(edge.from) || !known.has(edge.to)) {\r\n continue;\r\n }\r\n graph.setEdge(edge.from, edge.to, {}, edge.id);\r\n }\r\n\r\n dagre.layout(graph);\r\n\r\n const positions = new Map<string, DpeLayoutPosition>();\r\n let minX = Number.POSITIVE_INFINITY;\r\n let minY = Number.POSITIVE_INFINITY;\r\n\r\n for (const node of nodes) {\r\n const laid = graph.node(node.name) as { x?: number; y?: number } | undefined;\r\n if (!laid || laid.x === undefined || laid.y === undefined) {\r\n continue;\r\n }\r\n const x = laid.x - node.width / 2;\r\n const y = laid.y - node.height / 2;\r\n positions.set(node.name, { x, y });\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n }\r\n\r\n // Trasla il grafo sull'origine scelta: dagre puo' produrre coordinate negative, e un nodo\r\n // a coordinate negative finisce fuori dall'area visibile appena il canvas si apre.\r\n if (Number.isFinite(minX) && Number.isFinite(minY)) {\r\n const deltaX = origin.x - minX;\r\n const deltaY = origin.y - minY;\r\n for (const [name, position] of positions) {\r\n positions.set(name, {\r\n x: Math.round(position.x + deltaX),\r\n y: Math.round(position.y + deltaY),\r\n });\r\n }\r\n }\r\n\r\n return positions;\r\n }\r\n}\r\n","/**\r\n * Cache locale del provider di metadati dell'host.\r\n *\r\n * Tabelle e campi arrivano da `DpeBuilderApi`, cioe' dal **provider dell'host** e non dai\r\n * cataloghi del database (ADR 0004). Due cose che questa cache non fa, di proposito:\r\n *\r\n * - **non appiattisce i tre esiti**. `Declared`, `DeclaredWithoutFields` (\"la tabella c'e', i\r\n * campi non li so\") e `Unknown` restano distinti fino alla UI: chi vede una tendina vuota\r\n * deve poter sapere quale dei tre casi sta guardando, perche' nel secondo il nome del campo\r\n * si digita a mano e non c'e' niente da correggere;\r\n * - **non giudica**. Se una tabella non e' nel catalogo, il rilievo autorevole\r\n * (`DPE_REF_UNKNOWN_TABLE`) arriva dalla validazione; qui si sa solo che non si sa.\r\n *\r\n * L'elenco delle tabelle puo' essere grande: si chiede una volta, si tiene, e chi lo mostra\r\n * filtra invece di riversarlo in un `<select>`.\r\n */\r\n\r\nimport { Injectable, inject, signal } from '@angular/core';\r\nimport { catchError, of, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { TableDescriptor, TableLookupOutcome, TableSummary } from '../model/dpe-api.model';\r\n\r\nexport interface DpeTableState {\r\n outcome: TableLookupOutcome;\r\n table?: TableDescriptor;\r\n}\r\n\r\n@Injectable()\r\nexport class DpeMetadataStore {\r\n private readonly api = inject(DpeBuilderApi);\r\n\r\n private readonly _tables = signal<readonly TableSummary[]>([]);\r\n private readonly _isLoadingTables = signal(false);\r\n private readonly _tablesRequested = signal(false);\r\n private readonly _byName = signal<ReadonlyMap<string, DpeTableState>>(new Map());\r\n private readonly pending = new Set<string>();\r\n\r\n readonly tables = this._tables.asReadonly();\r\n readonly isLoadingTables = this._isLoadingTables.asReadonly();\r\n\r\n /** Idempotente: la prima chiamata carica, le successive non fanno nulla. */\r\n loadTables(): void {\r\n if (this._tablesRequested()) {\r\n return;\r\n }\r\n this._tablesRequested.set(true);\r\n this._isLoadingTables.set(true);\r\n this.api\r\n .getTables()\r\n .pipe(\r\n tap((tables) => {\r\n this._tables.set(tables);\r\n this._isLoadingTables.set(false);\r\n }),\r\n catchError(() => {\r\n // Elenco vuoto significa \"non lo so\", non \"nessuna tabella\": la UI lascia digitare\r\n // il nome invece di impedire di scriverlo.\r\n this._isLoadingTables.set(false);\r\n return of([]);\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /** Stato noto di una tabella, se già richiesta. */\r\n stateOf(tableName: string): DpeTableState | undefined {\r\n return this._byName().get(tableName);\r\n }\r\n\r\n /** Chiede la descrizione di una tabella una sola volta per nome. */\r\n describe(tableName: string): void {\r\n if (!tableName || this.pending.has(tableName) || this._byName().has(tableName)) {\r\n return;\r\n }\r\n this.pending.add(tableName);\r\n this.api\r\n .getTable(tableName)\r\n .pipe(\r\n tap((result) => {\r\n this.pending.delete(tableName);\r\n this.put(tableName, { outcome: result.outcome, table: result.table });\r\n }),\r\n catchError(() => {\r\n this.pending.delete(tableName);\r\n // Un guasto di trasporto non e' `Unknown`: `Unknown` e' una risposta del provider.\r\n // Non si registra nulla, cosi' un tentativo successivo riprova.\r\n return of(undefined);\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n private put(tableName: string, state: DpeTableState): void {\r\n const next = new Map(this._byName());\r\n next.set(tableName, state);\r\n this._byName.set(next);\r\n }\r\n}\r\n","/**\r\n * I tracciati SVG delle icone di categoria, uno per collezione di nodi.\r\n *\r\n * **Perche' tracciati e non glifi Unicode** (divergenza motivata dal progetto di riferimento,\r\n * `frontend.md` §3-ter): i glifi non hanno metriche ne' linea di base coerenti fra loro e su\r\n * alcune piattaforme diventano emoji a colori — cioe' proprio la resa sbagliata quando stanno\r\n * in colonna in una palette. Un tracciato disegnato su una griglia 24x24 con `currentColor` si\r\n * colora con una sola regola CSS e vale identico in tema chiaro e scuro.\r\n *\r\n * **Nessun asset e nessuna dipendenza**: sono stringhe, e il componente che le rende le lega con\r\n * `[attr.d]` senza mai toccare `innerHTML` — quindi niente `bypassSecurityTrust*`.\r\n *\r\n * Il disegno e' pensato per la resa a **16px**: pochi tratti, nessun dettaglio sotto i 2 px di\r\n * griglia, e sagome che restano distinguibili l'una dall'altra quando sono incolonnate.\r\n */\r\n\r\nimport { DpeNodeCollectionName } from '../model/dpe-definition.model';\r\nimport { dpeNodeCategory } from './dpe-node-catalog';\r\n\r\n/**\r\n * La famiglia cromatica di una categoria. **Non e' una tassonomia nuova**: si deriva per intero\r\n * da `isSource`/`isSink`/`isNotCompilableInV1` del catalogo, che restano l'unica descrizione dei\r\n * tipi di nodo. Serve solo a scegliere un colore.\r\n */\r\nexport type DpeNodeIconFamily = 'source' | 'transform' | 'sink' | 'uncompilable';\r\n\r\nexport function dpeNodeIconFamily(collection: DpeNodeCollectionName): DpeNodeIconFamily {\r\n const category = dpeNodeCategory(collection);\r\n if (category.isSource) {\r\n return 'source';\r\n }\r\n if (category.isSink) {\r\n return 'sink';\r\n }\r\n // Dopo sorgenti e scritture: un sink non compilabile non esiste, e se un giorno esistesse\r\n // resterebbe piu' utile vederlo come sink.\r\n if (category.isNotCompilableInV1) {\r\n return 'uncompilable';\r\n }\r\n return 'transform';\r\n}\r\n\r\n/** Classe CSS della famiglia: un solo posto la costruisce, cosi' i fogli restano allineati. */\r\nexport function dpeNodeIconFamilyClass(collection: DpeNodeCollectionName): string {\r\n return `dpe-cat--${dpeNodeIconFamily(collection)}`;\r\n}\r\n\r\n/**\r\n * I tracciati, per collezione. Ogni voce e' l'elenco degli attributi `d` di un `<path>`; il\r\n * contorno e' `stroke`, mai `fill`, cosi' l'icona pesa uguale su qualunque sfondo.\r\n */\r\nexport const DPE_NODE_ICON_PATHS: Readonly<Record<DpeNodeCollectionName, readonly string[]>> = {\r\n // Cilindro di database: ellisse superiore, fianchi, e la riga di mezzo che lo fa leggere\r\n // come un solido invece che come un ovale con due gambe.\r\n dataSources: [\r\n 'M4 6a8 3 0 1 0 16 0a8 3 0 1 0 -16 0',\r\n 'M4 6v12c0 1.66 3.58 3 8 3s8-1.34 8-3V6',\r\n 'M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3',\r\n ],\r\n // Imbuto.\r\n filters: ['M3 4h18l-7 8.5V20l-4-2v-5.5z'],\r\n // Due cerchi che si intersecano: ogni cerchio e' due archi da 180 gradi. I centri stanno a 7\r\n // unita' e il raggio e' 4.5: con una sovrapposizione maggiore, a 16px, si leggevano come un\r\n // cerchio con un anello dentro invece che come due insiemi che si incrociano.\r\n joins: ['M8.5 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 1 0 0-9', 'M15.5 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 1 0 0-9'],\r\n // Tre barre di altezza diversa. Rettangoli e non segmenti: a 16px un segmento verticale\r\n // spesso 2 non si distingue da una barra sottile, e l'insieme si confonde con l'unione.\r\n aggregates: ['M4 11h4v9H4z', 'M10 5h4v15h-4z', 'M16 14h4v6h-4z'],\r\n // Due frecce affiancate in versi opposti.\r\n transforms: ['M3 8h13', 'M12 4l4 4-4 4', 'M21 16H8', 'M12 12l-4 4 4 4'],\r\n // Due lastre impilate.\r\n appends: ['M4 5h16v5H4z', 'M4 14h16v5H4z'],\r\n // Albero: un nodo in alto, due sotto, collegati.\r\n hierarchyPaths: ['M9 3h6v4H9z', 'M12 7v3', 'M6 10h12', 'M6 10v3', 'M18 10v3', 'M3 13h6v4H3z', 'M15 13h6v4h-6z'],\r\n // Spezzata crescente, con la punta che dichiara la direzione.\r\n forecasts: ['M21 7l-8 8-4-4-6 6', 'M15 7h6v6'],\r\n // Tassello di puzzle: una bozza sopra, un incavo a destra. Due sole sporgenze e non quattro —\r\n // a 16px il tassello \"completo\" diventava un quadrato con quattro tacche indistinguibili.\r\n customNodes: ['M4 4h5.5a2.5 2.5 0 0 1 5 0H20v5.5a2.5 2.5 0 0 0 0 5V20H4z'],\r\n // Freccia che entra in un contenitore.\r\n writebacks: ['M12 3v10', 'M8 9l4 4 4-4', 'M4 14v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4'],\r\n // Lo stesso contenitore, con un lucchetto al posto della freccia.\r\n atomicWritebacks: [\r\n 'M10 7V5.5a2 2 0 0 1 4 0V7',\r\n 'M8.5 7h7v5h-7z',\r\n 'M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3',\r\n ],\r\n};\r\n\r\n/**\r\n * I tracciati di una collezione. Il ripiego vuoto non e' pigrizia: una collezione aggiunta al\r\n * modello e non ancora disegnata deve produrre una pastiglia vuota, non un errore in console\r\n * ne' un `undefined` dentro `[attr.d]`.\r\n */\r\nexport function dpeNodeIconPaths(collection: DpeNodeCollectionName): readonly string[] {\r\n return DPE_NODE_ICON_PATHS[collection] ?? [];\r\n}\r\n","/**\r\n * Il ponte fra il documento e il backend: valida in modo **debounced**, chiede l'anteprima SQL su\r\n * comando e salva su comando.\r\n *\r\n * Il salvataggio sta qui e non in un componente per la stessa ragione degli altri due: nessun\r\n * componente conosce il trasporto. Che il nome della classe sia piu' stretto della sua\r\n * responsabilita' e' un debito segnalato all'architect, non una svista.\r\n *\r\n * Perche' il debounce non e' un dettaglio: la chiamata al service DPE e' sincrona nel\r\n * backend, cioe' occupa il chiamante finche' non termina. Incatenarne una a ogni battitura\r\n * significa una coda di lavori che nessuno leggera' — e nel frattempo l'editor mostra un\r\n * risultato vecchio. Qui si aspetta la pausa di digitazione, si annulla la richiesta in volo\r\n * quando ne parte una nuova (`switchMap`), e si mostra sempre lo stato di attesa.\r\n *\r\n * L'editing resta **sincrono** mentre una validazione e' in volo: il documento e' la fonte di\r\n * verita', le diagnostiche arrivano dopo e non bloccano niente.\r\n *\r\n * Provider del componente radice come gli store: montare due editor non deve significare due\r\n * servizi che validano lo stesso documento.\r\n */\r\n\r\nimport { DestroyRef, Injectable, computed, inject, signal } from '@angular/core';\r\nimport { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EMPTY, catchError, debounceTime, of, switchMap, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { DpeApiError } from '../api/dpe-api-error';\r\nimport { DpeParameterValue } from '../model/dpe-api.model';\r\nimport { SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { dpeReadCapabilities } from './dpe-capabilities';\r\nimport { DpeDocumentStore } from './dpe-document.store';\r\n\r\n/** Pausa di digitazione oltre la quale vale la pena chiedere al backend. */\r\nconst VALIDATE_DEBOUNCE_MS = 400;\r\n\r\n/**\r\n * Durata dell'avviso di salvataggio riuscito. Transitorio di proposito: il fatto durevole e'\r\n * «nessuna modifica» nell'indicatore, e un avviso di successo che resta va poi chiuso a mano.\r\n */\r\nconst SAVE_NOTICE_MS = 2600;\r\n\r\n@Injectable()\r\nexport class DpeValidationService {\r\n private readonly api = inject(DpeBuilderApi);\r\n private readonly store = inject(DpeDocumentStore);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n private readonly _isValidating = signal(false);\r\n private readonly _isCompiling = signal(false);\r\n private readonly _error = signal<DpeApiError | undefined>(undefined);\r\n /**\r\n * Le primitive opzionali si sanno **alla costruzione**, per identita' del metodo\r\n * (`dpe-capabilities.ts`, `contracts.md` §7). Prima si partiva da «disponibile» e si scopriva\r\n * l'assenza dal primo `MissingService`: il comando sembrava attivo e falliva alla pressione,\r\n * che e' peggio di un comando disabilitato che ne dice il motivo.\r\n */\r\n private readonly capabilities = dpeReadCapabilities(this.api);\r\n private readonly _isPreviewAvailable = signal(this.capabilities.compilePreview);\r\n private readonly _isSaving = signal(false);\r\n /** Come l'anteprima: un host senza `save` disabilita il comando, non rompe l'editor. */\r\n private readonly _isSaveAvailable = signal(this.capabilities.save);\r\n /** Esito dell'ultimo salvataggio: transitorio al successo, persistente al fallimento. */\r\n private readonly _justSaved = signal(false);\r\n private readonly _saveError = signal<DpeApiError | undefined>(undefined);\r\n /**\r\n * Il dialetto **dichiarato dall'ambiente** (ADR 0017), quando l'host espone `getEnvironment`.\r\n * Non e' il dialetto con cui si compila — quello sta nella definizione — ed e' esattamente per\r\n * questo che i due si tengono separati: il confronto e' l'unica cosa che l'editor puo' dire.\r\n */\r\n private readonly _environmentDialect = signal<SqlDialectKind | undefined>(undefined);\r\n\r\n readonly isValidating = this._isValidating.asReadonly();\r\n readonly isCompiling = this._isCompiling.asReadonly();\r\n readonly error = this._error.asReadonly();\r\n readonly isPreviewAvailable = this._isPreviewAvailable.asReadonly();\r\n readonly isSaving = this._isSaving.asReadonly();\r\n readonly isSaveAvailable = this._isSaveAvailable.asReadonly();\r\n readonly justSaved = this._justSaved.asReadonly();\r\n readonly saveError = this._saveError.asReadonly();\r\n readonly environmentDialect = this._environmentDialect.asReadonly();\r\n\r\n /** Vero finche' non e' arrivata la prima risposta: la UI non deve dire \"nessun problema\". */\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n constructor() {\r\n toObservable(this.store.definition)\r\n .pipe(\r\n debounceTime(VALIDATE_DEBOUNCE_MS),\r\n tap(() => {\r\n this._isValidating.set(true);\r\n this._error.set(undefined);\r\n }),\r\n // `switchMap`: una definizione piu' recente rende inutile la risposta precedente, e\r\n // applicarla dopo mostrerebbe diagnostiche di un documento che non esiste piu'.\r\n switchMap((definition) =>\r\n this.api.validate(definition).pipe(\r\n tap((result) => {\r\n this.store.applyValidateResult(result);\r\n this._isValidating.set(false);\r\n }),\r\n catchError((error: unknown) => {\r\n this._isValidating.set(false);\r\n this._error.set(this.toApiError(error));\r\n // Le diagnostiche precedenti **restano**: cancellarle direbbe \"va tutto bene\"\r\n // proprio quando non lo sappiamo piu'.\r\n return EMPTY;\r\n }),\r\n ),\r\n ),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n\r\n // La dichiarazione dell'ambiente si chiede **una volta**, all'apertura: e' un fatto\r\n // dell'installazione, non cambia mentre si edita. Un guasto qui non si mostra come errore\r\n // dell'editor — senza dichiarazione l'editor si comporta come con `getEnvironment` assente.\r\n if (this.capabilities.getEnvironment) {\r\n this.api\r\n .getEnvironment()\r\n .pipe(\r\n tap((environment) => this._environmentDialect.set(environment.dialect)),\r\n catchError(() => EMPTY),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n // Il timer dell'avviso transitorio non deve sopravvivere all'editor: scriverebbe su un\r\n // signal di un componente distrutto.\r\n this.destroyRef.onDestroy(() => this.clearSaveNotice());\r\n }\r\n\r\n /** Anteprima dell'SQL. Opzionale sull'host: assente, il comando resta disabilitato. */\r\n requestPreview(parameterValues?: DpeParameterValue[]): void {\r\n if (!this._isPreviewAvailable()) {\r\n return;\r\n }\r\n this._isCompiling.set(true);\r\n this.api\r\n .compilePreview(this.store.definition(), parameterValues)\r\n .pipe(\r\n tap((result) => {\r\n this.store.applyCompileResult(result);\r\n this._isCompiling.set(false);\r\n }),\r\n catchError((error: unknown) => {\r\n this._isCompiling.set(false);\r\n const apiError = this.toApiError(error);\r\n if (apiError.category === 'MissingService') {\r\n this._isPreviewAvailable.set(false);\r\n } else {\r\n this._error.set(apiError);\r\n }\r\n return of(undefined);\r\n }),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /**\r\n * Salvataggio attraverso `DpeBuilderApi.save` (opzionale, `contracts.md` §7). Al successo\r\n * **l'editor dichiara da se'** lo stato salvato: quando l'ospite espone il metodo, e' questo il\r\n * punto che sa se e' andato a buon fine.\r\n *\r\n * Si passa a `markSaved` **il documento inviato**, non quello corrente: se l'utente scrive\r\n * mentre il salvataggio e' in volo, quelle modifiche non sono state salvate e l'indicatore deve\r\n * continuare a dirlo.\r\n */\r\n save(): void {\r\n if (!this._isSaveAvailable() || this._isSaving()) {\r\n return;\r\n }\r\n const sent = this.store.definition();\r\n this._isSaving.set(true);\r\n this._saveError.set(undefined);\r\n this.api\r\n .save(sent)\r\n .pipe(\r\n tap(() => {\r\n this._isSaving.set(false);\r\n // `markSaved` **solo** qui: un salvataggio fallito che azzerasse l'indicatore\r\n // cancellerebbe la traccia di un lavoro che non e' stato scritto da nessuna parte.\r\n this.store.markSaved(sent);\r\n this.showSaveNotice();\r\n }),\r\n catchError((error: unknown) => {\r\n this._isSaving.set(false);\r\n const apiError = this.toApiError(error);\r\n if (apiError.category === 'MissingService') {\r\n // Non dovrebbe accadere: la disponibilita' e' nota prima del clic. Se accade, l'host\r\n // ha sovrascritto la primitiva per rifiutarla — si disabilita il comando invece di\r\n // riproporlo a ogni tentativo.\r\n this._isSaveAvailable.set(false);\r\n }\r\n // L'esito si **vede**: banner persistente con la categoria. Un salvataggio che\r\n // fallisce in silenzio e' peggio di nessun salvataggio.\r\n this._saveError.set(apiError);\r\n return of(undefined);\r\n }),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n dismissError(): void {\r\n this._error.set(undefined);\r\n }\r\n\r\n dismissSaveError(): void {\r\n this._saveError.set(undefined);\r\n }\r\n\r\n private saveNoticeTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n private showSaveNotice(): void {\r\n this.clearSaveNotice();\r\n this._justSaved.set(true);\r\n this.saveNoticeTimer = setTimeout(() => {\r\n this.saveNoticeTimer = undefined;\r\n this._justSaved.set(false);\r\n }, SAVE_NOTICE_MS);\r\n }\r\n\r\n private clearSaveNotice(): void {\r\n if (this.saveNoticeTimer !== undefined) {\r\n clearTimeout(this.saveNoticeTimer);\r\n this.saveNoticeTimer = undefined;\r\n }\r\n this._justSaved.set(false);\r\n }\r\n\r\n /**\r\n * Un host che non usa `DpeApiError` non deve far esplodere l'editor: cio' che non e'\r\n * categorizzato diventa `Transport`, che e' la categoria \"riprovabile\".\r\n */\r\n private toApiError(error: unknown): DpeApiError {\r\n if (DpeApiError.is(error)) {\r\n return error;\r\n }\r\n const message = error instanceof Error ? error.message : 'Errore inatteso dal backend.';\r\n return new DpeApiError('Transport', message, error);\r\n }\r\n}\r\n","/**\r\n * Geometria della viewport: funzioni pure, nessun DOM.\r\n *\r\n * Serve a una sola domanda, che si pone quando si naviga da una diagnostica al nodo: **il nodo\r\n * e' interamente in vista?** Se lo e', non si sposta niente — una panoramica non richiesta\r\n * disorienta quanto la sua assenza. Se non lo e', si centra la **vista**, non il nodo: le\r\n * coordinate del documento non si toccano.\r\n *\r\n * Sta qui e non nel componente perche' e' esattamente il tipo di logica che si sbaglia in\r\n * silenzio (un `>` al posto di un `>=`, un margine dimenticato) e che si verifica senza browser.\r\n */\r\n\r\n/** Rettangolo in coordinate di schermo, la forma che `getBoundingClientRect` restituisce. */\r\nexport interface DpeRect {\r\n left: number;\r\n top: number;\r\n right: number;\r\n bottom: number;\r\n}\r\n\r\n/**\r\n * Vero quando `target` sta **interamente** dentro `view`, lasciando `margin` pixel di respiro su\r\n * ogni lato. Il margine non e' un vezzo: un nodo tangente al bordo e' tecnicamente visibile e\r\n * praticamente illeggibile, e senza respiro il criterio \"e' visibile\" scatterebbe anche quando\r\n * dell'ombra e del connettore di uscita non si vede nulla.\r\n */\r\nexport function dpeIsRectFullyVisible(target: DpeRect, view: DpeRect, margin = 0): boolean {\r\n return (\r\n target.left >= view.left + margin &&\r\n target.top >= view.top + margin &&\r\n target.right <= view.right - margin &&\r\n target.bottom <= view.bottom - margin\r\n );\r\n}\r\n","/**\r\n * L'icona di una categoria di nodo.\r\n *\r\n * Rende markup SVG **statico** e lega soltanto `[attr.d]` dei tracciati: nessun `innerHTML`,\r\n * quindi nessun bypass del sanitizer e nessuna dipendenza per le icone. `d` non e' un attributo\r\n * sensibile — e' l'unico punto in cui il dato entra nel markup, ed e' un dato nostro, non del\r\n * documento.\r\n *\r\n * `aria-hidden`: l'icona **non e' informazione**, l'etichetta accanto lo e' gia'. Annunciarla\r\n * farebbe leggere due volte la stessa cosa a chi usa uno screen reader.\r\n *\r\n * La stessa icona compare in tre posti — palette, card del canvas, intestazione dell'ispettore —\r\n * perche' cio' che si trascina deve assomigliare a cio' che compare.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\n\r\nimport { dpeNodeIconPaths } from '../../core/dpe-node-icons';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n@Component({\r\n selector: 'dpe-node-icon',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styles: [\r\n `\r\n :host {\r\n display: inline-flex;\r\n flex: 0 0 auto;\r\n line-height: 0;\r\n }\r\n `,\r\n ],\r\n template: `\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n width=\"16\"\r\n height=\"16\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n aria-hidden=\"true\"\r\n >\r\n <!-- track $index: i tracciati sono una lista ricalcolata, e due uguali sono legittimi. -->\r\n @for (path of paths(); track $index) {\r\n <path [attr.d]=\"path\" />\r\n }\r\n </svg>\r\n `,\r\n})\r\nexport class DpeNodeIconComponent {\r\n readonly collection = input.required<DpeNodeCollectionName>();\r\n\r\n protected readonly paths = computed(() => dpeNodeIconPaths(this.collection()));\r\n}\r\n","/**\r\n * View model del canvas.\r\n *\r\n * Gli **id** non si costruiscono qui: vengono da `core/dpe-graph.ts`, che e' l'unico posto che\r\n * li conosce. Qui stanno solo le misure, e stanno qui perche' servono a due consumatori che\r\n * devono concordare: il CSS che disegna la card e dagre che calcola il layout. Se divergono,\r\n * il layout automatico lascia i nodi sovrapposti.\r\n */\r\n\r\nimport { DiagnosticSeverity } from '../../model/dpe-diagnostics.model';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n/** Altezza nominale della card: non cambia con il numero di porte, che stanno in fila sopra. */\r\nexport const DPE_NODE_HEIGHT = 104;\r\n\r\n/**\r\n * Larghezza per numero di porte di ingresso. Le porte stanno in fila sul bordo **superiore**,\r\n * quindi e' la larghezza a dipendere dal loro numero.\r\n *\r\n * E' una tabella a scaglioni e non una formula perche' la larghezza si applica con una\r\n * **classe**: @foblex/flow riscrive l'attributo `style` del nodo a ogni riposizionamento e\r\n * qualunque `[style.width]` di Angular verrebbe cancellato al primo spostamento. I valori qui\r\n * e quelli di `.dpe-node--ports-N` nel CSS del componente devono restare uguali.\r\n */\r\nconst PORT_WIDTHS = [230, 230, 260, 320, 380];\r\n\r\nconst MAX_PORT_BUCKET = PORT_WIDTHS.length - 1;\r\n\r\nfunction portBucket(portCount: number): number {\r\n return Math.min(Math.max(portCount, 0), MAX_PORT_BUCKET);\r\n}\r\n\r\nexport function dpeNodeWidth(portCount: number): number {\r\n return PORT_WIDTHS[portBucket(portCount)];\r\n}\r\n\r\nexport function dpeNodeWidthClass(portCount: number): string {\r\n return `dpe-node--ports-${portBucket(portCount)}`;\r\n}\r\n\r\nexport interface DpeCanvasPort {\r\n id: string;\r\n slot: string;\r\n index?: number;\r\n /** Etichetta della porta: si mostra solo dove le porte sono piu' di una. */\r\n label: string;\r\n /** Nome collegato, assente se la porta e' libera. */\r\n sourceName?: string;\r\n /** Il nome collegato non corrisponde a nessun nodo: si dice sulla porta. */\r\n isBroken: boolean;\r\n}\r\n\r\nexport interface DpeCanvasNode {\r\n /** Nome nel documento: l'identita', anche per la selezione. */\r\n name: string;\r\n /** Id per il canvas, costruito da `dpeNodeId`. */\r\n id: string;\r\n collection: DpeNodeCollectionName;\r\n categoryLabel: string;\r\n label: string;\r\n subtitle: string | null;\r\n position: { x: number; y: number };\r\n ports: DpeCanvasPort[];\r\n showsPortLabels: boolean;\r\n widthClass: string;\r\n /**\r\n * Classe della famiglia cromatica (`dpe-cat--*`): la calcola `core/dpe-node-icons.ts` dai\r\n * flag del catalogo. Sta nel view model e non nel template perche' e' la stessa che usa la\r\n * palette, e due modi di derivarla sarebbero due colori diversi per lo stesso tipo di nodo.\r\n */\r\n familyClass: string;\r\n outputPortId: string;\r\n /** I sink non producono uno schema: la porta di uscita non si disegna... */\r\n hasOutput: boolean;\r\n /** Gravita' peggiore fra le diagnostiche del nodo. */\r\n severity: DiagnosticSeverity | null;\r\n diagnosticCount: number;\r\n /**\r\n * Nodo **valido ma non compilabile** (**I10**): stato distinto da \"non valido\", con un\r\n * colore proprio. Sono due situazioni diverse e l'utente deve capire subito quale guarda.\r\n */\r\n isNotCompilable: boolean;\r\n /** Numero di colonne dello schema di uscita, quando il backend lo ha detto. */\r\n columnCount: number | null;\r\n}\r\n\r\nexport interface DpeCanvasEdge {\r\n id: string;\r\n sourceId: string;\r\n targetId: string;\r\n slot: string;\r\n}\r\n","/**\r\n * Il canvas del DAG.\r\n *\r\n * @foblex/flow in *classic mode*: la libreria disegna e riconosce i gesti, **lo stato resta\r\n * nostro**. Nodi e archi sono signal derivati da `DpeDocumentStore` attraverso\r\n * `core/dpe-graph.ts`, e ogni gesto e' una mutazione del documento.\r\n *\r\n * Cosa il canvas **non** fa: non decide se un collegamento sia lecito. Un ciclo (**I2**) o un\r\n * riferimento a valle (**I3**) li rifiuta il backend, e la diagnostica arriva subito perche' la\r\n * validazione parte dopo la mutazione. Disegnare solo cio' che il backend accetterebbe\r\n * richiederebbe di riprodurre qui la sua semantica: e' esattamente cio' che non facciamo.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport {\r\n EFConnectableSide,\r\n EFMarkerType,\r\n FCanvasComponent,\r\n FFlowComponent,\r\n FFlowModule,\r\n provideFFlow,\r\n withA11y,\r\n} from '@foblex/flow';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport {\r\n dpeAllNodes,\r\n dpeInputPorts,\r\n dpeNodeId,\r\n dpeOutputPortId,\r\n dpeParseInputPortId,\r\n dpeParseNodeId,\r\n dpeParseOutputPortId,\r\n} from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport { dpeIsRectFullyVisible } from '../../core/dpe-viewport';\r\nimport { dpeNodeSubtitle } from '../../core/dpe-node-factory';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\nimport {\r\n DPE_NODE_HEIGHT,\r\n DpeCanvasEdge,\r\n DpeCanvasNode,\r\n DpeCanvasPort,\r\n dpeNodeWidth,\r\n dpeNodeWidthClass,\r\n} from './dpe-canvas.model';\r\n\r\n/** Etichette delle porte di ingresso, per slot. Presentazione, non semantica. */\r\nconst PORT_LABELS: Readonly<Record<string, string>> = {\r\n source: 'Ingresso',\r\n primary: 'Primaria',\r\n secondary: 'Secondaria',\r\n sources: 'Sorgente',\r\n};\r\n\r\n/**\r\n * Respiro attorno al grafo inquadrato. Era 100 per lato: su un'area alta 590 px erano 200 px di\r\n * vuoto, cioe' un terzo dello spazio, e bastavano a spingere l'inquadratura sotto la soglia di\r\n * leggibilita' — quindi a farla saltare del tutto.\r\n *\r\n * Il valore verticale e' un filo piu' generoso di quello orizzontale, e non per estetica: la card\r\n * disegna piu' del rettangolo con cui e' misurata (le porte sporgono sopra, il connettore di\r\n * uscita sotto), e con un respiro simmetrico l'ultima card restava tangente al bordo inferiore —\r\n * misurato: un pixel fuori.\r\n */\r\nconst FIT_PADDING = { x: 44, y: 56 };\r\n\r\n/**\r\n * Scala minima con cui il canvas si apre. Sotto questa soglia le etichette della card — nome,\r\n * categoria, conteggio delle colonne — sono disegnate in un corpo che non si legge, e si apre al\r\n * 100% centrato lasciando all'utente lo zoom (rotella, `+`/`-`, minimappa, «Inquadra»).\r\n *\r\n * Il valore non e' arbitrario: il titolo della card e' 13px, quindi a 0,75 resta un corpo effettivo\r\n * di ~10px, il minimo che si legge. Era stato abbassato a 0.35 per soddisfare il criterio «nessun\r\n * nodo fuori dal riquadro all'apertura», criterio poi **ritirato** dal committente\r\n * (`docs/frontend.md` §3-ter): su un grafo grande si soddisfa solo rimpicciolendo fino\r\n * all'illeggibile — misurato sul seed della demo, scala 0,516 e titolo effettivo 6,7px. La\r\n * leggibilita' viene prima della vista d'insieme; la vista d'insieme resta a un clic, tramite\r\n * «Inquadra», che in questo ramo si mostra apposta.\r\n */\r\nconst MIN_INITIAL_SCALE = 0.75;\r\n\r\n/**\r\n * Respiro richiesto attorno al nodo perche' si consideri \"in vista\". Un nodo tangente al bordo\r\n * e' visibile e illeggibile: la panoramica scatta anche in quel caso.\r\n */\r\nconst REVEAL_MARGIN = 24;\r\n\r\n@Component({\r\n selector: 'dpe-canvas',\r\n standalone: true,\r\n imports: [FFlowModule, DpeNodeIconComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './dpe-canvas.component.html',\r\n styleUrl: './dpe-canvas.component.css',\r\n /**\r\n * Il layer da tastiera di @foblex/flow e' **opzionale**: senza `withA11y()` la libreria non\r\n * ascolta nessun tasto e `(fDeleteSelected)` — l'unico modo in cui annuncia «l'utente vuole\r\n * cancellare» — non viene mai emesso. Nessun errore: semplicemente `Canc` non fa niente.\r\n * Attiva anche frecce, `Ctrl+A`, `Escape`, zoom da tastiera, cioe' la meta' della\r\n * navigazione senza mouse che un editor a canvas deve avere.\r\n *\r\n * Provider **del componente**: montare il canvas non installa ascoltatori globali nell'app\r\n * ospite.\r\n */\r\n providers: [provideFFlow(withA11y())],\r\n})\r\nexport class DpeCanvasComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n /** Serve per misurare l'area disponibile prima di decidere la scala d'apertura. */\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n /** Marker \"all states\": senza, l'arco selezionato perde la punta. */\r\n readonly markerEnd = EFMarkerType.END_ALL_STATES;\r\n\r\n /**\r\n * Ingressi in alto, uscita in basso, **dichiarati**. Lasciando calcolare il lato, un arco\r\n * che risale (un nodo posizionato sopra la sua sorgente) esce di fianco e il grafo diventa\r\n * illeggibile.\r\n */\r\n readonly sides = EFConnectableSide;\r\n\r\n readonly isEditable = input(true);\r\n\r\n readonly nodeOpened = output<string>();\r\n readonly nodeDropped = output<{ collection: DpeNodeCollectionName; x: number; y: number }>();\r\n\r\n private readonly canvas = viewChild.required(FCanvasComponent);\r\n /**\r\n * Serve solo a **riallineare** la selezione della libreria a quella dello store: e' l'unico\r\n * punto che scrive nello stato di selezione di @foblex/flow.\r\n */\r\n private readonly flow = viewChild(FFlowComponent);\r\n private hasFramedOnce = false;\r\n\r\n /**\r\n * Visibilita' del comando «Inquadra». Non e' piu' «l'utente ha spostato la vista»: lo diventa\r\n * anche all'apertura quando l'editor rinuncia a inquadrare per non scendere sotto\r\n * `MIN_INITIAL_SCALE`. In quel caso la vista d'insieme non e' stata data, quindi il comando che\r\n * la offre deve essere raggiungibile — nasconderlo significherebbe toglierla e basta.\r\n */\r\n private readonly _isFitCommandVisible = signal(false);\r\n readonly isFitCommandVisible = this._isFitCommandVisible.asReadonly();\r\n\r\n readonly nodes = computed<DpeCanvasNode[]>(() => {\r\n const definition = this.store.definition();\r\n const positions = this.store.positions();\r\n const diagnostics = this.store.diagnosticsByNode();\r\n const schemas = this.store.schemaByNode();\r\n const known = new Set(this.store.graph().nodes.map((node) => node.name));\r\n\r\n // Si cammina la definizione, non il grafo: servono i nodi veri (etichetta, sintesi) e le\r\n // porte, che si leggono dagli slot del nodo.\r\n return dpeAllNodes(definition).map((located) => {\r\n const category = dpeNodeCategory(located.collection);\r\n const ports: DpeCanvasPort[] = dpeInputPorts(located).map((port) => ({\r\n id: port.id,\r\n slot: port.slot,\r\n index: port.index,\r\n label:\r\n port.index === undefined\r\n ? (PORT_LABELS[port.slot] ?? port.slot)\r\n : `${PORT_LABELS[port.slot] ?? port.slot} ${port.index + 1}`,\r\n sourceName: port.sourceName,\r\n // Un nome che non corrisponde a nessun nodo non e' disegnabile come arco — non\r\n // esiste il connettore da cui partirebbe — quindi si dice **sulla porta**. Nasconderlo\r\n // sarebbe l'unico modo di non vedere un riferimento rotto.\r\n isBroken: port.sourceName !== undefined && !known.has(port.sourceName),\r\n }));\r\n const name = located.node.name;\r\n const nodeDiagnostics = diagnostics.get(name);\r\n const schema = schemas.get(name);\r\n\r\n return {\r\n name,\r\n id: dpeNodeId(name),\r\n collection: located.collection,\r\n categoryLabel: category.label,\r\n label: located.node.label || name,\r\n subtitle: dpeNodeSubtitle(located.collection, located.node),\r\n position: positions.get(name) ?? { x: 0, y: 0 },\r\n ports,\r\n showsPortLabels: ports.length > 1,\r\n widthClass: dpeNodeWidthClass(ports.length),\r\n familyClass: dpeNodeIconFamilyClass(located.collection),\r\n outputPortId: dpeOutputPortId(name),\r\n hasOutput: !category.isSink,\r\n severity: nodeDiagnostics?.severity ?? null,\r\n diagnosticCount: nodeDiagnostics?.diagnostics.length ?? 0,\r\n // Due fonti concordi: la diagnostica del backend (autorevole) e lo schema, che porta\r\n // `isCompilable`. La categoria «non compilabile in v1» del catalogo e' solo un\r\n // suggerimento della palette e qui non basterebbe.\r\n isNotCompilable:\r\n (nodeDiagnostics?.isNotCompilable ?? false) || schema?.isCompilable === false,\r\n columnCount: schema?.columns?.length ?? null,\r\n };\r\n });\r\n });\r\n\r\n /**\r\n * Solo gli archi con **entrambi** i capi risolti diventano `<f-connection>`: un capo che non\r\n * esiste non ha un connettore, e una connessione verso un id inesistente si attacca a un\r\n * punto arbitrario del canvas. Il riferimento rotto si vede sulla porta del nodo.\r\n */\r\n readonly edges = computed<DpeCanvasEdge[]>(() =>\r\n this.store\r\n .graph()\r\n .edges.filter((edge) => edge.isResolved)\r\n .map((edge) => ({\r\n id: edge.id,\r\n sourceId: edge.fromPortId,\r\n targetId: edge.toPortId,\r\n slot: edge.slot,\r\n })),\r\n );\r\n\r\n constructor() {\r\n /*\r\n * Riallineamento della selezione: **una sola scrittura**, e in questa direzione.\r\n *\r\n * @foblex/flow tiene una sua selezione (classe `f-selected`, elenco interno usato da drag\r\n * multiplo e `Canc`) e la aggiorna da se' sui gesti. Se la si lascia autorevole si finisce\r\n * con due sistemi che non si parlano: il nodo raggiunto da una diagnostica porta la nostra\r\n * classe, quello cliccato prima porta `f-selected`, e l'utente vede due nodi selezionati\r\n * senza sapere su quale sta agendo. La cura non e' azzerare l'altro sistema dove serve — e'\r\n * derivarlo: il gesto entra da `fSelectionChange` e finisce nello store, lo store torna qui e\r\n * scrive nella libreria. La classe `dpe-node--selected` deriva dallo stesso stato.\r\n *\r\n * `isSelectedChanged: false` perche' questa scrittura **non** e' un gesto dell'utente e non\r\n * deve far emettere un cambio di selezione: sarebbe il ciclo.\r\n */\r\n effect(() => {\r\n const selected = this.store.selectedNodeNames();\r\n const flow = this.flow();\r\n if (!flow) {\r\n return;\r\n }\r\n if (selected.length === 0) {\r\n // `clearSelection` agisce subito; `select` no (vedi sotto), quindi il caso vuoto passa da qui.\r\n flow.clearSelection();\r\n return;\r\n }\r\n flow.select(selected.map((name) => dpeNodeId(name)), [], false);\r\n // `select()` della libreria non applica: si iscrive al prossimo cambio delle connessioni e\r\n // agisce **la' dentro**. Senza una notifica, la selezione programmatica resta in attesa\r\n // indefinitamente e nel DOM non compare niente — nessun errore, solo un `f-selected` che\r\n // non arriva. `redraw()` e' cio' che emette quel cambio.\r\n flow.redraw();\r\n });\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Navigazione\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Porta il nodo in vista **muovendo la vista**, non il nodo: le coordinate del documento non si\r\n * toccano (una navigazione non e' una modifica). Se il nodo e' gia' interamente visibile non fa\r\n * nulla, perche' una panoramica non richiesta disorienta quanto la sua assenza.\r\n */\r\n revealNode(name: string): void {\r\n const id = dpeNodeId(name);\r\n const element = this.findNodeElement(id);\r\n if (!element) {\r\n return;\r\n }\r\n const view = this.host.nativeElement.getBoundingClientRect();\r\n if (dpeIsRectFullyVisible(element.getBoundingClientRect(), view, REVEAL_MARGIN)) {\r\n return;\r\n }\r\n // La panoramica e' un movimento della vista fatto da noi, ma resta un movimento: lasciando\r\n // emettere `fCanvasChange` compare «Inquadra», che e' il modo di tornare all'insieme.\r\n this.canvas().centerGroupOrNode(id, true);\r\n }\r\n\r\n /**\r\n * Il nodo nel DOM. Si scorre l'elenco invece di comporre un selettore con il valore\r\n * dell'attributo: il nome del nodo arriva dal documento e puo' contenere qualunque carattere,\r\n * e un selettore costruito per concatenazione su un dato del documento e' un errore in attesa.\r\n */\r\n private findNodeElement(id: string): HTMLElement | undefined {\r\n const elements = this.host.nativeElement.querySelectorAll<HTMLElement>('[data-f-node-id]');\r\n for (const element of Array.from(elements)) {\r\n if (element.getAttribute('data-f-node-id') === id) {\r\n return element;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n /** Misure per il layout automatico: le stesse che il CSS applica con le classi. */\r\n layoutInput(): { name: string; width: number; height: number }[] {\r\n return this.nodes().map((node) => ({\r\n name: node.name,\r\n width: dpeNodeWidth(node.ports.length),\r\n height: DPE_NODE_HEIGHT,\r\n }));\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Viewport\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * `fitToScreen` va chiamato **dopo** il render dei nodi: prima, la libreria non conosce\r\n * ancora le loro dimensioni e inquadra la vista sbagliata. Solo la prima volta: rifarlo\r\n * combatterebbe con l'utente che ha spostato la vista.\r\n */\r\n onNodesRendered(): void {\r\n if (this.hasFramedOnce || this.nodes().length < 2) {\r\n return;\r\n }\r\n /*\r\n * Si inquadra **dopo** che tutti i nodi hanno una posizione. Un documento che non porta\r\n * coordinate (ADR 0013) le riceve da dagre subito dopo il primo render: inquadrare prima\r\n * significava inquadrare un mucchio di card tutte in (0,0), e il risultato era il grafo\r\n * tagliato in alto a sinistra all'apertura — con `hasFramedOnce` già consumato, quindi senza\r\n * una seconda occasione. Qui non si consuma niente: il layout scrive le posizioni, i nodi si\r\n * ridisegnano e questo gestore torna con le misure vere.\r\n */\r\n const positions = this.store.positions();\r\n if (this.nodes().some((node) => !positions.has(node.name))) {\r\n return;\r\n }\r\n this.hasFramedOnce = true;\r\n const canvas = this.canvas();\r\n // La scala si **stima prima**: chiedere `getScale()` dopo `fitToScreen` restituisce la scala\r\n // di configurazione e non quella applicata, quindi il controllo non scattava mai e le card\r\n // restavano illeggibili. La stima usa gli stessi numeri che il CSS applica alle card.\r\n if (this.wouldFitBelowMinimumScale()) {\r\n // 100% centrato sui nodi: si perde la vista d'insieme e si guadagna un'etichetta\r\n // leggibile. `emitCanvasChange: false` perche' l'inquadratura iniziale non e' un gesto\r\n // dell'utente; il comando «Inquadra» si mostra qui in modo esplicito, perche' e' l'unico\r\n // modo di ottenere la panoramica a cui si e' appena rinunciato.\r\n canvas.resetScaleAndCenter(false, false);\r\n this._isFitCommandVisible.set(true);\r\n return;\r\n }\r\n canvas.fitToScreen(FIT_PADDING, false, false);\r\n }\r\n\r\n /** Vero quando inquadrare tutto il grafo richiederebbe una scala sotto la soglia leggibile. */\r\n private wouldFitBelowMinimumScale(): boolean {\r\n const nodes = this.nodes();\r\n if (nodes.length === 0) {\r\n return false;\r\n }\r\n let left = Number.POSITIVE_INFINITY;\r\n let top = Number.POSITIVE_INFINITY;\r\n let right = Number.NEGATIVE_INFINITY;\r\n let bottom = Number.NEGATIVE_INFINITY;\r\n for (const node of nodes) {\r\n const width = dpeNodeWidth(node.ports.length);\r\n left = Math.min(left, node.position.x);\r\n top = Math.min(top, node.position.y);\r\n right = Math.max(right, node.position.x + width);\r\n bottom = Math.max(bottom, node.position.y + DPE_NODE_HEIGHT);\r\n }\r\n const host = this.host.nativeElement;\r\n const availableWidth = host.clientWidth - FIT_PADDING.x * 2;\r\n const availableHeight = host.clientHeight - FIT_PADDING.y * 2;\r\n if (availableWidth <= 0 || availableHeight <= 0) {\r\n return false;\r\n }\r\n const scale = Math.min(\r\n availableWidth / Math.max(right - left, 1),\r\n availableHeight / Math.max(bottom - top, 1),\r\n );\r\n return scale < MIN_INITIAL_SCALE;\r\n }\r\n\r\n onCanvasChange(): void {\r\n this._isFitCommandVisible.set(true);\r\n }\r\n\r\n resetViewport(): void {\r\n this.canvas().fitToScreen(FIT_PADDING, true, false);\r\n // Il grafo e' inquadrato: il comando non ha piu' niente da offrire finche' la vista non si muove.\r\n this._isFitCommandVisible.set(false);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Gesti\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Creazione di un arco: si scrive il **riferimento** sulla porta di destinazione. La\r\n * direzione del gesto e' irrilevante — cio' che conta e' quale slot riceve il nome, ed e'\r\n * per questo che le porte di ingresso sono una per slot.\r\n */\r\n onCreateConnection(event: { sourceId: string; targetId?: string }): void {\r\n if (!this.isEditable() || !event.targetId) {\r\n return;\r\n }\r\n const source = dpeParseOutputPortId(event.sourceId);\r\n const target = dpeParseInputPortId(event.targetId);\r\n if (!source || !target || source === target.nodeName) {\r\n // Un nodo che si collega a se stesso e' un ciclo di lunghezza uno: il backend lo\r\n // rifiuterebbe con `DPE_GRAPH_CYCLE`, e disegnarlo non aggiunge informazione.\r\n return;\r\n }\r\n this.store.connect(target.nodeName, target.slot, source, target.index);\r\n }\r\n\r\n /** Riassegnazione di un arco già disegnato, da un capo o dall'altro. */\r\n onReassignConnection(event: {\r\n endpoint: string;\r\n previousSourceId: string;\r\n nextSourceId?: string;\r\n previousTargetId: string;\r\n nextTargetId?: string;\r\n }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n const previousTarget = dpeParseInputPortId(event.previousTargetId);\r\n const previousSource = dpeParseOutputPortId(event.previousSourceId);\r\n if (!previousTarget || !previousSource) {\r\n return;\r\n }\r\n if (event.endpoint === 'target') {\r\n const nextTarget = event.nextTargetId ? dpeParseInputPortId(event.nextTargetId) : undefined;\r\n this.store.disconnect(previousTarget.nodeName, previousTarget.slot, previousTarget.index);\r\n if (nextTarget) {\r\n this.store.connect(nextTarget.nodeName, nextTarget.slot, previousSource, nextTarget.index);\r\n }\r\n return;\r\n }\r\n const nextSource = event.nextSourceId ? dpeParseOutputPortId(event.nextSourceId) : undefined;\r\n if (nextSource) {\r\n this.store.connect(previousTarget.nodeName, previousTarget.slot, nextSource, previousTarget.index);\r\n }\r\n }\r\n\r\n /**\r\n * Spostamento: un solo passo di cronologia per l'intero gesto. Le posizioni intermedie non\r\n * sono modifiche che l'utente vuole annullare una per una.\r\n */\r\n onMoveNodes(event: { nodes: Array<{ id: string; position: { x: number; y: number } }> }): void {\r\n event.nodes.forEach((moved, index) => {\r\n const name = dpeParseNodeId(moved.id);\r\n if (name) {\r\n this.store.moveNode(name, moved.position, { silent: index > 0 });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Il gesto di selezione della libreria entra **nello store** e non altrove: e' l'unico verso in\r\n * cui la selezione di @foblex/flow conta, come rilevazione del gesto. Cio' che si vede lo decide\r\n * lo store, attraverso l'effect del costruttore.\r\n */\r\n onSelectionChange(event: { nodeIds: string[] }): void {\r\n const names: string[] = [];\r\n for (const id of event.nodeIds) {\r\n const name = dpeParseNodeId(id);\r\n if (name) {\r\n names.push(name);\r\n }\r\n }\r\n this.store.selectMany(names);\r\n }\r\n\r\n onDeleteSelected(event: { nodeIds: string[] }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n for (const id of event.nodeIds) {\r\n const name = dpeParseNodeId(id);\r\n if (name) {\r\n this.store.removeNode(name);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Rilascio di una voce trascinata dalla palette. `externalItemRect` e' già nel sistema di\r\n * coordinate del canvas: convertirlo a mano dal viewport sarebbe rifare la trasformazione\r\n * di zoom e panoramica della libreria.\r\n */\r\n onCreateNode(event: { data: unknown; externalItemRect: { x: number; y: number } }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n const collection = event.data as DpeNodeCollectionName | undefined;\r\n if (!collection) {\r\n return;\r\n }\r\n this.nodeDropped.emit({\r\n collection,\r\n x: Math.round(event.externalItemRect.x),\r\n y: Math.round(event.externalItemRect.y),\r\n });\r\n }\r\n\r\n onNodeDoubleClick(name: string): void {\r\n this.nodeOpened.emit(name);\r\n }\r\n\r\n onEditClick(event: Event, name: string): void {\r\n // Senza `stopPropagation` il clic vale anche come selezione dell'area sotto il bottone.\r\n event.stopPropagation();\r\n this.nodeOpened.emit(name);\r\n }\r\n\r\n onRemoveClick(event: Event, name: string): void {\r\n event.stopPropagation();\r\n this.store.removeNode(name);\r\n }\r\n\r\n /** La classe nel DOM **deriva** dallo store: non e' una seconda registrazione della selezione. */\r\n isSelected(node: DpeCanvasNode): boolean {\r\n return this.store.selectedNodeNameSet().has(node.name);\r\n }\r\n}\r\n","<!--\r\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection. I `@for` stanno\r\n direttamente dentro <f-canvas>: senza wrapper non serve `ngProjectAs`.\r\n-->\r\n<f-flow\r\n fDraggable\r\n (fCreateConnection)=\"onCreateConnection($event)\"\r\n (fReassignConnection)=\"onReassignConnection($event)\"\r\n (fMoveNodes)=\"onMoveNodes($event)\"\r\n (fSelectionChange)=\"onSelectionChange($event)\"\r\n (fDeleteSelected)=\"onDeleteSelected($event)\"\r\n (fCreateNode)=\"onCreateNode($event)\"\r\n (fNodesRendered)=\"onNodesRendered()\"\r\n>\r\n <f-canvas fZoom #canvas (fCanvasChange)=\"onCanvasChange()\">\r\n <f-background>\r\n <f-circle-pattern />\r\n </f-background>\r\n\r\n @for (edge of edges(); track edge.id) {\r\n <!--\r\n La classe porta lo **slot** di destinazione: la primaria e la secondaria di un join\r\n vanno distinte a vista, altrimenti l’unico modo di sapere quale lato e’ quale e’ aprire\r\n l’ispettore. I colori stanno nel CSS globale, non qui: i path SVG sono creati a runtime\r\n e non portano l’attributo di scope.\r\n -->\r\n <f-connection\r\n [fConnectionId]=\"edge.id\"\r\n [fSourceId]=\"edge.sourceId\"\r\n [fTargetId]=\"edge.targetId\"\r\n fBehavior=\"floating\"\r\n fType=\"bezier\"\r\n [class]=\"'dpe-edge dpe-edge--' + edge.slot\"\r\n >\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection>\r\n }\r\n\r\n @for (node of nodes(); track node.id) {\r\n <!--\r\n Nessun `[style.*]` sul nodo: @foblex/flow riscrive l’attributo `style` a ogni\r\n riposizionamento e lo cancellerebbe. La larghezza arriva da `node.widthClass`.\r\n -->\r\n <div\r\n fNode\r\n fDragHandle\r\n [fNodeId]=\"node.id\"\r\n [fNodePosition]=\"node.position\"\r\n [class]=\"\r\n 'dpe-node dpe-node--' + node.collection + ' ' + node.widthClass + ' ' + node.familyClass\r\n \"\r\n [class.dpe-node--selected]=\"isSelected(node)\"\r\n [class.dpe-node--error]=\"node.severity === 'Error'\"\r\n [class.dpe-node--warning]=\"node.severity === 'Warning'\"\r\n [class.dpe-node--not-compilable]=\"node.isNotCompilable\"\r\n [attr.aria-label]=\"node.categoryLabel + ' ' + node.label\"\r\n (dblclick)=\"onNodeDoubleClick(node.name)\"\r\n >\r\n <!--\r\n Le porte di ingresso stanno in fila sul bordo superiore, una per slot. Si renderizzano\r\n **sempre**: un connettore con `display: none` ha geometria 0x0 e l’arco si attacca nel\r\n punto sbagliato. `fConnectorConnectableSide` e’ dichiarato: senza, un arco che risale\r\n entrerebbe di fianco.\r\n -->\r\n @if (node.ports.length > 0) {\r\n <div class=\"dpe-node__ports\" [class.dpe-node__ports--labelled]=\"node.showsPortLabels\">\r\n @for (port of node.ports; track port.id) {\r\n <div class=\"dpe-port\">\r\n <div\r\n fConnector\r\n fConnectorType=\"target\"\r\n [fConnectorId]=\"port.id\"\r\n [fConnectorConnectableSide]=\"sides.TOP\"\r\n fConnectorMultiple=\"false\"\r\n class=\"dpe-connector dpe-connector--in\"\r\n [class.dpe-connector--broken]=\"port.isBroken\"\r\n [title]=\"port.label\"\r\n ></div>\r\n @if (node.showsPortLabels) {\r\n <span class=\"dpe-port__label\" [title]=\"port.label\">{{ port.label }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-node__head\">\r\n <!--\r\n La stessa pastiglia della palette: cio’ che si trascina deve assomigliare a cio’ che\r\n compare. La classe di famiglia porta i due token di colore.\r\n -->\r\n <span class=\"dpe-node__icon\">\r\n <dpe-node-icon [collection]=\"node.collection\" />\r\n </span>\r\n <div class=\"dpe-node__text\">\r\n <span class=\"dpe-node__title\" [title]=\"node.label\">{{ node.label }}</span>\r\n <span class=\"dpe-node__sub\">\r\n {{ node.categoryLabel }}\r\n @if (node.subtitle) {\r\n <span class=\"dpe-node__dot\">·</span>{{ node.subtitle }}\r\n }\r\n </span>\r\n </div>\r\n <!--\r\n `fDragBlocker` sui bottoni dentro un nodo: senza, il pointerdown diventa un\r\n trascinamento e aprire l’ispettore sposta il nodo di qualche pixel.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-node__btn\"\r\n [attr.aria-label]=\"'Apri l’ispettore di ' + node.label\"\r\n title=\"Apri l’ispettore\"\r\n (click)=\"onEditClick($event, node.name)\"\r\n >\r\n ✎\r\n </button>\r\n @if (isEditable() && isSelected(node)) {\r\n <!--\r\n Solo sul nodo selezionato: un comando distruttivo che compare sotto il puntatore\r\n mentre si attraversa il grafo si preme per sbaglio.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-node__btn dpe-node__btn--remove\"\r\n [attr.aria-label]=\"'Elimina ' + node.label\"\r\n title=\"Elimina (si annulla con ↶)\"\r\n (click)=\"onRemoveClick($event, node.name)\"\r\n >\r\n ×\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-node__meta\">\r\n <span class=\"dpe-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\r\n @if (node.columnCount !== null) {\r\n <span class=\"dpe-badge\" [title]=\"'Colonne in uscita secondo il backend'\">\r\n {{ node.columnCount }} col.\r\n </span>\r\n }\r\n @if (node.isNotCompilable) {\r\n <!--\r\n Stato distinto dall’errore: la definizione va bene, il compilatore non ci arriva\r\n (I10). Colore proprio, testo che non chiede di correggere niente.\r\n -->\r\n <span class=\"dpe-badge dpe-badge--not-compilable\" title=\"Valido, ma non compilabile: e’ un limite nostro\">\r\n non compilabile\r\n </span>\r\n }\r\n @if (node.diagnosticCount > 0) {\r\n <span\r\n class=\"dpe-badge\"\r\n [class.dpe-badge--error]=\"node.severity === 'Error'\"\r\n [class.dpe-badge--warning]=\"node.severity === 'Warning'\"\r\n [class.dpe-badge--info]=\"node.severity === 'Info'\"\r\n [title]=\"node.diagnosticCount + ' rilievi dal backend'\"\r\n >\r\n {{ node.diagnosticCount }}\r\n </span>\r\n }\r\n @for (port of node.ports; track $index) {\r\n @if (port.isBroken) {\r\n <span class=\"dpe-badge dpe-badge--error\" [title]=\"'Riferimento non risolto: ' + port.sourceName\">\r\n ⚠ {{ port.sourceName }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n\r\n <!--\r\n L’uscita e’ una sola: lo schema prodotto e’ uno. I sink non ne hanno, e la porta non\r\n si disegna affatto — qui non c’e’ niente da nascondere con `display: none`, il\r\n connettore semplicemente non esiste.\r\n -->\r\n @if (node.hasOutput) {\r\n <div class=\"dpe-node__out\">\r\n <div\r\n fConnector\r\n fConnectorType=\"source\"\r\n [fConnectorId]=\"node.outputPortId\"\r\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\r\n class=\"dpe-connector dpe-connector--out\"\r\n title=\"Uscita\"\r\n ></div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"dpe-edge dpe-edge--creating\">\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection-for-create>\r\n\r\n <f-selection-area />\r\n </f-canvas>\r\n\r\n <!--\r\n Fuori da <f-canvas> come la minimappa: dentro, la trasformazione del canvas se lo\r\n porterebbe via insieme ai nodi.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-viewport-reset\"\r\n [class.dpe-viewport-reset--hidden]=\"!isFitCommandVisible()\"\r\n title=\"Rimetti il grafo interamente in vista\"\r\n (click)=\"resetViewport()\"\r\n >\r\n ⤢ Inquadra\r\n </button>\r\n\r\n <f-minimap [fMinSize]=\"1200\" class=\"dpe-minimap\" />\r\n</f-flow>\r\n","/**\r\n * Il pannello delle diagnostiche.\r\n *\r\n * Mostra l'**elenco completo** (la validazione e' esaustiva, **I6**): non si accorpa, non si\r\n * tronca, non si riordina per gravita' — l'ordine del backend segue la struttura del documento e\r\n * perderlo rende impossibile capire quale nodo ha quale problema.\r\n *\r\n * La distinzione che questo pannello esiste per rendere: **nodo non valido** (l'utente deve\r\n * correggere) contro **nodo valido ma non ancora compilabile** (`DPE_NODE_NOT_COMPILABLE`,\r\n * **I10**). Sono situazioni diverse e hanno colore, icona ed etichetta diversi; mescolarle\r\n * significherebbe chiedere all'utente di correggere un limite nostro.\r\n *\r\n * Terza categoria a se': i rilievi **del dialetto** (`DPE_DIALECT_*`). Lo stesso documento su un\r\n * altro dialetto sarebbe compilabile, e l'interfaccia deve dirlo, altrimenti si cerca l'errore\r\n * nella definizione.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject, output } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport {\r\n dpeDiagnosticLocationLabel,\r\n dpeDiagnosticNodeName,\r\n dpeIsDialectDiagnostic,\r\n dpeIsNotCompilable,\r\n} from '../../core/dpe-diagnostics.util';\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { Diagnostic } from '../../model/dpe-diagnostics.model';\r\n\r\ninterface DpeDiagnosticRow {\r\n diagnostic: Diagnostic;\r\n location: string;\r\n /** Nodo a cui navigare, se il percorso permette di ricavarlo. */\r\n nodeName?: string;\r\n field?: string;\r\n isNotCompilable: boolean;\r\n isDialect: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-diagnostics-panel',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styles: [\r\n `\r\n :host {\r\n display: flex;\r\n flex-direction: column;\r\n overflow: auto;\r\n background: var(--dpe-surface, #fff);\r\n font-size: 12px;\r\n }\r\n\r\n .dpe-diag__head {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 8px 10px;\r\n border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);\r\n }\r\n\r\n .dpe-diag__count {\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 11px;\r\n }\r\n\r\n .dpe-diag__row {\r\n display: flex;\r\n gap: 8px;\r\n width: 100%;\r\n padding: 6px 10px;\r\n border: 0;\r\n border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);\r\n border-left: 3px solid transparent;\r\n background: transparent;\r\n color: inherit;\r\n font: inherit;\r\n font-size: 11px;\r\n text-align: left;\r\n cursor: pointer;\r\n }\r\n\r\n .dpe-diag__row:hover {\r\n background: var(--dpe-surface-alt, #f7f8fa);\r\n }\r\n\r\n .dpe-diag__row:focus-visible {\r\n outline: 2px solid var(--dpe-accent, #2f7d8f);\r\n outline-offset: -2px;\r\n }\r\n\r\n .dpe-diag__row--Error {\r\n border-left-color: var(--dpe-error, #dc2626);\r\n }\r\n\r\n .dpe-diag__row--Warning {\r\n border-left-color: var(--dpe-warning, #b7791f);\r\n }\r\n\r\n .dpe-diag__row--Info {\r\n border-left-color: var(--dpe-info, #3b6fd4);\r\n }\r\n\r\n /* Vince sulla gravita': non e' un problema dell'utente, e si deve vedere subito. */\r\n .dpe-diag__row--not-compilable {\r\n border-left-color: var(--dpe-not-compilable, #7c5cd6);\r\n background: color-mix(in srgb, var(--dpe-not-compilable, #7c5cd6) 6%, transparent);\r\n }\r\n\r\n .dpe-diag__code {\r\n flex: 0 0 auto;\r\n font-family: var(--dpe-font-mono, monospace);\r\n font-size: 10px;\r\n color: var(--dpe-text-muted, #6b7086);\r\n }\r\n\r\n .dpe-diag__text {\r\n flex: 1 1 auto;\r\n }\r\n\r\n .dpe-diag__where {\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 10px;\r\n }\r\n\r\n .dpe-diag__tag {\r\n flex: 0 0 auto;\r\n padding: 0 6px;\r\n border: 1px solid currentcolor;\r\n border-radius: 999px;\r\n font-size: 9px;\r\n text-transform: uppercase;\r\n }\r\n\r\n .dpe-diag__tag--not-compilable {\r\n color: var(--dpe-not-compilable, #7c5cd6);\r\n }\r\n\r\n .dpe-diag__tag--dialect {\r\n color: var(--dpe-info, #3b6fd4);\r\n }\r\n\r\n .dpe-diag__empty {\r\n padding: 10px;\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 11px;\r\n font-style: italic;\r\n }\r\n `,\r\n ],\r\n template: `\r\n <div class=\"dpe-diag__head\">\r\n <strong>Diagnostiche</strong>\r\n <span class=\"dpe-diag__count\">\r\n {{ counts().errors }} errori · {{ counts().warnings }} avvisi · {{ counts().infos }} info\r\n @if (counts().notCompilable > 0) {\r\n · {{ counts().notCompilable }} non compilabili\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (rows().length === 0) {\r\n <p class=\"dpe-diag__empty\">\r\n @if (hasResult()) {\r\n Nessun rilievo dal backend.\r\n } @else {\r\n In attesa della prima validazione…\r\n }\r\n </p>\r\n }\r\n\r\n <!--\r\n track $index: le chiavi composte da codice e percorso si duplicano davvero (lo stesso\r\n codice sullo stesso campo di due righe di una collezione) e Angular lo tratta come errore.\r\n -->\r\n @for (row of rows(); track $index) {\r\n <!-- Una sola sorgente di classi: class statico e [class] si contenderebbero l’attributo. -->\r\n <button\r\n type=\"button\"\r\n [class]=\"'dpe-diag__row dpe-diag__row--' + row.diagnostic.severity\"\r\n [class.dpe-diag__row--not-compilable]=\"row.isNotCompilable\"\r\n [disabled]=\"!row.nodeName\"\r\n (click)=\"navigateTo(row)\"\r\n >\r\n <span class=\"dpe-diag__code\">{{ row.diagnostic.code }}</span>\r\n <span class=\"dpe-diag__text\">\r\n {{ row.diagnostic.message }}\r\n <br />\r\n <span class=\"dpe-diag__where\">{{ row.location }}</span>\r\n </span>\r\n @if (row.isNotCompilable) {\r\n <span\r\n class=\"dpe-diag__tag dpe-diag__tag--not-compilable\"\r\n title=\"Valido, ma il compilatore non lo traduce: non c’e’ nulla da correggere\"\r\n >\r\n limite nostro\r\n </span>\r\n }\r\n @if (row.isDialect) {\r\n <span\r\n class=\"dpe-diag__tag dpe-diag__tag--dialect\"\r\n [title]=\"'Dipende dalle capacita’ del dialetto ' + dialectLabel() + ': su un altro dialetto lo stesso documento potrebbe compilare'\"\r\n >\r\n {{ dialectLabel() }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n `,\r\n})\r\nexport class DpeDiagnosticsPanelComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n /** Emesso quando la riga porta a un nodo: chi ascolta apre l'ispettore e inquadra il nodo. */\r\n readonly navigate = output<{ nodeName: string; field?: string }>();\r\n\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n readonly dialectLabel = computed(() => {\r\n const dialect = this.store.definition().dialect;\r\n return DPE_DIALECT_LABELS[dialect] ?? dialect;\r\n });\r\n\r\n readonly rows = computed<DpeDiagnosticRow[]>(() => {\r\n const definition = this.store.definition();\r\n return this.store.diagnostics().map((diagnostic) => ({\r\n diagnostic,\r\n location: dpeDiagnosticLocationLabel(diagnostic, definition),\r\n nodeName: dpeDiagnosticNodeName(diagnostic, definition),\r\n field: diagnostic.path?.field,\r\n isNotCompilable: dpeIsNotCompilable(diagnostic),\r\n isDialect: dpeIsDialectDiagnostic(diagnostic),\r\n }));\r\n });\r\n\r\n readonly counts = computed(() => {\r\n let errors = 0;\r\n let warnings = 0;\r\n let infos = 0;\r\n let notCompilable = 0;\r\n for (const row of this.rows()) {\r\n if (row.isNotCompilable) {\r\n notCompilable += 1;\r\n }\r\n switch (row.diagnostic.severity) {\r\n case 'Error':\r\n errors += 1;\r\n break;\r\n case 'Warning':\r\n warnings += 1;\r\n break;\r\n default:\r\n infos += 1;\r\n break;\r\n }\r\n }\r\n return { errors, warnings, infos, notCompilable };\r\n });\r\n\r\n /**\r\n * Emette **soltanto** l'intenzione: chi la riceve seleziona e inquadra. Selezionare anche da qui\r\n * significherebbe due scritture della selezione per un solo clic — la strada per due nodi\r\n * selezionati insieme — e un pannello che pilota il canvas invece di chiederglielo.\r\n */\r\n protected navigateTo(row: DpeDiagnosticRow): void {\r\n if (!row.nodeName) {\r\n return;\r\n }\r\n this.navigate.emit({ nodeName: row.nodeName, field: row.field });\r\n }\r\n}\r\n","/**\r\n * `[dpeValue]` su un `<select>`.\r\n *\r\n * Perche' esiste, e non e' un vezzo: un `[value]` viene applicato **prima** che le `<option>`\r\n * generate da un `@for` esistano. Il browser scarta un valore che non corrisponde a nessuna\r\n * opzione, Angular non lo riapplica (il binding non e' cambiato) e la tendina resta sulla prima\r\n * voce — mostrando un valore diverso da quello del documento. Nessun errore, nessun avviso: solo\r\n * una tendina che mente. L'abbiamo visto sul selettore del dialetto e sulle funzioni di\r\n * aggregazione, dove `Sum` compariva come `Count`.\r\n *\r\n * La direttiva riallinea l'elemento al valore dichiarato a ogni giro di change detection, quindi\r\n * quando le opzioni compaiono la selezione si sistema da se'.\r\n */\r\n\r\nimport { AfterViewChecked, Directive, ElementRef, inject, input } from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'select[dpeValue]',\r\n standalone: true,\r\n})\r\nexport class DpeSelectValueDirective implements AfterViewChecked {\r\n private readonly element = inject<ElementRef<HTMLSelectElement>>(ElementRef);\r\n\r\n readonly dpeValue = input<string | number | null | undefined>('');\r\n\r\n ngAfterViewChecked(): void {\r\n const select = this.element.nativeElement;\r\n const value = this.dpeValue();\r\n const normalized = value === null || value === undefined ? '' : String(value);\r\n if (select.value !== normalized) {\r\n select.value = normalized;\r\n }\r\n }\r\n}\r\n","/**\r\n * Base comune degli ispettori.\r\n *\r\n * `@Directive()` **senza selettore**: e' il solo modo in cui Angular riconosce come input\r\n * quelli dichiarati su una classe base ereditata da piu' componenti. Senza il decoratore ogni\r\n * ispettore darebbe NG8002 sul primo binding.\r\n *\r\n * Ogni ispettore riceve il nodo in **sola lettura** e scrive attraverso lo store: la\r\n * definizione e' un valore, le modifiche producono un nuovo valore. Nessun ispettore muta\r\n * l'oggetto che riceve.\r\n *\r\n * Quello che gli ispettori **non** fanno: non validano. Le sole verifiche locali ammesse sono\r\n * di forma del campo (obbligatorio non vuoto, un intero e' un intero) e servono al\r\n * comportamento del controllo, non a dire se la definizione va bene. Le diagnostiche mostrate\r\n * sono quelle del backend, con il loro codice e percorso.\r\n */\r\n\r\nimport { Directive, computed, inject, input } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeFindNode, dpeNodeSourceReferences } from '../../core/dpe-graph';\r\nimport { DpeColumnInfo } from '../../model/dpe-api.model';\r\nimport { Diagnostic } from '../../model/dpe-diagnostics.model';\r\nimport { DpeAnyNode, DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n@Directive()\r\nexport abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNode> {\r\n protected readonly store = inject(DpeDocumentStore);\r\n\r\n readonly nodeName = input.required<string>();\r\n readonly node = input.required<TNode>();\r\n\r\n /** La collezione di appartenenza: la sa l'ispettore, serve per scrivere nello store. */\r\n abstract readonly collection: DpeNodeCollectionName;\r\n\r\n /** Le diagnostiche ancorate a questo nodo, come le ha date il backend (**I6**). */\r\n readonly diagnostics = computed<readonly Diagnostic[]>(\r\n () => this.store.diagnosticsByNode().get(this.nodeName())?.diagnostics ?? [],\r\n );\r\n\r\n /**\r\n * Il nodo e' valido ma non compilabile (**I10**): l'ispettore lo dice in testa, perche' e'\r\n * l'informazione che spiega perche' non compare nessun SQL — e non c'e' niente da correggere.\r\n */\r\n readonly isNotCompilable = computed(\r\n () =>\r\n (this.store.diagnosticsByNode().get(this.nodeName())?.isNotCompilable ?? false) ||\r\n this.store.schemaByNode().get(this.nodeName())?.isCompilable === false,\r\n );\r\n\r\n /** Colonne prodotte dal nodo, secondo il backend. Mai calcolate qui (**I4**). */\r\n readonly outputColumns = computed<readonly DpeColumnInfo[]>(\r\n () => this.store.schemaByNode().get(this.nodeName())?.columns ?? [],\r\n );\r\n\r\n /**\r\n * Colonne disponibili **in ingresso**: l'unione degli schemi dei nodi a monte, nell'ordine.\r\n * Arrivano dal backend; se la validazione non e' ancora tornata l'elenco e' vuoto e i campi\r\n * si digitano a mano — che e' meglio di un elenco indovinato in locale.\r\n */\r\n readonly inputColumns = computed<readonly DpeColumnInfo[]>(() => {\r\n const located = dpeFindNode(this.store.definition(), this.nodeName());\r\n if (!located) {\r\n return [];\r\n }\r\n const schemas = this.store.schemaByNode();\r\n const result: DpeColumnInfo[] = [];\r\n const seen = new Set<string>();\r\n for (const reference of dpeNodeSourceReferences(located)) {\r\n if (!reference.isEdge || !reference.sourceName) {\r\n continue;\r\n }\r\n for (const column of schemas.get(reference.sourceName)?.columns ?? []) {\r\n // Confronto insensibile al caso: le colonne si confrontano cosi' in tutto il sistema,\r\n // perche' cosi' si comportano i quattro database di destinazione.\r\n const key = column.name.toLowerCase();\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n result.push(column);\r\n }\r\n }\r\n }\r\n return result;\r\n });\r\n\r\n /** I parametri dichiarati sulla radice: servono a filtri e mapping dei writeback. */\r\n readonly parameters = computed(() => this.store.definition().parameters ?? []);\r\n\r\n /** Le diagnostiche su un campo preciso, per mostrarle **accanto** al controllo. */\r\n issuesOn(field: string): Diagnostic[] {\r\n return this.diagnostics().filter((diagnostic) => diagnostic.path?.field === field);\r\n }\r\n\r\n hasIssueOn(field: string): boolean {\r\n return this.issuesOn(field).length > 0;\r\n }\r\n\r\n /** Applica una modifica al nodo. */\r\n protected patch(patch: Partial<TNode>): void {\r\n this.store.updateNode(this.collection, this.nodeName(), patch as never);\r\n }\r\n\r\n /**\r\n * Campo semplice: valore vuoto → chiave **rimossa**, non stringa vuota. Il backend\r\n * distingue assente da vuoto (`DPE_MODEL_REQUIRED_MISSING` contro un valore non valido), e\r\n * su Oracle la stringa vuota **e'** `NULL`: scriverla al posto di un'assenza cambia la\r\n * semantica invece di ripulire il campo.\r\n */\r\n protected setField(field: keyof TNode & string, value: unknown): void {\r\n const patch: Record<string, unknown> = {};\r\n patch[field] = value === '' || value === null ? undefined : value;\r\n this.patch(patch as Partial<TNode>);\r\n }\r\n\r\n /** Numero da un campo di testo: vuoto o non numerico → assente, non `0`. */\r\n protected toNumber(value: string): number | undefined {\r\n if (value.trim() === '') {\r\n return undefined;\r\n }\r\n const parsed = Number(value);\r\n return Number.isFinite(parsed) ? parsed : undefined;\r\n }\r\n\r\n /** Lettura tipizzata di un valore da un evento di input, senza `any` nei template. */\r\n protected valueOf(event: Event): string {\r\n return (event.target as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).value;\r\n }\r\n\r\n protected checkedOf(event: Event): boolean {\r\n return (event.target as HTMLInputElement).checked;\r\n }\r\n}\r\n","/**\r\n * Ispettore dell'aggregazione.\r\n *\r\n * Lo schema di uscita e' `groupBy` (con i loro nomi) **piu'** gli alias delle funzioni, in\r\n * quest'ordine: l'ispettore mostra le due sezioni in quell'ordine per la stessa ragione.\r\n *\r\n * `sourceFieldName` e' ammesso vuoto **solo** per `Count` (conteggio righe). Il contratto lo\r\n * rappresenta con l'assenza e non con la stringa `\"*\"`, quindi il campo si disabilita invece\r\n * di suggerire un valore magico.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateField,\r\n AggregateFunction,\r\n AggregateNode,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst FUNCTIONS: readonly AggregateFunction[] = [\r\n 'Count',\r\n 'CountDistinct',\r\n 'Sum',\r\n 'Min',\r\n 'Max',\r\n 'Avg',\r\n 'StdDev',\r\n 'StdDevPop',\r\n 'Variance',\r\n 'VariancePop',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-aggregate-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"agg-group\">Raggruppa per</label>\r\n <input\r\n id=\"agg-group\"\r\n type=\"text\"\r\n [value]=\"groupByText()\"\r\n placeholder=\"colonne separate da virgola\"\r\n (change)=\"onGroupBy(valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Vuoto = aggregazione globale, una sola riga in uscita.\r\n @if (inputColumns().length > 0) {\r\n Colonne disponibili: {{ columnHint() }}\r\n }\r\n </p>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Funzioni</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna funzione: il nodo non produce colonne calcolate.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Funzione</th>\r\n <th>Colonna</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"agg-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"field.function === 'Count'\"\r\n [attr.placeholder]=\"field.function === 'Count' ? 'tutte le righe' : ''\"\r\n [attr.aria-label]=\"'Colonna della funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias della funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la funzione\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"agg-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi funzione</button>\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n <code>StdDev</code> e le sue varianti non sono supportate da tutti i dialetti: se il\r\n dialetto scelto non le ha, la validazione lo dice con <code>DPE_DIALECT_UNSUPPORTED</code>.\r\n </p>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAggregateInspectorComponent extends DpeNodeInspectorBase<AggregateNode> {\r\n override readonly collection: DpeNodeCollectionName = 'aggregates';\r\n\r\n protected readonly functions = FUNCTIONS;\r\n\r\n readonly fields = computed<readonly AggregateField[]>(() => this.node().fields ?? []);\r\n\r\n readonly groupByText = computed(() => (this.node().groupBy ?? []).join(', '));\r\n\r\n readonly columnHint = computed(() => {\r\n const names = this.inputColumns().map((column) => column.name);\r\n return names.length > 10 ? `${names.slice(0, 10).join(', ')}, …` : names.join(', ');\r\n });\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected onGroupBy(raw: string): void {\r\n const columns = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n this.patch({ groupBy: columns.length > 0 ? columns : undefined });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { function: 'Count', alias: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<AggregateField>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore dell'unione.\r\n *\r\n * Le sorgenti si collegano sul canvas: qui si aggiunge o si toglie una **posizione**, cioe' una\r\n * porta. Sono due gesti diversi e vanno in due posti diversi — togliere una porta con l'arco\r\n * attaccato sul canvas non si capirebbe.\r\n *\r\n * `allowsDisjointSchema` cambia il significato dell'unione (schema comune obbligatorio contro\r\n * unione con colonne nulle): l'etichetta lo dice, perche' il nome del campo da solo no.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport { AppendNode, DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-append-inspector',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().allowsDisjointSchema ?? false\"\r\n (change)=\"setField('allowsDisjointSchema', checkedOf($event))\"\r\n />\r\n Ammetti schemi diversi\r\n </label>\r\n <p class=\"dpe-field__hint\">\r\n @if (node().allowsDisjointSchema) {\r\n Lo schema in uscita e’ l’unione degli alias: le colonne assenti in una sorgente\r\n diventano nulle.\r\n } @else {\r\n Gli schemi delle sorgenti devono coincidere per nome e tipo compatibile; se non\r\n coincidono, la validazione lo dice con <code>DPE_SCHEMA_INCOMPATIBLE_UNION</code>.\r\n }\r\n </p>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Sorgenti ({{ sources().length }})</h4>\r\n <ol class=\"dpe-form\">\r\n @for (source of sources(); track $index) {\r\n <li class=\"dpe-row\">\r\n <span>{{ $index + 1 }}. {{ source || 'non collegata' }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la posizione ' + ($index + 1)\"\r\n (click)=\"removeSource($index)\"\r\n >\r\n ×\r\n </button>\r\n </li>\r\n }\r\n </ol>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addSource()\">Aggiungi posizione</button>\r\n </div>\r\n <p class=\"dpe-field__hint\">Le sorgenti si collegano trascinando un arco sulle porte in alto.</p>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAppendInspectorComponent extends DpeNodeInspectorBase<AppendNode> {\r\n override readonly collection: DpeNodeCollectionName = 'appends';\r\n\r\n readonly sources = computed<readonly string[]>(() => this.node().sources ?? []);\r\n\r\n protected addSource(): void {\r\n // Stringa vuota e non `undefined`: una posizione vuota **esiste** come porta, e serve un\r\n // elemento nell'array perche' il canvas la disegni.\r\n this.patch({ sources: [...this.sources(), ''] });\r\n }\r\n\r\n protected removeSource(index: number): void {\r\n this.patch({ sources: this.sources().filter((_, position) => position !== index) });\r\n }\r\n}\r\n","/**\r\n * Ispettore del gruppo atomico.\r\n *\r\n * Non e' un nodo del DAG: dichiara che alcune scritture vanno applicate dall'host **nella stessa\r\n * transazione**, nell'ordine dato. La libreria non apre transazioni — lo dice nel risultato e\r\n * l'host obbedisce — e l'avviso serve a non far credere che qui ci sia un `BEGIN`.\r\n *\r\n * I riferimenti sono a `WritebackNode` con destinazione `Database`: l'elenco e' chiuso a quelli,\r\n * perche' un gruppo atomico su un file non significherebbe niente.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AtomicWritebackNode,\r\n AtomicWritebackRelationship,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-atomic-writeback-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note\">\r\n La libreria non apre transazioni: questo gruppo <strong>dichiara</strong> che le scritture\r\n elencate vanno applicate insieme, e l’host lo esegue.\r\n </p>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"aw-sequence\">Sequenza</label>\r\n <input\r\n id=\"aw-sequence\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"node().sequence\"\r\n [attr.aria-invalid]=\"hasIssueOn('sequence')\"\r\n (change)=\"setField('sequence', toNumber(valueOf($event)) ?? 1)\"\r\n />\r\n <p class=\"dpe-field__hint\">Nello stesso spazio di numerazione delle scritture.</p>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Relazioni</h4>\r\n @if (relationships().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna relazione.</p>\r\n }\r\n @for (relationship of relationships(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-parent-' + $index\">Scrittura padre</label>\r\n <select\r\n [id]=\"'aw-parent-' + $index\"\r\n [dpeValue]=\"relationship.parentWritebackName ?? ''\"\r\n (change)=\"patchRelationship($index, { parentWritebackName: valueOf($event) || undefined })\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (writeback of databaseWritebacks(); track $index) {\r\n <option [value]=\"writeback.name\">{{ writeback.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-child-' + $index\">Scrittura figlia</label>\r\n <select\r\n [id]=\"'aw-child-' + $index\"\r\n [dpeValue]=\"relationship.childWritebackName ?? ''\"\r\n (change)=\"patchRelationship($index, { childWritebackName: valueOf($event) || undefined })\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (writeback of databaseWritebacks(); track $index) {\r\n <option [value]=\"writeback.name\">{{ writeback.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-seq-' + $index\">Ordine</label>\r\n <input\r\n [id]=\"'aw-seq-' + $index\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"relationship.sequence\"\r\n (change)=\"patchRelationship($index, { sequence: toNumber(valueOf($event)) ?? 1 })\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-pfield-' + $index\">Campo padre</label>\r\n <input\r\n [id]=\"'aw-pfield-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.parentFieldName ?? ''\"\r\n (change)=\"patchRelationship($index, { parentFieldName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-cfield-' + $index\">Campo figlio</label>\r\n <input\r\n [id]=\"'aw-cfield-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.childFieldName ?? ''\"\r\n (change)=\"patchRelationship($index, { childFieldName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-rel-' + $index\">Relazione</label>\r\n <input\r\n [id]=\"'aw-rel-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.relationshipName ?? ''\"\r\n (change)=\"patchRelationship($index, { relationshipName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la relazione ' + ($index + 1)\"\r\n (click)=\"removeRelationship($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addRelationship()\">Aggiungi relazione</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAtomicWritebackInspectorComponent extends DpeNodeInspectorBase<AtomicWritebackNode> {\r\n override readonly collection: DpeNodeCollectionName = 'atomicWritebacks';\r\n\r\n readonly relationships = computed<readonly AtomicWritebackRelationship[]>(\r\n () => this.node().relationships ?? [],\r\n );\r\n\r\n readonly databaseWritebacks = computed(() =>\r\n (this.store.definition().writebacks ?? []).filter((writeback) => writeback.target === 'Database'),\r\n );\r\n\r\n protected addRelationship(): void {\r\n const nextSequence =\r\n this.relationships().reduce((max, relationship) => Math.max(max, relationship.sequence), 0) + 1;\r\n this.patch({ relationships: [...this.relationships(), { sequence: nextSequence }] });\r\n }\r\n\r\n protected removeRelationship(index: number): void {\r\n this.patch({\r\n relationships: this.relationships().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchRelationship(index: number, patch: Partial<AtomicWritebackRelationship>): void {\r\n this.patch({\r\n relationships: this.relationships().map((relationship, position) =>\r\n position === index ? { ...relationship, ...patch } : relationship,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Editor di un `ColumnType`: i sei tipi logici e i loro attributi condizionali.\r\n *\r\n * I campi che compaiono dipendono dal `kind`, e la dipendenza e' quella del contratto:\r\n * `length` per `String`, `precision`/`scale` per `Number`, `allowedValues` per `Enum`. Mostrare\r\n * sempre tutto renderebbe rappresentabile un tipo che il backend rifiuta; mostrare solo cio'\r\n * che serve rende quello stato non rappresentabile.\r\n *\r\n * Cosa **non** fa: non decide se `length` sia obbligatorio in questo punto della definizione —\r\n * lo e' nei campi *dichiarati* e non altrove, e a dirlo e' la validazione\r\n * (`DPE_MODEL_CONDITIONAL_REQUIRED`).\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\r\n\r\nimport { ColumnType, LogicalType } from '../../model/dpe-definition.model';\r\n\r\nconst LOGICAL_TYPES: readonly LogicalType[] = [\r\n 'String',\r\n 'Number',\r\n 'Integer',\r\n 'DateTime',\r\n 'Boolean',\r\n 'Enum',\r\n];\r\n\r\nimport { DpeSelectValueDirective } from './dpe-select-value.directive';\r\n\r\n@Component({\r\n selector: 'dpe-column-type-editor',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: './dpe-form.css',\r\n template: `\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-kind'\">Tipo</label>\r\n <select [id]=\"controlId() + '-kind'\" [dpeValue]=\"kind()\" (change)=\"onKind(text($event))\">\r\n @for (option of types; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (kind() === 'String') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-length'\">Lunghezza</label>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [id]=\"controlId() + '-length'\"\r\n [value]=\"value()?.length ?? ''\"\r\n (change)=\"onNumber('length', text($event))\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (kind() === 'Number') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-precision'\">Precisione</label>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [id]=\"controlId() + '-precision'\"\r\n [value]=\"value()?.precision ?? ''\"\r\n (change)=\"onNumber('precision', text($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-scale'\">Decimali</label>\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n [id]=\"controlId() + '-scale'\"\r\n [value]=\"value()?.scale ?? ''\"\r\n (change)=\"onNumber('scale', text($event))\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (kind() === 'Enum') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-values'\">Valori ammessi</label>\r\n <input\r\n type=\"text\"\r\n [id]=\"controlId() + '-values'\"\r\n [value]=\"allowedValues()\"\r\n placeholder=\"separati da virgola\"\r\n (change)=\"onAllowedValues(text($event))\"\r\n />\r\n </div>\r\n }\r\n `,\r\n})\r\nexport class DpeColumnTypeEditorComponent {\r\n readonly value = input<ColumnType | undefined>(undefined);\r\n readonly controlId = input('dpe-type');\r\n readonly valueChange = output<ColumnType>();\r\n\r\n protected readonly types = LOGICAL_TYPES;\r\n\r\n readonly kind = computed<LogicalType>(() => this.value()?.kind ?? 'String');\r\n\r\n readonly allowedValues = computed(() => (this.value()?.allowedValues ?? []).join(', '));\r\n\r\n protected onKind(kind: string): void {\r\n // Cambiare tipo **azzera** gli attributi dell'altro: una `length` rimasta su un `Number`\r\n // sarebbe un campo che il backend ignora oggi e rifiuta domani.\r\n this.valueChange.emit({ kind: kind as LogicalType });\r\n }\r\n\r\n protected onNumber(field: 'length' | 'precision' | 'scale', raw: string): void {\r\n const parsed = raw.trim() === '' ? undefined : Number(raw);\r\n this.valueChange.emit({\r\n ...(this.value() ?? { kind: this.kind() }),\r\n [field]: Number.isFinite(parsed) ? parsed : undefined,\r\n });\r\n }\r\n\r\n protected onAllowedValues(raw: string): void {\r\n const values = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n this.valueChange.emit({\r\n ...(this.value() ?? { kind: 'Enum' }),\r\n allowedValues: values.length > 0 ? values : undefined,\r\n });\r\n }\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLInputElement | HTMLSelectElement).value;\r\n }\r\n}\r\n","/**\r\n * Ispettore del nodo personalizzato.\r\n *\r\n * `outputFields` non e' un campo come gli altri: **e' l'unica cosa che tiene in piedi lo schema\r\n * a valle** (**I4**). Senza uno schema dichiarato la propagazione si interrompe e tutto cio' che\r\n * sta dopo diventa invalidabile — quindi l'avviso non e' generico, dice esattamente questo.\r\n *\r\n * Come il `Forecast`, e' modellato e non compilabile in v1.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n ColumnType,\r\n CustomNode,\r\n CustomNodeParameter,\r\n DeclaredField,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-custom-node-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note dpe-note--not-compilable\">\r\n Nodo modellato per intero ma <strong>non traducibile in SQL</strong> nella versione 1.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"cn-extension\">Estensione</label>\r\n <input\r\n id=\"cn-extension\"\r\n type=\"text\"\r\n [value]=\"node().extensionName ?? ''\"\r\n (change)=\"setField('extensionName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"cn-namespace\">Namespace</label>\r\n <input\r\n id=\"cn-namespace\"\r\n type=\"text\"\r\n [value]=\"node().extensionNamespace ?? ''\"\r\n (change)=\"setField('extensionNamespace', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Sorgenti ({{ sources().length }})</h4>\r\n @for (source of sources(); track $index) {\r\n <div class=\"dpe-row\">\r\n <span>{{ $index + 1 }}. {{ source || 'non collegata' }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la posizione ' + ($index + 1)\"\r\n (click)=\"removeSource($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addSource()\">Aggiungi posizione</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Parametri dell’estensione</h4>\r\n @for (parameter of nodeParameters(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n [value]=\"parameter.name\"\r\n [attr.aria-label]=\"'Nome del parametro ' + ($index + 1)\"\r\n (change)=\"patchParameter($index, { name: valueOf($event) })\"\r\n />\r\n <input\r\n type=\"text\"\r\n [value]=\"parameter.value\"\r\n [attr.aria-label]=\"'Valore del parametro ' + ($index + 1)\"\r\n (change)=\"patchParameter($index, { value: valueOf($event) })\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeParameter($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addParameter()\">Aggiungi parametro</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Schema in uscita</h4>\r\n <p class=\"dpe-note dpe-note--warning\">\r\n Va dichiarato qui: non esiste un registro delle estensioni da cui ricavarlo. Se manca,\r\n la propagazione dello schema si interrompe e <strong>tutto cio’ che sta a valle</strong>\r\n diventa invalidabile.\r\n </p>\r\n @for (field of outputFields(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'cn-field-' + $index\">Nome</label>\r\n <input\r\n [id]=\"'cn-field-' + $index\"\r\n type=\"text\"\r\n [value]=\"field.name\"\r\n (change)=\"patchOutput($index, { name: valueOf($event) })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la colonna ' + field.name\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n <dpe-column-type-editor\r\n [value]=\"field.type\"\r\n [controlId]=\"'cn-type-' + $index\"\r\n (valueChange)=\"patchOutput($index, { type: $event })\"\r\n />\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addOutput()\">Aggiungi colonna</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeCustomNodeInspectorComponent extends DpeNodeInspectorBase<CustomNode> {\r\n override readonly collection: DpeNodeCollectionName = 'customNodes';\r\n\r\n readonly sources = computed<readonly string[]>(() => this.node().sources ?? []);\r\n readonly nodeParameters = computed<readonly CustomNodeParameter[]>(\r\n () => this.node().parameters ?? [],\r\n );\r\n readonly outputFields = computed<readonly DeclaredField[]>(() => this.node().outputFields ?? []);\r\n\r\n protected addSource(): void {\r\n this.patch({ sources: [...this.sources(), ''] });\r\n }\r\n\r\n protected removeSource(index: number): void {\r\n this.patch({ sources: this.sources().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected addParameter(): void {\r\n this.patch({ parameters: [...this.nodeParameters(), { name: '', value: '' }] });\r\n }\r\n\r\n protected removeParameter(index: number): void {\r\n this.patch({\r\n parameters: this.nodeParameters().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchParameter(index: number, patch: Partial<CustomNodeParameter>): void {\r\n this.patch({\r\n parameters: this.nodeParameters().map((parameter, position) =>\r\n position === index ? { ...parameter, ...patch } : parameter,\r\n ),\r\n });\r\n }\r\n\r\n protected addOutput(): void {\r\n this.patch({\r\n outputFields: [...this.outputFields(), { name: '', type: { kind: 'String' } }],\r\n });\r\n }\r\n\r\n protected removeOutput(index: number): void {\r\n this.patch({ outputFields: this.outputFields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchOutput(index: number, patch: Partial<DeclaredField> & { type?: ColumnType }): void {\r\n this.patch({\r\n outputFields: this.outputFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore della sorgente.\r\n *\r\n * I campi che compaiono dipendono dal `kind`: `tableName` per `Table`, le opzioni CSV per\r\n * `Csv`, il nome del dataset per `ExternalDataset`. Il `declaredType` di un campo si mostra\r\n * **solo** dove serve — per `Table` il tipo lo da' il provider di metadati e quello dichiarato\r\n * viene ignorato: mostrarlo farebbe credere di poterlo decidere.\r\n *\r\n * I tre esiti del provider (ADR 0004) restano distinti: tabella dichiarata, dichiarata **senza\r\n * campi**, sconosciuta. Nel secondo caso i nomi dei campi si digitano a mano e non c'e' niente\r\n * da correggere; nel terzo la diagnostica autorevole e' `DPE_REF_UNKNOWN_TABLE` del backend.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, effect, inject } from '@angular/core';\r\n\r\nimport { DpeMetadataStore } from '../../core/dpe-metadata.store';\r\nimport {\r\n ColumnType,\r\n CsvDelimiter,\r\n DataSourceField,\r\n DataSourceKind,\r\n DataSourceNode,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly DataSourceKind[] = ['Table', 'Csv', 'ExternalDataset'];\r\nconst DELIMITERS: readonly CsvDelimiter[] = ['Comma', 'Semicolon', 'Tab', 'Pipe', 'Caret', 'Backquote'];\r\n\r\n@Component({\r\n selector: 'dpe-data-source-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-kind\">Tipo di sorgente</label>\r\n <select id=\"ds-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @switch (node().kind) {\r\n @case ('Table') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-table\">Tabella</label>\r\n <input\r\n id=\"ds-table\"\r\n type=\"text\"\r\n list=\"ds-table-options\"\r\n [value]=\"node().tableName ?? ''\"\r\n [attr.aria-invalid]=\"hasIssueOn('tableName')\"\r\n (change)=\"setField('tableName', valueOf($event))\"\r\n />\r\n <!--\r\n Elenco proposto (datalist) e non tendina chiusa: le tabelle possono essere molte e\r\n il nome resta digitabile — un catalogo incompleto non deve impedire di scrivere.\r\n -->\r\n <datalist id=\"ds-table-options\">\r\n @for (table of tables(); track $index) {\r\n <option [value]=\"table.name\">{{ table.description || table.name }}</option>\r\n }\r\n </datalist>\r\n <p class=\"dpe-field__hint\">{{ tableHint() }}</p>\r\n @for (issue of issuesOn('tableName'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n }\r\n @case ('Csv') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-location\">Posizione del file</label>\r\n <input\r\n id=\"ds-location\"\r\n type=\"text\"\r\n [value]=\"node().csvOptions?.location ?? ''\"\r\n (change)=\"patchCsv({ location: valueOf($event) })\"\r\n />\r\n <p class=\"dpe-field__hint\">Identificatore opaco: lo risolve l’host, non la libreria.</p>\r\n </div>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-delimiter\">Separatore</label>\r\n <select\r\n id=\"ds-delimiter\"\r\n [dpeValue]=\"node().csvOptions?.delimiter ?? 'Comma'\"\r\n (change)=\"patchCsv({ delimiter: valueOf($event) })\"\r\n >\r\n @for (delimiter of delimiters; track $index) {\r\n <option [value]=\"delimiter\">{{ delimiter }}</option>\r\n }\r\n </select>\r\n </div>\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().csvOptions?.hasHeaderRow ?? true\"\r\n (change)=\"patchCsv({ hasHeaderRow: checkedOf($event) })\"\r\n />\r\n Prima riga di intestazione\r\n </label>\r\n </div>\r\n }\r\n @case ('ExternalDataset') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-dataset\">Dataset esterno</label>\r\n <input\r\n id=\"ds-dataset\"\r\n type=\"text\"\r\n [value]=\"node().externalDatasetName ?? ''\"\r\n (change)=\"setField('externalDatasetName', valueOf($event))\"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo: la sorgente non produce colonne.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Nome</th>\r\n <th>Alias</th>\r\n @if (declaresTypes()) {\r\n <th>Tipo</th>\r\n }\r\n <th>PK</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"ds-field-options\"\r\n [value]=\"field.name\"\r\n [attr.aria-label]=\"'Nome del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { name: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias ?? ''\"\r\n [attr.aria-label]=\"'Alias del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n @if (declaresTypes()) {\r\n <td>\r\n <dpe-column-type-editor\r\n [value]=\"field.declaredType\"\r\n [controlId]=\"'ds-field-' + $index\"\r\n (valueChange)=\"patchField($index, { declaredType: $event })\"\r\n />\r\n </td>\r\n }\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"field.isPrimaryKey ?? false\"\r\n [attr.aria-label]=\"'Chiave primaria del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { isPrimaryKey: checkedOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi il campo ' + field.name\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"ds-field-options\">\r\n @for (candidate of providerFields(); track $index) {\r\n <option [value]=\"candidate.name\">{{ candidate.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeDataSourceInspectorComponent extends DpeNodeInspectorBase<DataSourceNode> {\r\n private readonly metadata = inject(DpeMetadataStore);\r\n\r\n override readonly collection: DpeNodeCollectionName = 'dataSources';\r\n\r\n protected readonly kinds = KINDS;\r\n protected readonly delimiters = DELIMITERS;\r\n\r\n readonly tables = computed(() => this.metadata.tables());\r\n\r\n readonly fields = computed<readonly DataSourceField[]>(() => this.node().fields ?? []);\r\n\r\n /** Il tipo si dichiara solo dove non c'e' un catalogo da interrogare. */\r\n readonly declaresTypes = computed(() => this.node().kind !== 'Table');\r\n\r\n readonly providerFields = computed(() => {\r\n const tableName = this.node().tableName;\r\n if (!tableName) {\r\n return [];\r\n }\r\n return this.metadata.stateOf(tableName)?.table?.fields ?? [];\r\n });\r\n\r\n /** I tre esiti in una frase: sono situazioni diverse e vanno dette diverse. */\r\n readonly tableHint = computed(() => {\r\n const tableName = this.node().tableName;\r\n if (!tableName) {\r\n return 'Nome noto al provider di metadati dell’host, non al catalogo del database.';\r\n }\r\n const state = this.metadata.stateOf(tableName);\r\n if (!state) {\r\n return 'Lettura dei metadati in corso…';\r\n }\r\n switch (state.outcome) {\r\n case 'Declared':\r\n return `Tabella dichiarata: ${state.table?.fields?.length ?? 0} campi noti.`;\r\n case 'DeclaredWithoutFields':\r\n return 'Tabella dichiarata senza campi: i nomi si scrivono a mano, non c’e’ nulla da correggere.';\r\n case 'Unknown':\r\n return 'Tabella sconosciuta al provider: la validazione lo segnalera’.';\r\n default:\r\n return '';\r\n }\r\n });\r\n\r\n constructor() {\r\n super();\r\n this.metadata.loadTables();\r\n // Si chiede la descrizione della tabella riferita, una volta per nome. La cache e' dello\r\n // store: cambiare nodo e tornare indietro non rifa' la chiamata.\r\n effect(() => {\r\n const tableName = this.node().tableName;\r\n if (tableName) {\r\n this.metadata.describe(tableName);\r\n }\r\n });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { name: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(\r\n index: number,\r\n patch: Partial<DataSourceField> & { declaredType?: ColumnType },\r\n ): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected patchCsv(patch: Partial<{ location: string; delimiter: string; hasHeaderRow: boolean }>): void {\r\n const current = this.node().csvOptions ?? { location: '' };\r\n this.patch({\r\n csvOptions: { ...current, ...(patch as Partial<typeof current>) },\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del filtro.\r\n *\r\n * Il vincolo condizionale del contratto governa cosa si vede: con `isDynamic` falso servono i\r\n * criteri e la `condition`; con `isDynamic` vero serve il nome del parametro di filtro, e i\r\n * criteri **non** si mostrano affatto. Mostrarli entrambi renderebbe rappresentabile uno stato\r\n * che il backend rifiuta (`DPE_MODEL_CONDITIONAL_FORBIDDEN`).\r\n *\r\n * `condition` non e' SQL: e' una combinazione booleana dei numeri di sequenza dei criteri\r\n * (`1 AND (2 OR 3)`), ed e' l'unico linguaggio che il backend parsifica davvero. L'etichetta lo\r\n * dice, perche' una casella accanto a \"SQL nativo\" altrove invita a scriverci dentro SQL.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n FilterCriterion,\r\n FilterNode,\r\n FilterOperator,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst OPERATORS: readonly FilterOperator[] = [\r\n 'Equals',\r\n 'NotEquals',\r\n 'GreaterThan',\r\n 'GreaterThanOrEqual',\r\n 'LessThan',\r\n 'LessThanOrEqual',\r\n 'StartsWith',\r\n 'EndsWith',\r\n 'Contains',\r\n 'DoesNotContain',\r\n 'IsNull',\r\n 'IsNotNull',\r\n 'In',\r\n 'NotIn',\r\n];\r\n\r\n/** Gli unici operatori che non prendono un valore: e' forma del controllo, non validazione. */\r\nconst UNARY: readonly FilterOperator[] = ['IsNull', 'IsNotNull'];\r\n\r\n@Component({\r\n selector: 'dpe-filter-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().isDynamic ?? false\"\r\n (change)=\"setField('isDynamic', checkedOf($event))\"\r\n />\r\n Filtro dinamico (i criteri arrivano da un parametro)\r\n </label>\r\n\r\n @if (node().isDynamic) {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"filter-parameter\">Parametro di filtro</label>\r\n <select\r\n id=\"filter-parameter\"\r\n [dpeValue]=\"node().filterParameterName ?? ''\"\r\n (change)=\"setField('filterParameterName', valueOf($event))\"\r\n >\r\n <option value=\"\">— non impostato —</option>\r\n @for (parameter of filterParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.label }} ({{ parameter.name }})</option>\r\n }\r\n </select>\r\n @if (filterParameters().length === 0) {\r\n <p class=\"dpe-field__hint\">\r\n Nessun parametro con ruolo <code>Filter</code> dichiarato sulla definizione.\r\n </p>\r\n }\r\n </div>\r\n } @else {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Criteri</h4>\r\n @if (criteria().length === 0) {\r\n <p class=\"dpe-empty\">Nessun criterio.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Seq.</th>\r\n <th>Colonna</th>\r\n <th>Operatore</th>\r\n <th>Valore</th>\r\n <th>Parametro</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (criterion of criteria(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"criterion.sequence\"\r\n [attr.aria-label]=\"'Sequenza del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { sequence: number(valueOf($event)) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"filter-columns\"\r\n [value]=\"criterion.sourceFieldName\"\r\n [attr.aria-label]=\"'Colonna del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { sourceFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"criterion.operator\"\r\n [attr.aria-label]=\"'Operatore del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { operator: operator(valueOf($event)) })\"\r\n >\r\n @for (option of operators; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n @if (!isUnary(criterion.operator)) {\r\n <input\r\n type=\"text\"\r\n [value]=\"criterion.value ?? ''\"\r\n [disabled]=\"!!criterion.inputVariable\"\r\n [attr.aria-label]=\"'Valore del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { value: valueOf($event) || undefined })\"\r\n />\r\n }\r\n </td>\r\n <td>\r\n @if (!isUnary(criterion.operator)) {\r\n <!--\r\n Valore e parametro sono mutuamente esclusivi: sceglierne uno disabilita\r\n l’altro, così lo stato \"entrambi\" non e’ rappresentabile.\r\n -->\r\n <select\r\n [dpeValue]=\"criterion.inputVariable ?? ''\"\r\n [attr.aria-label]=\"'Parametro del criterio ' + ($index + 1)\"\r\n (change)=\"onInputVariable($index, valueOf($event))\"\r\n >\r\n <option value=\"\">— nessuno —</option>\r\n @for (parameter of valueParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }}</option>\r\n }\r\n </select>\r\n }\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi il criterio ' + criterion.sequence\"\r\n (click)=\"removeCriterion($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"filter-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addCriterion()\">Aggiungi criterio</button>\r\n </div>\r\n </section>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"filter-condition\">Condizione sui numeri di sequenza</label>\r\n <input\r\n id=\"filter-condition\"\r\n type=\"text\"\r\n [value]=\"node().condition ?? ''\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n [attr.aria-invalid]=\"hasIssueOn('condition')\"\r\n (change)=\"setField('condition', valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Non e’ SQL: solo numeri di sequenza, <code>AND</code>, <code>OR</code>,\r\n <code>NOT</code> e parentesi.\r\n </p>\r\n @for (issue of issuesOn('condition'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n `,\r\n})\r\nexport class DpeFilterInspectorComponent extends DpeNodeInspectorBase<FilterNode> {\r\n override readonly collection: DpeNodeCollectionName = 'filters';\r\n\r\n protected readonly operators = OPERATORS;\r\n\r\n readonly criteria = computed<readonly FilterCriterion[]>(() => this.node().criteria ?? []);\r\n\r\n readonly filterParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Filter'),\r\n );\r\n\r\n readonly valueParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Value'),\r\n );\r\n\r\n protected isUnary(operator: FilterOperator): boolean {\r\n return UNARY.includes(operator);\r\n }\r\n\r\n protected operator(value: string): FilterOperator {\r\n return value as FilterOperator;\r\n }\r\n\r\n protected number(value: string): number {\r\n // Forma del campo: un numero di sequenza non numerico non e' rappresentabile, e 1 e' il\r\n // minimo dichiarato. Non e' validazione: l'unicita' la verifica il backend.\r\n const parsed = Number(value);\r\n return Number.isFinite(parsed) && parsed >= 1 ? Math.trunc(parsed) : 1;\r\n }\r\n\r\n protected addCriterion(): void {\r\n const nextSequence =\r\n this.criteria().reduce((max, criterion) => Math.max(max, criterion.sequence), 0) + 1;\r\n this.patch({\r\n criteria: [\r\n ...this.criteria(),\r\n { sequence: nextSequence, sourceFieldName: '', operator: 'Equals' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeCriterion(index: number): void {\r\n this.patch({ criteria: this.criteria().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchCriterion(index: number, patch: Partial<FilterCriterion>): void {\r\n this.patch({\r\n criteria: this.criteria().map((criterion, position) =>\r\n position === index ? { ...criterion, ...patch } : criterion,\r\n ),\r\n });\r\n }\r\n\r\n /** Scegliere un parametro **toglie** il valore letterale: sono esclusivi per contratto. */\r\n protected onInputVariable(index: number, name: string): void {\r\n this.patchCriterion(index, {\r\n inputVariable: name === '' ? undefined : name,\r\n value: name === '' ? this.criteria()[index]?.value : undefined,\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore della previsione.\r\n *\r\n * Il nodo e' **modellato per intero e non compilabile in v1**: l'avviso sta in testa e non a\r\n * pie' di pagina, perche' e' la prima cosa da sapere prima di costruirci una pipeline intorno.\r\n * Non e' un errore dell'utente — e' `DPE_NODE_NOT_COMPILABLE`, l'unico codice che significa\r\n * \"hai fatto bene, siamo noi\" — quindi il colore non e' quello dell'errore.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateFunction,\r\n DatePart,\r\n DpeNodeCollectionName,\r\n ForecastAccuracy,\r\n ForecastAggregationField,\r\n ForecastGroupField,\r\n ForecastModelType,\r\n ForecastNode,\r\n ForecastPeriodType,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst PERIOD_TYPES: readonly ForecastPeriodType[] = [\r\n 'Year',\r\n 'YearQuarter',\r\n 'YearMonth',\r\n 'YearWeek',\r\n 'YearMonthDay',\r\n 'FiscalYear',\r\n 'FiscalYearQuarter',\r\n 'FiscalYearMonth',\r\n 'FiscalYearWeek',\r\n];\r\n\r\nconst MODELS: readonly ForecastModelType[] = ['Auto', 'Additive', 'Multiplicative'];\r\nconst ACCURACIES: readonly ForecastAccuracy[] = ['None', 'Eighty', 'NinetyFive'];\r\nconst FUNCTIONS: readonly AggregateFunction[] = ['Sum', 'Avg', 'Min', 'Max', 'Count'];\r\nconst DATE_PARTS: readonly DatePart[] = [\r\n 'Second',\r\n 'Minute',\r\n 'Hour',\r\n 'Day',\r\n 'Week',\r\n 'Month',\r\n 'Quarter',\r\n 'Year',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-forecast-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note dpe-note--not-compilable\">\r\n Nodo modellato per intero ma <strong>non traducibile in SQL</strong> nella versione 1:\r\n puoi descriverlo e salvarlo, la compilazione lo rifiuta con\r\n <code>DPE_NODE_NOT_COMPILABLE</code>. Non c’e’ niente da correggere.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-date\">Campo data</label>\r\n <input\r\n id=\"fc-date\"\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"node().dateFieldName ?? ''\"\r\n (change)=\"setField('dateFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-period\">Periodo</label>\r\n <select\r\n id=\"fc-period\"\r\n [dpeValue]=\"node().periodType ?? 'YearMonth'\"\r\n (change)=\"setField('periodType', valueOf($event))\"\r\n >\r\n @for (period of periodTypes; track $index) {\r\n <option [value]=\"period\">{{ period }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-count\">Numero di periodi</label>\r\n <input\r\n id=\"fc-count\"\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"100\"\r\n [value]=\"node().periodCount ?? 1\"\r\n (change)=\"setField('periodCount', toNumber(valueOf($event)))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-start\">Alias inizio periodo</label>\r\n <input\r\n id=\"fc-start\"\r\n type=\"text\"\r\n [value]=\"node().periodStartFieldName ?? ''\"\r\n (change)=\"setField('periodStartFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-model\">Modello</label>\r\n <select\r\n id=\"fc-model\"\r\n [dpeValue]=\"node().modelType ?? 'Auto'\"\r\n (change)=\"setField('modelType', valueOf($event))\"\r\n >\r\n @for (model of models; track $index) {\r\n <option [value]=\"model\">{{ model }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-seasonality\">Stagionalita’</label>\r\n <input\r\n id=\"fc-seasonality\"\r\n type=\"number\"\r\n min=\"2\"\r\n max=\"24\"\r\n [value]=\"node().seasonality ?? ''\"\r\n placeholder=\"automatica\"\r\n (change)=\"setField('seasonality', toNumber(valueOf($event)))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-accuracy\">Intervallo di confidenza</label>\r\n <select\r\n id=\"fc-accuracy\"\r\n [dpeValue]=\"node().accuracyPercent ?? 'None'\"\r\n (change)=\"setField('accuracyPercent', valueOf($event))\"\r\n >\r\n @for (accuracy of accuracies; track $index) {\r\n <option [value]=\"accuracy\">{{ accuracy }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().excludesLastPeriod ?? false\"\r\n (change)=\"setField('excludesLastPeriod', checkedOf($event))\"\r\n />\r\n Escludi l’ultimo periodo (spesso incompleto)\r\n </label>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi da prevedere</h4>\r\n @for (field of aggregationFields(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"field.fieldName\"\r\n [attr.aria-label]=\"'Campo ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { fieldName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.resultAlias\"\r\n [attr.aria-label]=\"'Alias ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { resultAlias: valueOf($event) })\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeAggregation($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addAggregation()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Raggruppamenti</h4>\r\n @for (group of groupFields(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"group.fieldName\"\r\n [attr.aria-label]=\"'Campo di raggruppamento ' + ($index + 1)\"\r\n (change)=\"patchGroup($index, { fieldName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"group.datePart ?? ''\"\r\n [attr.aria-label]=\"'Parte di data ' + ($index + 1)\"\r\n (change)=\"patchGroup($index, { datePart: asDatePart(valueOf($event)) })\"\r\n >\r\n <option value=\"\">— nessuna —</option>\r\n @for (part of dateParts; track $index) {\r\n <option [value]=\"part\">{{ part }}</option>\r\n }\r\n </select>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il raggruppamento\"\r\n (click)=\"removeGroup($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <p class=\"dpe-field__hint\">\r\n La parte di data e’ richiesta quando il campo e’ di tipo <code>DateTime</code>.\r\n </p>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addGroup()\">Aggiungi raggruppamento</button>\r\n </div>\r\n </section>\r\n\r\n <datalist id=\"fc-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeForecastInspectorComponent extends DpeNodeInspectorBase<ForecastNode> {\r\n override readonly collection: DpeNodeCollectionName = 'forecasts';\r\n\r\n protected readonly periodTypes = PERIOD_TYPES;\r\n protected readonly models = MODELS;\r\n protected readonly accuracies = ACCURACIES;\r\n protected readonly functions = FUNCTIONS;\r\n protected readonly dateParts = DATE_PARTS;\r\n\r\n readonly aggregationFields = computed<readonly ForecastAggregationField[]>(\r\n () => this.node().aggregationFields ?? [],\r\n );\r\n\r\n readonly groupFields = computed<readonly ForecastGroupField[]>(() => this.node().groupFields ?? []);\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected asDatePart(value: string): DatePart | undefined {\r\n return value === '' ? undefined : (value as DatePart);\r\n }\r\n\r\n protected addAggregation(): void {\r\n this.patch({\r\n aggregationFields: [\r\n ...this.aggregationFields(),\r\n { fieldName: '', function: 'Sum', resultAlias: '' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeAggregation(index: number): void {\r\n this.patch({\r\n aggregationFields: this.aggregationFields().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchAggregation(index: number, patch: Partial<ForecastAggregationField>): void {\r\n this.patch({\r\n aggregationFields: this.aggregationFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected addGroup(): void {\r\n this.patch({ groupFields: [...this.groupFields(), { fieldName: '' }] });\r\n }\r\n\r\n protected removeGroup(index: number): void {\r\n this.patch({ groupFields: this.groupFields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchGroup(index: number, patch: Partial<ForecastGroupField>): void {\r\n this.patch({\r\n groupFields: this.groupFields().map((group, position) =>\r\n position === index ? { ...group, ...patch } : group,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del percorso gerarchico.\r\n *\r\n * E' il nodo che pone il vincolo di capacita' sul dialetto: richiede CTE ricorsive. Non lo\r\n * verifichiamo qui — `DPE_DIALECT_UNSUPPORTED` arriva dalla validazione — ma lo diciamo, perche'\r\n * un utente che non sa che questo nodo dipende dal dialetto non capirebbe la diagnostica.\r\n *\r\n * I campi di aggregazione compaiono solo con `isAggregationRequired`: e' il vincolo condizionale\r\n * del contratto, e senza il flag sono campi che il backend rifiuta.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateField,\r\n AggregateFunction,\r\n DpeNodeCollectionName,\r\n HierarchyPathNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst FUNCTIONS: readonly AggregateFunction[] = [\r\n 'Count',\r\n 'CountDistinct',\r\n 'Sum',\r\n 'Min',\r\n 'Max',\r\n 'Avg',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-hierarchy-path-inspector',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note\">\r\n Richiede le CTE ricorsive del dialetto di destinazione: se il dialetto scelto non le\r\n supporta, la validazione lo segnala come limite del <strong>dialetto</strong>, non della\r\n definizione.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-self\">Campo chiave</label>\r\n <input\r\n id=\"hp-self\"\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"node().selfFieldName ?? ''\"\r\n (change)=\"setField('selfFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-parent\">Campo padre</label>\r\n <input\r\n id=\"hp-parent\"\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"node().parentFieldName ?? ''\"\r\n (change)=\"setField('parentFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-path\">Alias della colonna di percorso</label>\r\n <input\r\n id=\"hp-path\"\r\n type=\"text\"\r\n [value]=\"node().pathFieldName ?? ''\"\r\n (change)=\"setField('pathFieldName', valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">La produce il backend: e’ di tipo <code>String</code> e non nulla.</p>\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().includesSelfValue ?? true\"\r\n (change)=\"setField('includesSelfValue', checkedOf($event))\"\r\n />\r\n Includi il valore del nodo corrente nel percorso\r\n </label>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-rollup\">Alias della percentuale di rollup</label>\r\n <input\r\n id=\"hp-rollup\"\r\n type=\"text\"\r\n [value]=\"node().rollupPercentageFieldName ?? ''\"\r\n (change)=\"setField('rollupPercentageFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().isAggregationRequired ?? false\"\r\n (change)=\"setField('isAggregationRequired', checkedOf($event))\"\r\n />\r\n Aggrega lungo la gerarchia\r\n </label>\r\n\r\n @if (node().isAggregationRequired) {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi aggregati</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo: con l’aggregazione attiva ne serve almeno uno.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Funzione</th>\r\n <th>Colonna</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <select\r\n [value]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"field.function === 'Count'\"\r\n [attr.aria-label]=\"'Colonna ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n }\r\n\r\n <datalist id=\"hp-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeHierarchyPathInspectorComponent extends DpeNodeInspectorBase<HierarchyPathNode> {\r\n override readonly collection: DpeNodeCollectionName = 'hierarchyPaths';\r\n\r\n protected readonly functions = FUNCTIONS;\r\n\r\n readonly fields = computed<readonly AggregateField[]>(() => this.node().aggregateFields ?? []);\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ aggregateFields: [...this.fields(), { function: 'Sum', alias: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ aggregateFields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<AggregateField>): void {\r\n this.patch({\r\n aggregateFields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del join.\r\n *\r\n * Due cose che il canvas non puo' dire e che quindi stanno qui: quale sorgente e' la\r\n * **primaria** (il lato che sopravvive in un `LeftOuter`) e lo **schema di uscita esplicito** —\r\n * un join produce solo i campi dichiarati in `fields`, non l'unione dei due lati.\r\n *\r\n * `allowsMultipleLookupValues` compare solo con `kind === 'Lookup'`: altrove il contratto lo\r\n * dichiara non significativo, e un interruttore che non fa niente e' peggio di un interruttore\r\n * assente.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n JoinKey,\r\n JoinKind,\r\n JoinNode,\r\n JoinResultField,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly JoinKind[] = ['Inner', 'LeftOuter', 'RightOuter', 'FullOuter', 'Lookup'];\r\n\r\n@Component({\r\n selector: 'dpe-join-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"join-kind\">Tipo di join</label>\r\n <select id=\"join-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n @for (issue of issuesOn('kind'); track $index) {\r\n <!--\r\n Un FullOuter su SQLite e’ DPE_DIALECT_UNSUPPORTED: il messaggio arriva da qui e non\r\n da un controllo locale, perche’ le capacita’ del dialetto le conosce il backend.\r\n -->\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Sorgente primaria</span>\r\n <p class=\"dpe-field__hint\">{{ node().primarySourceName || 'non collegata' }}</p>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Sorgente secondaria</span>\r\n <p class=\"dpe-field__hint\">{{ node().secondarySourceName || 'non collegata' }}</p>\r\n </div>\r\n </div>\r\n <p class=\"dpe-field__hint\">Le sorgenti si collegano sul canvas, sulle due porte in alto.</p>\r\n\r\n @if (node().kind === 'Lookup') {\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().allowsMultipleLookupValues ?? false\"\r\n (change)=\"setField('allowsMultipleLookupValues', checkedOf($event))\"\r\n />\r\n Ammetti piu’ corrispondenze sul lato secondario\r\n </label>\r\n }\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Chiavi</h4>\r\n @if (keys().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna chiave.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Campo primario</th>\r\n <th>Campo secondario</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (key of keys(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"join-primary-columns\"\r\n [value]=\"key.primaryFieldName\"\r\n [attr.aria-label]=\"'Campo primario della chiave ' + ($index + 1)\"\r\n (change)=\"patchKey($index, { primaryFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"join-secondary-columns\"\r\n [value]=\"key.secondaryFieldName\"\r\n [attr.aria-label]=\"'Campo secondario della chiave ' + ($index + 1)\"\r\n (change)=\"patchKey($index, { secondaryFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la chiave\"\r\n (click)=\"removeKey($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addKey()\">Aggiungi chiave</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi in uscita</h4>\r\n <p class=\"dpe-field__hint\">\r\n Lo schema del join e’ <strong>solo</strong> questo elenco: cio’ che non e’ dichiarato\r\n qui non arriva a valle.\r\n </p>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo dichiarato.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Da</th>\r\n <th>Campo</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <!--\r\n Un elenco chiuso alle due sorgenti del nodo: il contratto dice che\r\n la sorgente del campo deve essere una delle due, e con una casella di testo\r\n digitarne una terza sarebbe possibile.\r\n -->\r\n <select\r\n [dpeValue]=\"field.sourceName\"\r\n [attr.aria-label]=\"'Sorgente del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceName: valueOf($event) })\"\r\n >\r\n <option value=\"\">—</option>\r\n @if (node().primarySourceName) {\r\n <option [value]=\"node().primarySourceName!\">\r\n {{ node().primarySourceName }} (primaria)\r\n </option>\r\n }\r\n @if (node().secondarySourceName) {\r\n <option [value]=\"node().secondarySourceName!\">\r\n {{ node().secondarySourceName }} (secondaria)\r\n </option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [attr.list]=\"columnListIdFor(field)\"\r\n [value]=\"field.sourceFieldName\"\r\n [attr.aria-label]=\"'Campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n\r\n <datalist id=\"join-primary-columns\">\r\n @for (column of primaryColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <datalist id=\"join-secondary-columns\">\r\n @for (column of secondaryColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeJoinInspectorComponent extends DpeNodeInspectorBase<JoinNode> {\r\n override readonly collection: DpeNodeCollectionName = 'joins';\r\n\r\n protected readonly kinds = KINDS;\r\n\r\n readonly keys = computed<readonly JoinKey[]>(() => this.node().keys ?? []);\r\n readonly fields = computed<readonly JoinResultField[]>(() => this.node().fields ?? []);\r\n\r\n /** Gli schemi dei due lati, separati: qui `inputColumns` fusi non basterebbero. */\r\n readonly primaryColumns = computed(\r\n () => this.store.schemaByNode().get(this.node().primarySourceName ?? '')?.columns ?? [],\r\n );\r\n\r\n readonly secondaryColumns = computed(\r\n () => this.store.schemaByNode().get(this.node().secondarySourceName ?? '')?.columns ?? [],\r\n );\r\n\r\n /** L'elenco dei campi proposti segue il lato scelto sulla riga. */\r\n protected columnListIdFor(field: JoinResultField): string {\r\n return field.sourceName === this.node().secondarySourceName\r\n ? 'join-secondary-columns'\r\n : 'join-primary-columns';\r\n }\r\n\r\n protected addKey(): void {\r\n this.patch({ keys: [...this.keys(), { primaryFieldName: '', secondaryFieldName: '' }] });\r\n }\r\n\r\n protected removeKey(index: number): void {\r\n this.patch({ keys: this.keys().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchKey(index: number, patch: Partial<JoinKey>): void {\r\n this.patch({\r\n keys: this.keys().map((key, position) => (position === index ? { ...key, ...patch } : key)),\r\n });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({\r\n fields: [\r\n ...this.fields(),\r\n { sourceName: this.node().primarySourceName ?? '', sourceFieldName: '', alias: '' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<JoinResultField>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * L'editor di un'espressione.\r\n *\r\n * Per la v1 le espressioni sono **SQL nativo del dialetto della definizione** (ADR 0006): non\r\n * c'e' nessun parser, il testo passa verbatim nell'SQL generato. Tre conseguenze che\r\n * l'interfaccia deve rendere visibili, perche' nessuna di esse si vede scrivendo:\r\n *\r\n * 1. i **riferimenti dentro l'espressione non sono validati**: un nome di colonna sbagliato\r\n * non produce nessuna diagnostica e fallisce al momento dell'esecuzione, sul database;\r\n * 2. il **tipo dichiarato e' autorevole e non verificato**: se l'espressione produce altro,\r\n * nessuno lo dira';\r\n * 3. cio' che si scrive **verra' eseguito** sul database di destinazione: authoring di\r\n * un'espressione equivale a eseguire SQL arbitrario.\r\n *\r\n * Per questo l'avviso non e' un tooltip: e' testo accanto al campo. Un'interfaccia che facesse\r\n * sembrare questa casella un editor di formule verificate mentirebbe.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\r\n\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { SqlDialectKind } from '../../model/dpe-definition.model';\r\n\r\n@Component({\r\n selector: 'dpe-expression-editor',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: './dpe-form.css',\r\n styles: [\r\n `\r\n .dpe-expr__dialect {\r\n font-family: var(--dpe-font-mono, monospace);\r\n font-weight: 600;\r\n }\r\n `,\r\n ],\r\n template: `\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId()\">{{ label() }}</label>\r\n <textarea\r\n [id]=\"controlId()\"\r\n [value]=\"value() ?? ''\"\r\n [attr.placeholder]=\"placeholder()\"\r\n [attr.aria-describedby]=\"controlId() + '-warn'\"\r\n spellcheck=\"false\"\r\n (change)=\"valueChange.emit(text($event))\"\r\n ></textarea>\r\n <p class=\"dpe-note dpe-note--danger\" [id]=\"controlId() + '-warn'\">\r\n <span class=\"dpe-expr__dialect\">SQL {{ dialectLabel() }}</span> — il testo entra\r\n nell’istruzione generata così com’è: i riferimenti non vengono verificati e il tipo\r\n dichiarato non viene controllato. Quello che scrivi qui verrà <strong>eseguito</strong>\r\n sul database di destinazione.\r\n </p>\r\n @if (columnHint().length > 0) {\r\n <p class=\"dpe-field__hint\">Colonne in ingresso: {{ columnHint() }}</p>\r\n }\r\n </div>\r\n `,\r\n})\r\nexport class DpeExpressionEditorComponent {\r\n readonly label = input('Espressione');\r\n readonly value = input<string | undefined>(undefined);\r\n readonly placeholder = input('');\r\n readonly dialect = input.required<SqlDialectKind>();\r\n /**\r\n * I nomi delle colonne a monte, **come suggerimento** e non come elenco chiuso: sono cio'\r\n * che il backend ha propagato, ma dentro l'espressione si puo' scrivere qualunque SQL.\r\n */\r\n readonly columns = input<readonly string[]>([]);\r\n readonly controlId = input('dpe-expression');\r\n\r\n readonly valueChange = output<string>();\r\n\r\n readonly dialectLabel = computed(() => DPE_DIALECT_LABELS[this.dialect()] ?? this.dialect());\r\n\r\n /** Elenco troncato: dieci nomi sono un aiuto, cinquanta sono un muro di testo. */\r\n readonly columnHint = computed(() => {\r\n const columns = this.columns();\r\n const shown = columns.slice(0, 10).join(', ');\r\n return columns.length > 10 ? `${shown}, …` : shown;\r\n });\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLTextAreaElement).value;\r\n }\r\n}\r\n","/**\r\n * Ispettore della trasformazione.\r\n *\r\n * `kind` governa i campi, e la corrispondenza e' quella del contratto: `expressionFields` per\r\n * `Expression` e `ComputeRelative`, `droppedFields` per `Slice`, `partitionBy`/`orderBy` solo\r\n * per `ComputeRelative`. Il vincolo e' **esclusivo** in entrambi i sensi (per `Slice` le\r\n * espressioni devono essere vuote), quindi cambiare `kind` non lascia in giro i campi dell'altro\r\n * ramo: restano nel documento solo se l'utente li ha scritti in quel ramo.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n ExpressionField,\r\n OrderByField,\r\n TransformKind,\r\n TransformNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeExpressionEditorComponent } from '../shared/dpe-expression-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly TransformKind[] = ['Expression', 'Slice', 'ComputeRelative'];\r\n\r\n@Component({\r\n selector: 'dpe-transform-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent, DpeExpressionEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-kind\">Tipo di trasformazione</label>\r\n <select id=\"tr-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (node().kind === 'Slice') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-dropped\">Colonne da eliminare</label>\r\n <input\r\n id=\"tr-dropped\"\r\n type=\"text\"\r\n [value]=\"droppedText()\"\r\n placeholder=\"separate da virgola\"\r\n (change)=\"onDropped(valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">In ingresso: {{ columnHint() }}</p>\r\n </div>\r\n } @else {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Colonne calcolate</h4>\r\n @if (expressionFields().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna colonna calcolata.</p>\r\n }\r\n @for (field of expressionFields(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'tr-alias-' + $index\">Alias</label>\r\n <input\r\n [id]=\"'tr-alias-' + $index\"\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n (change)=\"patchExpression($index, { alias: valueOf($event) })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la colonna ' + field.alias\"\r\n (click)=\"removeExpression($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n\r\n <dpe-expression-editor\r\n [value]=\"field.expression\"\r\n [dialect]=\"dialect()\"\r\n [columns]=\"columnNames()\"\r\n [controlId]=\"'tr-expr-' + $index\"\r\n (valueChange)=\"patchExpression($index, { expression: $event })\"\r\n />\r\n\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Tipo dichiarato</span>\r\n <dpe-column-type-editor\r\n [value]=\"field.declaredType\"\r\n [controlId]=\"'tr-type-' + $index\"\r\n (valueChange)=\"patchExpression($index, { declaredType: $event })\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Autorevole e <strong>non verificato</strong>: il backend si fida di questa\r\n dichiarazione e non controlla cosa l’espressione produca davvero.\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addExpression()\">Aggiungi colonna</button>\r\n </div>\r\n </section>\r\n }\r\n\r\n @if (node().kind === 'ComputeRelative') {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Finestra</h4>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-partition\">Partiziona per</label>\r\n <input\r\n id=\"tr-partition\"\r\n type=\"text\"\r\n [value]=\"partitionText()\"\r\n placeholder=\"colonne separate da virgola\"\r\n (change)=\"onPartition(valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Ordina per</span>\r\n @for (order of orderBy(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"tr-columns\"\r\n [value]=\"order.columnName\"\r\n [attr.aria-label]=\"'Colonna di ordinamento ' + ($index + 1)\"\r\n (change)=\"patchOrder($index, { columnName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"order.direction ?? 'Ascending'\"\r\n [attr.aria-label]=\"'Direzione ' + ($index + 1)\"\r\n (change)=\"patchOrder($index, { direction: valueOf($event) === 'Descending' ? 'Descending' : 'Ascending' })\"\r\n >\r\n <option value=\"Ascending\">Ascendente</option>\r\n <option value=\"Descending\">Discendente</option>\r\n </select>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi l’ordinamento\"\r\n (click)=\"removeOrder($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addOrder()\">Aggiungi ordinamento</button>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n\r\n <datalist id=\"tr-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeTransformInspectorComponent extends DpeNodeInspectorBase<TransformNode> {\r\n override readonly collection: DpeNodeCollectionName = 'transforms';\r\n\r\n protected readonly kinds = KINDS;\r\n\r\n readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n readonly expressionFields = computed<readonly ExpressionField[]>(\r\n () => this.node().expressionFields ?? [],\r\n );\r\n\r\n readonly orderBy = computed<readonly OrderByField[]>(() => this.node().orderBy ?? []);\r\n\r\n readonly droppedText = computed(() => (this.node().droppedFields ?? []).join(', '));\r\n readonly partitionText = computed(() => (this.node().partitionBy ?? []).join(', '));\r\n\r\n readonly columnNames = computed(() => this.inputColumns().map((column) => column.name));\r\n\r\n readonly columnHint = computed(() => {\r\n const names = this.columnNames();\r\n return names.length > 10 ? `${names.slice(0, 10).join(', ')}, …` : names.join(', ') || '—';\r\n });\r\n\r\n protected addExpression(): void {\r\n this.patch({\r\n expressionFields: [\r\n ...this.expressionFields(),\r\n { alias: '', expression: '', declaredType: { kind: 'String' } },\r\n ],\r\n });\r\n }\r\n\r\n protected removeExpression(index: number): void {\r\n this.patch({\r\n expressionFields: this.expressionFields().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchExpression(index: number, patch: Partial<ExpressionField>): void {\r\n this.patch({\r\n expressionFields: this.expressionFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected onDropped(raw: string): void {\r\n this.patch({ droppedFields: this.split(raw) });\r\n }\r\n\r\n protected onPartition(raw: string): void {\r\n this.patch({ partitionBy: this.split(raw) });\r\n }\r\n\r\n protected addOrder(): void {\r\n this.patch({ orderBy: [...this.orderBy(), { columnName: '' }] });\r\n }\r\n\r\n protected removeOrder(index: number): void {\r\n this.patch({ orderBy: this.orderBy().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchOrder(index: number, patch: Partial<OrderByField>): void {\r\n this.patch({\r\n orderBy: this.orderBy().map((order, position) =>\r\n position === index ? { ...order, ...patch } : order,\r\n ),\r\n });\r\n }\r\n\r\n private split(raw: string): string[] | undefined {\r\n const values = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n return values.length > 0 ? values : undefined;\r\n }\r\n}\r\n","/**\r\n * Ispettore della scrittura.\r\n *\r\n * `target` decide **cosa produce la libreria**: un'istruzione SQL per l'host (`Database`) oppure\r\n * un file (`Json`, `Csv`). E' la cosa piu' importante di questo nodo, quindi sta in cima, e i\r\n * campi che seguono cambiano di conseguenza: tabella e operazione solo per `Database`, opzioni di\r\n * formato solo per il file corrispondente.\r\n *\r\n * Due avvisi che non sono decorazione:\r\n *\r\n * - `Insert`/`Update`/`Upsert`/`Delete` **non vengono eseguiti** dalla libreria: determinano la\r\n * forma dell'SQL di lettura consegnato all'host. Un'interfaccia che li presentasse come azioni\r\n * farebbe credere che la pipeline scriva sul database;\r\n * - `onlyChangedRows` e' **dichiarato e non implementato** da noi: il change tracking e' dell'host\r\n * (ADR 0011) e non influenza l'SQL generato.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n CsvDelimiter,\r\n DpeNodeCollectionName,\r\n WritebackFieldMapping,\r\n WritebackFieldRole,\r\n WritebackNode,\r\n WritebackOperation,\r\n WritebackTargetKind,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeExpressionEditorComponent } from '../shared/dpe-expression-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst TARGETS: readonly WritebackTargetKind[] = ['Database', 'Json', 'Csv'];\r\nconst OPERATIONS: readonly WritebackOperation[] = ['Insert', 'Update', 'Upsert', 'Delete'];\r\nconst ROLES: readonly WritebackFieldRole[] = ['Value', 'PrimaryKey', 'QualifierKey'];\r\nconst DELIMITERS: readonly CsvDelimiter[] = ['Comma', 'Semicolon', 'Tab', 'Pipe', 'Caret', 'Backquote'];\r\n\r\n@Component({\r\n selector: 'dpe-writeback-inspector',\r\n standalone: true,\r\n imports: [DpeExpressionEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-target\">Destinazione</label>\r\n <select id=\"wb-target\" [dpeValue]=\"node().target\" (change)=\"onTarget(valueOf($event))\">\r\n @for (target of targets; track $index) {\r\n <option [value]=\"target\">{{ target }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-sequence\">Sequenza</label>\r\n <input\r\n id=\"wb-sequence\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"node().sequence\"\r\n [attr.aria-invalid]=\"hasIssueOn('sequence')\"\r\n (change)=\"setField('sequence', toNumber(valueOf($event)) ?? 1)\"\r\n />\r\n @for (issue of issuesOn('sequence'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (node().target === 'Database') {\r\n <p class=\"dpe-note\">\r\n La libreria <strong>non scrive</strong> sul database: produce un’istruzione SQL di\r\n lettura e la consegna all’host, che la esegue. L’operazione scelta determina la forma di\r\n quell’istruzione (quali colonne, quale chiave di correlazione).\r\n </p>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-table\">Tabella di destinazione</label>\r\n <input\r\n id=\"wb-table\"\r\n type=\"text\"\r\n [value]=\"node().tableName ?? ''\"\r\n [attr.aria-invalid]=\"hasIssueOn('tableName')\"\r\n (change)=\"setField('tableName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-operation\">Operazione</label>\r\n <select\r\n id=\"wb-operation\"\r\n [dpeValue]=\"node().operation ?? 'Insert'\"\r\n (change)=\"setField('operation', valueOf($event))\"\r\n >\r\n @for (operation of operations; track $index) {\r\n <option [value]=\"operation\">{{ operation }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n @if (node().operation === 'Upsert') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-external-id\">Campo di identificazione esterna</label>\r\n <input\r\n id=\"wb-external-id\"\r\n type=\"text\"\r\n [value]=\"node().externalIdFieldName ?? ''\"\r\n (change)=\"setField('externalIdFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().onlyChangedRows ?? false\"\r\n (change)=\"setField('onlyChangedRows', checkedOf($event))\"\r\n />\r\n Solo le righe cambiate\r\n </label>\r\n <p class=\"dpe-field__hint\">\r\n Dichiarazione per l’host: il confronto con lo stato precedente non lo fa la libreria e\r\n non cambia l’SQL generato.\r\n </p>\r\n }\r\n\r\n @if (node().target === 'Csv') {\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-delimiter\">Separatore</label>\r\n <select\r\n id=\"wb-delimiter\"\r\n [dpeValue]=\"node().csvOptions?.delimiter ?? 'Comma'\"\r\n (change)=\"patchCsv({ delimiter: asDelimiter(valueOf($event)) })\"\r\n >\r\n @for (delimiter of delimiters; track $index) {\r\n <option [value]=\"delimiter\">{{ delimiter }}</option>\r\n }\r\n </select>\r\n </div>\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().csvOptions?.includesHeaderRow ?? true\"\r\n (change)=\"patchCsv({ includesHeaderRow: checkedOf($event) })\"\r\n />\r\n Riga di intestazione\r\n </label>\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n Il quoting non e’ configurabile: si quota quando serve, con le virgolette raddoppiate.\r\n </p>\r\n }\r\n\r\n @if (node().target === 'Json') {\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().jsonOptions?.indented ?? false\"\r\n (change)=\"patchJson(checkedOf($event))\"\r\n />\r\n JSON indentato\r\n </label>\r\n }\r\n\r\n <dpe-expression-editor\r\n label=\"Filtro sul risultato (facoltativo)\"\r\n [value]=\"node().filterCondition\"\r\n [dialect]=\"dialect()\"\r\n [columns]=\"columnNames()\"\r\n controlId=\"wb-filter\"\r\n (valueChange)=\"setField('filterCondition', $event)\"\r\n />\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Mappatura dei campi</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo mappato.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Colonna a monte</th>\r\n <th>Parametro</th>\r\n <th>Campo di destinazione</th>\r\n <th>Ruolo</th>\r\n <th>Auto</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <!-- Colonna e parametro sono esclusivi: scegliere l’uno svuota l’altro. -->\r\n <input\r\n type=\"text\"\r\n list=\"wb-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"!!field.runtimeParameterName || (field.isAutoGenerated ?? false)\"\r\n [attr.aria-label]=\"'Colonna del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.runtimeParameterName ?? ''\"\r\n [attr.aria-label]=\"'Parametro del campo ' + ($index + 1)\"\r\n (change)=\"onRuntimeParameter($index, valueOf($event))\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (parameter of valueParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.targetFieldName\"\r\n [attr.aria-label]=\"'Campo di destinazione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { targetFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.role ?? 'Value'\"\r\n [attr.aria-label]=\"'Ruolo del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { role: asRole(valueOf($event)) })\"\r\n >\r\n @for (role of roles; track $index) {\r\n <option [value]=\"role\">{{ role }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"field.isAutoGenerated ?? false\"\r\n [attr.aria-label]=\"'Generato dalla destinazione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { isAutoGenerated: checkedOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la mappatura\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"wb-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi mappatura</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeWritebackInspectorComponent extends DpeNodeInspectorBase<WritebackNode> {\r\n override readonly collection: DpeNodeCollectionName = 'writebacks';\r\n\r\n protected readonly targets = TARGETS;\r\n protected readonly operations = OPERATIONS;\r\n protected readonly roles = ROLES;\r\n protected readonly delimiters = DELIMITERS;\r\n\r\n readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n readonly fields = computed<readonly WritebackFieldMapping[]>(() => this.node().fields ?? []);\r\n\r\n readonly columnNames = computed(() => this.inputColumns().map((column) => column.name));\r\n\r\n readonly valueParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Value'),\r\n );\r\n\r\n protected asRole(value: string): WritebackFieldRole {\r\n return value as WritebackFieldRole;\r\n }\r\n\r\n protected asDelimiter(value: string): CsvDelimiter {\r\n return value as CsvDelimiter;\r\n }\r\n\r\n /**\r\n * Cambiare destinazione **toglie** i campi dell'altra: `operation` e' richiesta per\r\n * `Database` e deve essere assente per `Json`/`Csv`, quindi lasciarla scritta produrrebbe\r\n * `DPE_MODEL_CONDITIONAL_FORBIDDEN` su un campo che l'utente non vede piu'.\r\n */\r\n protected onTarget(value: string): void {\r\n const target = value as WritebackTargetKind;\r\n this.patch({\r\n target,\r\n operation: target === 'Database' ? (this.node().operation ?? 'Insert') : undefined,\r\n tableName: target === 'Database' ? this.node().tableName : undefined,\r\n externalIdFieldName: target === 'Database' ? this.node().externalIdFieldName : undefined,\r\n csvOptions: target === 'Csv' ? this.node().csvOptions : undefined,\r\n jsonOptions: target === 'Json' ? this.node().jsonOptions : undefined,\r\n });\r\n }\r\n\r\n // Lo spread non esiste nelle espressioni dei template Angular: la fusione sta qui.\r\n protected patchJson(indented: boolean): void {\r\n this.patch({ jsonOptions: { ...(this.node().jsonOptions ?? {}), indented } });\r\n }\r\n\r\n protected patchCsv(patch: Partial<{ delimiter: CsvDelimiter; includesHeaderRow: boolean }>): void {\r\n this.patch({ csvOptions: { ...(this.node().csvOptions ?? {}), ...patch } });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { targetFieldName: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<WritebackFieldMapping>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected onRuntimeParameter(index: number, name: string): void {\r\n this.patchField(index, {\r\n runtimeParameterName: name === '' ? undefined : name,\r\n sourceFieldName: name === '' ? this.fields()[index]?.sourceFieldName : undefined,\r\n });\r\n }\r\n}\r\n","/**\r\n * Il contenitore degli ispettori: campi comuni, poi l'ispettore della categoria.\r\n *\r\n * La **rinomina** sta qui e non nei singoli ispettori, per due ragioni. E' identica per tutte le\r\n * categorie, e soprattutto e' un refactoring globale (**I5**): passa dall'unico punto che\r\n * riscrive i riferimenti a valle, e prima di applicarla **dice quante occorrenze tocchera'**.\r\n * Rinominare non e' modificare un campo, e non deve sembrarlo.\r\n *\r\n * Con **piu' di un nodo selezionato** non si mostra l'editor del primo: si dichiara quanti sono e\r\n * si offrono solo le operazioni valide su molti. Mostrare i campi di uno mentre N sono evidenziati\r\n * e' la stessa bugia della doppia evidenziazione, detta piu' piano — l'utente crede di stare\r\n * agendo su cio' che vede selezionato.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeFindNode } from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport {\r\n AggregateNode,\r\n AppendNode,\r\n AtomicWritebackNode,\r\n CustomNode,\r\n DataSourceNode,\r\n FilterNode,\r\n ForecastNode,\r\n HierarchyPathNode,\r\n JoinNode,\r\n TransformNode,\r\n WritebackNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeAggregateInspectorComponent } from './dpe-aggregate-inspector.component';\r\nimport { DpeAppendInspectorComponent } from './dpe-append-inspector.component';\r\nimport { DpeAtomicWritebackInspectorComponent } from './dpe-atomic-writeback-inspector.component';\r\nimport { DpeCustomNodeInspectorComponent } from './dpe-custom-node-inspector.component';\r\nimport { DpeDataSourceInspectorComponent } from './dpe-data-source-inspector.component';\r\nimport { DpeFilterInspectorComponent } from './dpe-filter-inspector.component';\r\nimport { DpeForecastInspectorComponent } from './dpe-forecast-inspector.component';\r\nimport { DpeHierarchyPathInspectorComponent } from './dpe-hierarchy-path-inspector.component';\r\nimport { DpeJoinInspectorComponent } from './dpe-join-inspector.component';\r\nimport { DpeTransformInspectorComponent } from './dpe-transform-inspector.component';\r\nimport { DpeWritebackInspectorComponent } from './dpe-writeback-inspector.component';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\n\r\n@Component({\r\n selector: 'dpe-node-inspector',\r\n standalone: true,\r\n imports: [\r\n DpeAggregateInspectorComponent,\r\n DpeAppendInspectorComponent,\r\n DpeAtomicWritebackInspectorComponent,\r\n DpeCustomNodeInspectorComponent,\r\n DpeDataSourceInspectorComponent,\r\n DpeFilterInspectorComponent,\r\n DpeForecastInspectorComponent,\r\n DpeHierarchyPathInspectorComponent,\r\n DpeJoinInspectorComponent,\r\n DpeTransformInspectorComponent,\r\n DpeWritebackInspectorComponent,\r\n DpeNodeIconComponent,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styleUrl: '../shared/dpe-form.css',\r\n styles: [\r\n `\r\n :host {\r\n display: block;\r\n padding: 12px;\r\n overflow: auto;\r\n }\r\n\r\n .dpe-inspector__head {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n margin-bottom: 10px;\r\n }\r\n\r\n /* Pastiglia identica a quella della palette e della card: stessa misura, stessi token. */\r\n .dpe-inspector__icon {\r\n display: inline-flex;\r\n flex: 0 0 auto;\r\n align-items: center;\r\n justify-content: center;\r\n width: 26px;\r\n height: 26px;\r\n border-radius: var(--dpe-radius-sm, 8px);\r\n background: var(--dpe-cat-soft, #eef0f4);\r\n color: var(--dpe-cat, #6b7086);\r\n }\r\n\r\n .dpe-cat--source {\r\n --dpe-cat: var(--dpe-cat-source, #2f7d8f);\r\n --dpe-cat-soft: var(--dpe-cat-source-soft, #dbecf0);\r\n }\r\n\r\n .dpe-cat--transform {\r\n --dpe-cat: var(--dpe-cat-transform, #3b6fd4);\r\n --dpe-cat-soft: var(--dpe-cat-transform-soft, #e2eafb);\r\n }\r\n\r\n .dpe-cat--sink {\r\n --dpe-cat: var(--dpe-cat-sink, #1c8a5c);\r\n --dpe-cat-soft: var(--dpe-cat-sink-soft, #dcf1e8);\r\n }\r\n\r\n .dpe-cat--uncompilable {\r\n --dpe-cat: var(--dpe-cat-uncompilable, #7c5cd6);\r\n --dpe-cat-soft: var(--dpe-cat-uncompilable-soft, #ebe6fa);\r\n }\r\n\r\n .dpe-inspector__name {\r\n flex: 1 1 auto;\r\n overflow: hidden;\r\n min-width: 0;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n .dpe-inspector__category {\r\n /* All'estremita' opposta del titolo, come prima di avere l'icona in testa. */\r\n margin-left: auto;\r\n flex: 0 0 auto;\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 11px;\r\n text-transform: uppercase;\r\n letter-spacing: 0.04em;\r\n }\r\n\r\n .dpe-columns {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 4px;\r\n }\r\n\r\n .dpe-column {\r\n padding: 1px 6px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: 999px;\r\n background: var(--dpe-surface-alt, #f7f8fa);\r\n font-size: 10px;\r\n }\r\n\r\n .dpe-column--nullable {\r\n border-style: dashed;\r\n }\r\n\r\n .dpe-multi__names {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 4px;\r\n margin: 8px 0;\r\n padding: 0;\r\n list-style: none;\r\n }\r\n\r\n .dpe-multi__name {\r\n padding: 1px 6px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: 999px;\r\n background: var(--dpe-surface-alt, #f7f8fa);\r\n font-family: var(--dpe-font-mono, monospace);\r\n font-size: 10px;\r\n }\r\n `,\r\n ],\r\n template: `\r\n @if (selectedNames().length > 1) {\r\n <!--\r\n Selezione multipla: si dice quanti sono e si offre solo cio' che ha senso su molti. Nessun\r\n campo del primo nodo, perche' non e' su quello che l’utente sta agendo.\r\n -->\r\n <div class=\"dpe-inspector__head\">\r\n <strong>{{ selectedNames().length }} nodi selezionati</strong>\r\n <span class=\"dpe-inspector__category\">selezione</span>\r\n </div>\r\n\r\n <ul class=\"dpe-multi__names\">\r\n @for (name of selectedNames(); track $index) {\r\n <li class=\"dpe-multi__name\">{{ name }}</li>\r\n }\r\n </ul>\r\n\r\n <p class=\"dpe-note\">\r\n I campi di un singolo nodo si modificano con un nodo solo selezionato: mostrarli qui\r\n farebbe credere di agire su tutti.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"removeSelected()\">\r\n Elimina i {{ selectedNames().length }} nodi\r\n </button>\r\n <!--\r\n Il riordino e’ dichiaratamente **dell’intero grafo**: dagre su un sottografo sarebbe una\r\n funzione nuova, e chiamarla «riordina i selezionati» mentre riordina tutto sarebbe una\r\n bugia — la stessa classe di difetto che questo pannello esiste per evitare.\r\n -->\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"layoutRequested.emit()\">\r\n Riordina il grafo\r\n </button>\r\n </div>\r\n\r\n <p class=\"dpe-note dpe-note--warning\">\r\n L’eliminazione lascia i riferimenti a valle così come sono: diventano riferimenti rotti, e\r\n il backend li segnala. Si annulla con ↶.\r\n </p>\r\n } @else if (located(); as entry) {\r\n <div class=\"dpe-inspector__head\">\r\n <!--\r\n La stessa icona della palette e della card: il terzo posto in cui compare il tipo, e\r\n deve avere lo stesso aspetto degli altri due.\r\n -->\r\n <span class=\"dpe-inspector__icon\" [class]=\"'dpe-inspector__icon ' + familyClass()\">\r\n <dpe-node-icon [collection]=\"entry.collection\" />\r\n </span>\r\n <strong class=\"dpe-inspector__name\">{{ entry.node.label || entry.node.name }}</strong>\r\n <span class=\"dpe-inspector__category\">{{ categoryLabel() }}</span>\r\n </div>\r\n\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-name\">Nome tecnico</label>\r\n <div class=\"dpe-row\">\r\n <input\r\n id=\"node-name\"\r\n type=\"text\"\r\n [value]=\"nameDraft()\"\r\n [attr.aria-invalid]=\"nameDraft().trim().length === 0\"\r\n (input)=\"nameDraft.set(valueOf($event))\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn\"\r\n [disabled]=\"!canRename()\"\r\n (click)=\"rename(entry.node.name)\"\r\n >\r\n Rinomina\r\n </button>\r\n </div>\r\n @if (canRename()) {\r\n <p class=\"dpe-note dpe-note--warning\">\r\n La rinomina aggiorna <strong>{{ referenceCount() }}</strong> riferimenti a valle.\r\n I nomi si confrontano in modo esatto: un riferimento che sbaglia le maiuscole non\r\n verrebbe risolto dal backend.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-label\">Etichetta</label>\r\n <input\r\n id=\"node-label\"\r\n type=\"text\"\r\n [value]=\"entry.node.label ?? ''\"\r\n (change)=\"setCommon('label', valueOf($event))\"\r\n />\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-description\">Descrizione</label>\r\n <input\r\n id=\"node-description\"\r\n type=\"text\"\r\n [value]=\"entry.node.description ?? ''\"\r\n (change)=\"setCommon('description', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n @switch (entry.collection) {\r\n @case ('dataSources') {\r\n <dpe-data-source-inspector [nodeName]=\"entry.node.name\" [node]=\"asDataSource(entry.node)\" />\r\n }\r\n @case ('filters') {\r\n <dpe-filter-inspector [nodeName]=\"entry.node.name\" [node]=\"asFilter(entry.node)\" />\r\n }\r\n @case ('joins') {\r\n <dpe-join-inspector [nodeName]=\"entry.node.name\" [node]=\"asJoin(entry.node)\" />\r\n }\r\n @case ('aggregates') {\r\n <dpe-aggregate-inspector [nodeName]=\"entry.node.name\" [node]=\"asAggregate(entry.node)\" />\r\n }\r\n @case ('transforms') {\r\n <dpe-transform-inspector [nodeName]=\"entry.node.name\" [node]=\"asTransform(entry.node)\" />\r\n }\r\n @case ('appends') {\r\n <dpe-append-inspector [nodeName]=\"entry.node.name\" [node]=\"asAppend(entry.node)\" />\r\n }\r\n @case ('hierarchyPaths') {\r\n <dpe-hierarchy-path-inspector [nodeName]=\"entry.node.name\" [node]=\"asHierarchy(entry.node)\" />\r\n }\r\n @case ('forecasts') {\r\n <dpe-forecast-inspector [nodeName]=\"entry.node.name\" [node]=\"asForecast(entry.node)\" />\r\n }\r\n @case ('customNodes') {\r\n <dpe-custom-node-inspector [nodeName]=\"entry.node.name\" [node]=\"asCustom(entry.node)\" />\r\n }\r\n @case ('writebacks') {\r\n <dpe-writeback-inspector [nodeName]=\"entry.node.name\" [node]=\"asWriteback(entry.node)\" />\r\n }\r\n @case ('atomicWritebacks') {\r\n <dpe-atomic-writeback-inspector [nodeName]=\"entry.node.name\" [node]=\"asAtomic(entry.node)\" />\r\n }\r\n }\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Schema in uscita</h4>\r\n @if (columns().length === 0) {\r\n <p class=\"dpe-empty\">\r\n Nessuna colonna: il backend non ha (ancora) propagato uno schema per questo nodo.\r\n </p>\r\n } @else {\r\n <div class=\"dpe-columns\">\r\n @for (column of columns(); track $index) {\r\n <span\r\n class=\"dpe-column\"\r\n [class.dpe-column--nullable]=\"column.isNullable\"\r\n [title]=\"column.type.kind + (column.isNullable ? ' · nullabile' : ' · non nulla')\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n Tratteggiate le colonne nullabili. Lo schema arriva da <code>validate</code>: non lo\r\n calcoliamo qui.\r\n </p>\r\n }\r\n </section>\r\n\r\n @if (diagnostics().length > 0) {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Rilievi su questo nodo</h4>\r\n @for (diagnostic of diagnostics(); track $index) {\r\n <p\r\n class=\"dpe-field__issue\"\r\n [class.dpe-field__issue--warning]=\"diagnostic.severity === 'Warning'\"\r\n [class.dpe-field__issue--info]=\"diagnostic.severity === 'Info'\"\r\n >\r\n <code>{{ diagnostic.code }}</code> — {{ diagnostic.message }}\r\n </p>\r\n }\r\n </section>\r\n }\r\n } @else {\r\n <p class=\"dpe-empty\">Nessun nodo selezionato.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeNodeInspectorComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n /**\r\n * Il riordino richiede le misure delle card, che le conosce il canvas: l'ispettore **chiede**,\r\n * non calcola. Componente stupido, orchestrazione fuori.\r\n */\r\n readonly layoutRequested = output<void>();\r\n\r\n readonly selectedNames = computed(() => this.store.selectedNodeNames());\r\n\r\n readonly located = computed(() => {\r\n const name = this.store.selectedNodeName();\r\n return name === undefined ? undefined : dpeFindNode(this.store.definition(), name);\r\n });\r\n\r\n readonly nameDraft = signal('');\r\n\r\n readonly categoryLabel = computed(() => {\r\n const entry = this.located();\r\n return entry ? dpeNodeCategory(entry.collection).label : '';\r\n });\r\n\r\n /** La classe di famiglia dell'icona: la stessa funzione che usano palette e canvas. */\r\n readonly familyClass = computed(() => {\r\n const entry = this.located();\r\n return entry ? dpeNodeIconFamilyClass(entry.collection) : '';\r\n });\r\n\r\n readonly columns = computed(() => {\r\n const entry = this.located();\r\n return entry ? (this.store.schemaByNode().get(entry.node.name)?.columns ?? []) : [];\r\n });\r\n\r\n readonly diagnostics = computed(() => {\r\n const entry = this.located();\r\n return entry ? (this.store.diagnosticsByNode().get(entry.node.name)?.diagnostics ?? []) : [];\r\n });\r\n\r\n readonly referenceCount = computed(() => {\r\n const entry = this.located();\r\n return entry ? this.store.countReferences(entry.node.name) : 0;\r\n });\r\n\r\n readonly canRename = computed(() => {\r\n const entry = this.located();\r\n const draft = this.nameDraft().trim();\r\n return !!entry && draft.length > 0 && draft !== entry.node.name;\r\n });\r\n\r\n constructor() {\r\n // La bozza del nome segue la selezione: senza, cambiando nodo si resterebbe con il nome\r\n // del precedente in una casella che rinomina.\r\n effect(() => {\r\n const entry = this.located();\r\n this.nameDraft.set(entry?.node.name ?? '');\r\n });\r\n }\r\n\r\n /**\r\n * Elimina i nodi selezionati. Si itera su una **copia** dei nomi: `removeNode` pota la selezione\r\n * a ogni giro, e scorrere il signal mentre lo si svuota salterebbe la meta' dei nodi.\r\n */\r\n protected removeSelected(): void {\r\n for (const name of [...this.selectedNames()]) {\r\n this.store.removeNode(name);\r\n }\r\n }\r\n\r\n protected rename(currentName: string): void {\r\n this.store.renameNode(currentName, this.nameDraft().trim());\r\n }\r\n\r\n protected setCommon(field: 'label' | 'description', value: string): void {\r\n const entry = this.located();\r\n if (!entry) {\r\n return;\r\n }\r\n this.store.updateNode(entry.collection, entry.node.name, {\r\n [field]: value === '' ? undefined : value,\r\n } as never);\r\n }\r\n\r\n protected valueOf(event: Event): string {\r\n return (event.target as HTMLInputElement).value;\r\n }\r\n\r\n // I cast sono confinati qui: `@switch` restringe la collezione ma non il tipo del nodo, che\r\n // nel modello e' un'unione. Un cast per ramo e' il prezzo, e sbagliarne uno e' un errore di\r\n // compilazione nel template dell'ispettore, non un difetto silenzioso.\r\n protected asDataSource(node: unknown): DataSourceNode {\r\n return node as DataSourceNode;\r\n }\r\n\r\n protected asFilter(node: unknown): FilterNode {\r\n return node as FilterNode;\r\n }\r\n\r\n protected asJoin(node: unknown): JoinNode {\r\n return node as JoinNode;\r\n }\r\n\r\n protected asAggregate(node: unknown): AggregateNode {\r\n return node as AggregateNode;\r\n }\r\n\r\n protected asTransform(node: unknown): TransformNode {\r\n return node as TransformNode;\r\n }\r\n\r\n protected asAppend(node: unknown): AppendNode {\r\n return node as AppendNode;\r\n }\r\n\r\n protected asHierarchy(node: unknown): HierarchyPathNode {\r\n return node as HierarchyPathNode;\r\n }\r\n\r\n protected asForecast(node: unknown): ForecastNode {\r\n return node as ForecastNode;\r\n }\r\n\r\n protected asCustom(node: unknown): CustomNode {\r\n return node as CustomNode;\r\n }\r\n\r\n protected asWriteback(node: unknown): WritebackNode {\r\n return node as WritebackNode;\r\n }\r\n\r\n protected asAtomic(node: unknown): AtomicWritebackNode {\r\n return node as AtomicWritebackNode;\r\n }\r\n}\r\n","/**\r\n * La palette dei nodi.\r\n *\r\n * Il trascinamento verso il canvas usa `fExternalItem` di @foblex/flow: il rilascio emette\r\n * `fCreateNode` con il `fData` e la posizione **già nel sistema di coordinate del canvas**.\r\n * Convertirla a mano — che e' cio' che servirebbe con un drag generico — vorrebbe dire rifare la\r\n * trasformazione di zoom e panoramica della libreria, cioe' riscrivere la parte piu' facile da\r\n * sbagliare senza guadagnarci niente. Il **clic** resta la via da tastiera: la palette e'\r\n * navigabile con Tab e Invio, e chi non usa il mouse crea comunque un nodo.\r\n *\r\n * Il catalogo e' **descrittivo**: etichette e numero di sorgenti servono a rendere, non a\r\n * validare. Che un'unione con una sola sorgente sia sbagliata lo dice il backend.\r\n *\r\n * La voce sta su **una riga** — pastiglia con l'icona, etichetta — e la descrizione resta nel\r\n * `title`. La versione precedente ne faceva un paragrafo di tre righe: undici categorie non\r\n * entravano nel riquadro e sette si vedevano senza scorrere, cioe' l'elenco non era un elenco.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, output, signal } from '@angular/core';\r\nimport { FFlowModule } from '@foblex/flow';\r\n\r\nimport { DPE_NODE_CATEGORIES, DpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\n\r\n/** Un gruppo dell'elenco: intestazione e voci. Presentazione, non semantica. */\r\nexport interface DpeNodePaletteGroup {\r\n key: 'sources' | 'transforms' | 'sinks';\r\n label: string;\r\n categories: readonly DpeNodeCategory[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-node-palette',\r\n standalone: true,\r\n imports: [FFlowModule, DpeNodeIconComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styles: [\r\n `\r\n :host {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n padding: 8px;\r\n overflow: auto;\r\n background: var(--dpe-surface, #fff);\r\n border-right: 1px solid var(--dpe-border, #e2e5eb);\r\n }\r\n\r\n h3 {\r\n margin: 0;\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 11px;\r\n font-weight: 700;\r\n letter-spacing: 0.04em;\r\n text-transform: uppercase;\r\n }\r\n\r\n /* Intestazione di gruppo: piu' piccola del titolo della palette, e non cliccabile. */\r\n .dpe-palette__group {\r\n margin: 8px 2px 2px;\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 10px;\r\n font-weight: 700;\r\n letter-spacing: 0.06em;\r\n text-transform: uppercase;\r\n }\r\n\r\n input[type='search'] {\r\n box-sizing: border-box;\r\n width: 100%;\r\n padding: 5px 7px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: var(--dpe-radius-xs, 6px);\r\n background: var(--dpe-surface, #fff);\r\n color: var(--dpe-text, #1a1c23);\r\n font: inherit;\r\n font-size: 12px;\r\n }\r\n\r\n /*\r\n * TRAPPOLA @foblex/flow, la stessa dei nodi in un punto dove non era prevista: al termine di\r\n * un trascinamento la libreria **riscrive l'attributo style** della voce. Durante il gesto la\r\n * nasconde con display none e alla fine la ripristina scrivendo il display originale, oppure\r\n * block se non ce n'era. Il nostro display originale era vuoto — arriva dal CSS, non da uno\r\n * stile inline — quindi sull'elemento resta scritto display block.\r\n *\r\n * Conseguenza vista nel browser: un display flex qui sopravviveva fino al primo\r\n * trascinamento e poi no, e titolo e descrizione, che erano flex item, tornavano inline e si\r\n * attaccavano sulla stessa riga. Solo sulle voci trascinate, solo dopo il gesto: nessuno\r\n * screenshot iniziale lo mostrava.\r\n *\r\n * C'e' un secondo strato, scoperto misurando: il tema della libreria dichiara sulla stessa\r\n * classe .f-external-item un display inline-flex in **riga**. Quindi la voce e' inline-flex\r\n * finche' non la si trascina e block dopo: due valori, nessuno dei due nostro.\r\n *\r\n * Correzione **strutturale**: il layout non dipende dal display di questo elemento. La voce e'\r\n * un involucro qualunque — inline-flex o block, indifferente — e dentro c'e' **un solo**\r\n * figlio, .dpe-palette__body, che porta la riga. Un unico figlio si comporta allo stesso\r\n * modo in entrambi i casi, ed e' questo che rende il difetto irripetibile. Niente !important\r\n * e niente ripristino a mano dopo il gesto: sarebbe una gara di specificita' con chi riscrive\r\n * lo stile, e la si perde al prossimo aggiornamento.\r\n *\r\n * Corollario per l'icona: **non** diventa un secondo figlio del bottone. Sta dentro\r\n * .dpe-palette__body con l'etichetta, altrimenti dopo un trascinamento i due figli\r\n * tornerebbero a impilarsi.\r\n */\r\n .dpe-palette__item {\r\n box-sizing: border-box;\r\n width: 100%;\r\n padding: 4px 6px;\r\n border: 1px solid transparent;\r\n border-radius: var(--dpe-radius-xs, 6px);\r\n background: transparent;\r\n color: var(--dpe-text, #1a1c23);\r\n font: inherit;\r\n text-align: left;\r\n cursor: grab;\r\n }\r\n\r\n .dpe-palette__item:hover {\r\n background: var(--dpe-surface-alt, #f7f8fa);\r\n border-color: var(--dpe-border, #e2e5eb);\r\n }\r\n\r\n .dpe-palette__item:focus-visible {\r\n outline: 2px solid var(--dpe-accent, #2f7d8f);\r\n outline-offset: 1px;\r\n }\r\n\r\n /*\r\n * L'involucro interno: unico figlio della voce, quindi indifferente al display di chi lo\r\n * contiene. Qui vive il layout della riga.\r\n */\r\n .dpe-palette__body {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n width: 100%;\r\n min-width: 0;\r\n }\r\n\r\n /*\r\n * Pastiglia dell'icona. Sfondo tenue e tratto pieno della famiglia: gli stessi due token\r\n * che colorano la card sul canvas, cosi' cio' che si trascina e cio' che compare hanno lo\r\n * stesso colore.\r\n */\r\n .dpe-palette__icon {\r\n display: inline-flex;\r\n flex: 0 0 auto;\r\n align-items: center;\r\n justify-content: center;\r\n width: 24px;\r\n height: 24px;\r\n border-radius: var(--dpe-radius-xs, 6px);\r\n background: var(--dpe-cat-soft, #eef0f4);\r\n color: var(--dpe-cat, #6b7086);\r\n }\r\n\r\n .dpe-cat--source {\r\n --dpe-cat: var(--dpe-cat-source, #2f7d8f);\r\n --dpe-cat-soft: var(--dpe-cat-source-soft, #dbecf0);\r\n }\r\n\r\n .dpe-cat--transform {\r\n --dpe-cat: var(--dpe-cat-transform, #3b6fd4);\r\n --dpe-cat-soft: var(--dpe-cat-transform-soft, #e2eafb);\r\n }\r\n\r\n .dpe-cat--sink {\r\n --dpe-cat: var(--dpe-cat-sink, #1c8a5c);\r\n --dpe-cat-soft: var(--dpe-cat-sink-soft, #dcf1e8);\r\n }\r\n\r\n .dpe-cat--uncompilable {\r\n --dpe-cat: var(--dpe-cat-uncompilable, #7c5cd6);\r\n --dpe-cat-soft: var(--dpe-cat-uncompilable-soft, #ebe6fa);\r\n }\r\n\r\n .dpe-palette__label {\r\n flex: 1 1 auto;\r\n overflow: hidden;\r\n min-width: 0;\r\n font-size: 12px;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n }\r\n\r\n /*\r\n * Non compilabile in v1: si distingue **prima** di trascinarlo, non dopo. Segno compatto e\r\n * non una terza riga — l'informazione per esteso sta nel titolo, con la descrizione.\r\n */\r\n .dpe-palette__flag {\r\n flex: 0 0 auto;\r\n padding: 0 5px;\r\n border: 1px solid var(--dpe-not-compilable, #7c5cd6);\r\n border-radius: 999px;\r\n color: var(--dpe-not-compilable, #7c5cd6);\r\n font-size: 9px;\r\n font-weight: 700;\r\n letter-spacing: 0.04em;\r\n }\r\n\r\n .dpe-palette__empty {\r\n margin: 6px 2px;\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 11px;\r\n }\r\n `,\r\n ],\r\n template: `\r\n <h3>Nodi</h3>\r\n <input\r\n type=\"search\"\r\n placeholder=\"Cerca un nodo\"\r\n aria-label=\"Cerca un nodo\"\r\n (input)=\"filter.set(text($event))\"\r\n />\r\n\r\n @for (group of groups(); track group.key) {\r\n <p class=\"dpe-palette__group\">{{ group.label }}</p>\r\n @for (category of group.categories; track category.collection) {\r\n <!--\r\n fExternalItem rende la voce trascinabile sul canvas; fData porta il nome della\r\n collezione, che e’ l’unica cosa che serve per creare il nodo.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"dpe-palette__item\"\r\n fExternalItem\r\n [fExternalItemId]=\"category.collection\"\r\n [fData]=\"category.collection\"\r\n [title]=\"titleOf(category)\"\r\n (click)=\"nodeRequested.emit(category.collection)\"\r\n >\r\n <!--\r\n Un solo figlio dentro l’elemento che la libreria tocca: e’ qui che sta il layout della\r\n riga, e non dipende dal display che @foblex/flow riscrive dopo un trascinamento.\r\n -->\r\n <span class=\"dpe-palette__body\">\r\n <span class=\"dpe-palette__icon\" [class]=\"'dpe-palette__icon ' + familyClass(category)\">\r\n <dpe-node-icon [collection]=\"category.collection\" />\r\n </span>\r\n <span class=\"dpe-palette__label\">{{ category.label }}</span>\r\n @if (category.isNotCompilableInV1) {\r\n <span class=\"dpe-palette__flag\">v1</span>\r\n }\r\n </span>\r\n </button>\r\n }\r\n }\r\n\r\n @if (visible().length === 0) {\r\n <p class=\"dpe-palette__empty\">Nessun nodo corrisponde alla ricerca.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeNodePaletteComponent {\r\n /** Clic sulla voce: il nodo si crea al centro dell'area, non dove stava il puntatore. */\r\n readonly nodeRequested = output<DpeNodeCollectionName>();\r\n\r\n protected readonly filter = signal('');\r\n\r\n readonly visible = computed<readonly DpeNodeCategory[]>(() => {\r\n const needle = this.filter().trim().toLowerCase();\r\n if (needle.length === 0) {\r\n return DPE_NODE_CATEGORIES;\r\n }\r\n return DPE_NODE_CATEGORIES.filter(\r\n (category) =>\r\n category.label.toLowerCase().includes(needle) ||\r\n category.description.toLowerCase().includes(needle),\r\n );\r\n });\r\n\r\n /**\r\n * Tre gruppi, nell'ordine in cui si costruisce una pipeline: da dove entrano i dati, cosa ci\r\n * si fa, dove finiscono. I gruppi vuoti non compaiono, altrimenti una ricerca lascerebbe sullo\r\n * schermo intestazioni senza voci.\r\n */\r\n readonly groups = computed<readonly DpeNodePaletteGroup[]>(() => {\r\n const visible = this.visible();\r\n const groups: DpeNodePaletteGroup[] = [\r\n {\r\n key: 'sources',\r\n label: 'Sorgenti',\r\n categories: visible.filter((category) => category.isSource),\r\n },\r\n {\r\n key: 'transforms',\r\n label: 'Trasformazioni',\r\n categories: visible.filter((category) => !category.isSource && !category.isSink),\r\n },\r\n {\r\n key: 'sinks',\r\n label: 'Scritture',\r\n categories: visible.filter((category) => category.isSink),\r\n },\r\n ];\r\n return groups.filter((group) => group.categories.length > 0);\r\n });\r\n\r\n protected familyClass(category: DpeNodeCategory): string {\r\n return dpeNodeIconFamilyClass(category.collection);\r\n }\r\n\r\n /** Il testo che la descrizione non mostra piu' nel corpo della voce. */\r\n protected titleOf(category: DpeNodeCategory): string {\r\n return category.isNotCompilableInV1\r\n ? `${category.description}\\nModellato ma non compilabile nella versione 1.`\r\n : category.description;\r\n }\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLInputElement).value;\r\n }\r\n}\r\n","/**\r\n * Anteprima dell'SQL generato, in **sola lettura**.\r\n *\r\n * E' lo strumento diagnostico principale per chi costruisce una pipeline: e' l'unico posto in\r\n * cui si vede cosa diventera' il grafo. Tre cose che l'interfaccia dice esplicitamente, perche'\r\n * nessuna e' ovvia guardando il testo:\r\n *\r\n * - i writeback `Database` producono un'istruzione **per l'host**, che la libreria non esegue;\r\n * - i writeback `Json`/`Csv` portano l'SQL di **lettura** con cui l'artefatto viene materializzato;\r\n * - i parametri restano **parametri**: il testo mostra i marcatori del dialetto e i valori stanno\r\n * accanto. Non si interpolano nel testo nemmeno per mostrarlo — un'anteprima che mostra SQL\r\n * concatenato insegna a scriverlo.\r\n *\r\n * Se l'host non implementa `compilePreview` il comando e' disabilitato e questo pannello lo dice:\r\n * degrada l'anteprima, non l'editor.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { DpeValidationService } from '../../core/dpe-validation.service';\r\nimport { DpeCompiledWriteback } from '../../model/dpe-api.model';\r\n\r\ninterface DpeSqlSection {\r\n title: string;\r\n hint: string;\r\n writebacks: readonly DpeCompiledWriteback[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-sql-preview',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styles: [\r\n `\r\n :host {\r\n display: block;\r\n overflow: auto;\r\n padding: 8px 10px;\r\n background: var(--dpe-surface, #fff);\r\n font-size: 12px;\r\n }\r\n\r\n .dpe-sql__bar {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n margin-bottom: 8px;\r\n }\r\n\r\n .dpe-sql__btn {\r\n padding: 4px 9px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: var(--dpe-radius-xs, 6px);\r\n background: var(--dpe-surface, #fff);\r\n color: var(--dpe-text, #1a1c23);\r\n font: inherit;\r\n font-size: 11px;\r\n cursor: pointer;\r\n }\r\n\r\n .dpe-sql__btn:disabled {\r\n opacity: 0.5;\r\n cursor: not-allowed;\r\n }\r\n\r\n .dpe-sql__note {\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 10px;\r\n }\r\n\r\n .dpe-sql__section {\r\n margin-bottom: 10px;\r\n }\r\n\r\n .dpe-sql__title {\r\n margin: 0 0 2px;\r\n font-size: 11px;\r\n font-weight: 700;\r\n text-transform: uppercase;\r\n letter-spacing: 0.03em;\r\n color: var(--dpe-text-muted, #6b7086);\r\n }\r\n\r\n pre {\r\n margin: 4px 0;\r\n padding: 8px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: var(--dpe-radius-xs, 6px);\r\n background: var(--dpe-surface-sunken, #eef0f4);\r\n font-family: var(--dpe-font-mono, monospace);\r\n font-size: 11px;\r\n white-space: pre-wrap;\r\n word-break: break-word;\r\n }\r\n\r\n table {\r\n width: 100%;\r\n border-collapse: collapse;\r\n font-size: 10px;\r\n }\r\n\r\n th,\r\n td {\r\n padding: 2px 5px;\r\n border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);\r\n text-align: left;\r\n }\r\n\r\n .dpe-sql__empty {\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 11px;\r\n font-style: italic;\r\n }\r\n `,\r\n ],\r\n template: `\r\n <div class=\"dpe-sql__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-sql__btn\"\r\n [disabled]=\"!validation.isPreviewAvailable() || validation.isCompiling()\"\r\n (click)=\"validation.requestPreview()\"\r\n >\r\n @if (validation.isCompiling()) {\r\n Compilazione in corso…\r\n } @else {\r\n Genera anteprima\r\n }\r\n </button>\r\n @if (!validation.isPreviewAvailable()) {\r\n <span class=\"dpe-sql__note\">\r\n Anteprima non disponibile su questo ambiente: l’host non espone la compilazione.\r\n </span>\r\n } @else {\r\n <span class=\"dpe-sql__note\">Sola lettura: la libreria non esegue nulla.</span>\r\n }\r\n </div>\r\n\r\n @if (result(); as compiled) {\r\n @if (compiled.hasErrors) {\r\n <p class=\"dpe-sql__empty\">\r\n La compilazione si e’ fermata: ci sono errori di validazione, e nessun artefatto parziale\r\n viene prodotto. Guarda il pannello delle diagnostiche.\r\n </p>\r\n }\r\n\r\n @for (section of sections(); track $index) {\r\n @if (section.writebacks.length > 0) {\r\n <div class=\"dpe-sql__section\">\r\n <h4 class=\"dpe-sql__title\">{{ section.title }}</h4>\r\n <p class=\"dpe-sql__note\">{{ section.hint }}</p>\r\n @for (writeback of section.writebacks; track $index) {\r\n <div>\r\n <p class=\"dpe-sql__note\">\r\n <strong>{{ writeback.writebackName }}</strong> · sequenza {{ writeback.sequence }}\r\n </p>\r\n <pre>{{ writeback.statement.text }}</pre>\r\n @if (writeback.statement.parameters?.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>Parametro</th>\r\n <th>Tipo</th>\r\n <th>Valore</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (parameter of writeback.statement.parameters ?? []; track $index) {\r\n <tr>\r\n <td>{{ parameter.name }}</td>\r\n <td>{{ parameter.type }}</td>\r\n <td>{{ display(parameter.value) }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n @if (isEmpty()) {\r\n <p class=\"dpe-sql__empty\">Nessuna istruzione prodotta.</p>\r\n }\r\n } @else {\r\n <p class=\"dpe-sql__empty\">Nessuna anteprima richiesta.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeSqlPreviewComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n protected readonly validation = inject(DpeValidationService);\r\n\r\n readonly result = computed(() => this.store.compileResult());\r\n\r\n readonly sections = computed<DpeSqlSection[]>(() => {\r\n const compiled = this.result();\r\n return [\r\n {\r\n title: 'Scritture su database',\r\n hint: 'Istruzione consegnata all’host, che la esegue: la libreria non scrive.',\r\n writebacks: compiled?.databaseWritebacks ?? [],\r\n },\r\n {\r\n title: 'Artefatti (JSON / CSV)',\r\n hint: 'SQL di lettura con cui il file viene materializzato, non ancora eseguito.',\r\n writebacks: compiled?.fileWritebacks ?? [],\r\n },\r\n ];\r\n });\r\n\r\n readonly isEmpty = computed(() =>\r\n this.sections().every((section) => section.writebacks.length === 0),\r\n );\r\n\r\n /** Il valore di un parametro e' opaco: si mostra, non si converte. */\r\n protected display(value: unknown): string {\r\n if (value === null || value === undefined) {\r\n return 'NULL';\r\n }\r\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\r\n }\r\n}\r\n","/**\r\n * La vista dello schema: colonne in ingresso e in uscita, nodo per nodo.\r\n *\r\n * Tutto quello che si vede qui arriva da `Schemas` di `validate` (**I4**: propagazione pura e\r\n * deterministica, del backend). Il frontend non deduce niente — se il backend non ha ancora\r\n * risposto, la vista e' vuota e lo dice.\r\n *\r\n * Le colonne **in ingresso** sono lo schema dei nodi a monte, e servono accanto a quelle in\r\n * uscita per una cosa sola: vedere dove un **alias** cambia il nome di una colonna (**I5**) e\r\n * cosa arriva a valle con quel nome nuovo. Le colonne rinominate sono marcate: e' il punto in cui\r\n * un riferimento a valle sbaglia nome piu' spesso.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeAllNodes, dpeNodeSourceReferences } from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { DpeColumnInfo } from '../../model/dpe-api.model';\r\n\r\ninterface DpeSchemaRow {\r\n nodeName: string;\r\n categoryLabel: string;\r\n isSelected: boolean;\r\n isCompilable: boolean;\r\n hasSchema: boolean;\r\n inputColumns: readonly DpeColumnInfo[];\r\n outputColumns: readonly DpeColumnInfo[];\r\n /** Colonne in uscita che non esistono in ingresso: alias nuovi o colonne prodotte dal nodo. */\r\n introduced: ReadonlySet<string>;\r\n /** Colonne in ingresso che non arrivano in uscita: eliminate o rinominate. */\r\n dropped: readonly string[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-schema-panel',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n styles: [\r\n `\r\n :host {\r\n display: block;\r\n overflow: auto;\r\n padding: 8px 10px;\r\n background: var(--dpe-surface, #fff);\r\n font-size: 12px;\r\n }\r\n\r\n .dpe-schema__node {\r\n padding: 6px 0;\r\n border-bottom: 1px solid var(--dpe-border-subtle, #eef0f4);\r\n }\r\n\r\n .dpe-schema__head {\r\n display: flex;\r\n align-items: baseline;\r\n gap: 8px;\r\n }\r\n\r\n .dpe-schema__name {\r\n font-family: var(--dpe-font-mono, monospace);\r\n font-size: 11px;\r\n font-weight: 700;\r\n }\r\n\r\n .dpe-schema__node--selected .dpe-schema__name {\r\n color: var(--dpe-accent, #2f7d8f);\r\n }\r\n\r\n .dpe-schema__category {\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 10px;\r\n text-transform: uppercase;\r\n }\r\n\r\n .dpe-schema__line {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: baseline;\r\n gap: 4px;\r\n margin-top: 3px;\r\n }\r\n\r\n .dpe-schema__label {\r\n min-width: 62px;\r\n color: var(--dpe-text-muted, #6b7086);\r\n font-size: 10px;\r\n }\r\n\r\n .dpe-col {\r\n padding: 1px 6px;\r\n border: 1px solid var(--dpe-border, #e2e5eb);\r\n border-radius: 999px;\r\n background: var(--dpe-surface-alt, #f7f8fa);\r\n font-size: 10px;\r\n }\r\n\r\n .dpe-col--nullable {\r\n border-style: dashed;\r\n }\r\n\r\n /* Colonna che compare **qui**: un alias nuovo o una colonna calcolata. */\r\n .dpe-col--new {\r\n border-color: var(--dpe-accent, #2f7d8f);\r\n color: var(--dpe-accent-strong, #226270);\r\n font-weight: 600;\r\n }\r\n\r\n .dpe-col--dropped {\r\n border-color: var(--dpe-warning, #b7791f);\r\n color: var(--dpe-warning, #b7791f);\r\n text-decoration: line-through;\r\n }\r\n\r\n .dpe-schema__tag {\r\n padding: 0 6px;\r\n border: 1px solid var(--dpe-not-compilable, #7c5cd6);\r\n border-radius: 999px;\r\n color: var(--dpe-not-compilable, #7c5cd6);\r\n font-size: 9px;\r\n text-transform: uppercase;\r\n }\r\n\r\n .dpe-schema__empty {\r\n color: var(--dpe-text-subtle, #98a2b3);\r\n font-size: 11px;\r\n font-style: italic;\r\n }\r\n `,\r\n ],\r\n template: `\r\n @if (!hasResult()) {\r\n <p class=\"dpe-schema__empty\">In attesa della propagazione dello schema dal backend…</p>\r\n }\r\n\r\n @for (row of rows(); track $index) {\r\n <section class=\"dpe-schema__node\" [class.dpe-schema__node--selected]=\"row.isSelected\">\r\n <div class=\"dpe-schema__head\">\r\n <span class=\"dpe-schema__name\">{{ row.nodeName }}</span>\r\n <span class=\"dpe-schema__category\">{{ row.categoryLabel }}</span>\r\n @if (!row.isCompilable) {\r\n <span class=\"dpe-schema__tag\" title=\"Valido, ma non traducibile in SQL\">non compilabile</span>\r\n }\r\n </div>\r\n\r\n @if (row.inputColumns.length > 0) {\r\n <div class=\"dpe-schema__line\">\r\n <span class=\"dpe-schema__label\">In ingresso</span>\r\n @for (column of row.inputColumns; track $index) {\r\n <span\r\n class=\"dpe-col\"\r\n [class.dpe-col--nullable]=\"column.isNullable\"\r\n [class.dpe-col--dropped]=\"row.dropped.includes(column.name)\"\r\n [title]=\"column.type.kind\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-schema__line\">\r\n <span class=\"dpe-schema__label\">In uscita</span>\r\n @if (!row.hasSchema) {\r\n <span class=\"dpe-schema__empty\">nessuno schema propagato</span>\r\n }\r\n @for (column of row.outputColumns; track $index) {\r\n <span\r\n class=\"dpe-col\"\r\n [class.dpe-col--nullable]=\"column.isNullable\"\r\n [class.dpe-col--new]=\"row.introduced.has(column.name.toLowerCase())\"\r\n [title]=\"column.type.kind + (column.isNullable ? ' · nullabile' : ' · non nulla')\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n </section>\r\n }\r\n\r\n @if (rows().length > 0) {\r\n <p class=\"dpe-schema__empty\">\r\n In evidenza le colonne che il nodo <strong>introduce</strong> (alias nuovi e colonne\r\n calcolate) e barrate quelle che non arrivano a valle. Tratteggiate le nullabili.\r\n </p>\r\n }\r\n `,\r\n})\r\nexport class DpeSchemaPanelComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n readonly rows = computed<DpeSchemaRow[]>(() => {\r\n const definition = this.store.definition();\r\n const schemas = this.store.schemaByNode();\r\n const selected = this.store.selectedNodeName();\r\n const executionOrder = this.store.executionOrder();\r\n\r\n const located = dpeAllNodes(definition);\r\n // L'ordine e' quello **topologico** del backend quando c'e': leggere lo schema nell'ordine\r\n // in cui i dati scorrono e' l'unico modo di seguire un alias fino al sink.\r\n const ordered =\r\n executionOrder.length > 0\r\n ? [...located].sort(\r\n (left, right) =>\r\n indexOrLast(executionOrder, left.node.name) -\r\n indexOrLast(executionOrder, right.node.name),\r\n )\r\n : located;\r\n\r\n return ordered.map((entry) => {\r\n const schema = schemas.get(entry.node.name);\r\n const outputColumns = schema?.columns ?? [];\r\n const inputColumns: DpeColumnInfo[] = [];\r\n const seen = new Set<string>();\r\n for (const reference of dpeNodeSourceReferences(entry)) {\r\n if (!reference.isEdge || !reference.sourceName) {\r\n continue;\r\n }\r\n for (const column of schemas.get(reference.sourceName)?.columns ?? []) {\r\n const key = column.name.toLowerCase();\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n inputColumns.push(column);\r\n }\r\n }\r\n }\r\n const outputNames = new Set(outputColumns.map((column) => column.name.toLowerCase()));\r\n return {\r\n nodeName: entry.node.name,\r\n categoryLabel: dpeNodeCategory(entry.collection).label,\r\n isSelected: entry.node.name === selected,\r\n isCompilable: schema?.isCompilable !== false,\r\n hasSchema: schema !== undefined,\r\n inputColumns,\r\n outputColumns,\r\n introduced: new Set(\r\n outputColumns\r\n .map((column) => column.name.toLowerCase())\r\n .filter((name) => !seen.has(name)),\r\n ),\r\n dropped: inputColumns\r\n .filter((column) => !outputNames.has(column.name.toLowerCase()))\r\n .map((column) => column.name),\r\n };\r\n });\r\n });\r\n}\r\n\r\n/** I nodi fuori dall'ordine di esecuzione (irraggiungibili) finiscono in coda, non in testa. */\r\nfunction indexOrLast(order: readonly string[], name: string): number {\r\n const index = order.indexOf(name);\r\n return index < 0 ? Number.MAX_SAFE_INTEGER : index;\r\n}\r\n","/**\r\n * Il componente radice dell'editor: `<dpe-builder>`.\r\n *\r\n * Tiene i provider — store del documento, layout, validazione, metadati — **a livello di\r\n * componente** e non della root dell'applicazione: due editor sulla stessa pagina sono due\r\n * documenti indipendenti, con la loro cronologia e la loro selezione.\r\n *\r\n * Non conosce HTTP: tutto il traffico passa da `DpeBuilderApi`, che l'ospite fornisce.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n Signal,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\n\r\n\r\nimport { DpeDocumentStore } from '../core/dpe-document.store';\r\nimport { DpeLayoutService } from '../core/dpe-layout.service';\r\nimport { DpeMetadataStore } from '../core/dpe-metadata.store';\r\nimport { DpeValidationService } from '../core/dpe-validation.service';\r\nimport { dpeHasCompleteLayout } from '../core/dpe-node-layout';\r\nimport { dpeAllNodes } from '../core/dpe-graph';\r\nimport { DPE_DIALECT_LABELS } from '../core/dpe-node-catalog';\r\nimport { DpeDefinition, DpeNodeCollectionName, SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { DpeCanvasComponent } from './canvas/dpe-canvas.component';\r\nimport { DpeDiagnosticsPanelComponent } from './diagnostics/dpe-diagnostics-panel.component';\r\nimport { DpeNodeInspectorComponent } from './inspector/dpe-node-inspector.component';\r\nimport { DpeNodePaletteComponent } from './palette/dpe-node-palette.component';\r\nimport { DpeSqlPreviewComponent } from './preview/dpe-sql-preview.component';\r\nimport { DpeSchemaPanelComponent } from './schema/dpe-schema-panel.component';\r\n\r\n/** Le tre viste in basso: una alla volta, perche' guardano la stessa cosa da tre angoli. */\r\ntype DpeBottomTab = 'diagnostics' | 'schema' | 'sql';\r\n\r\n@Component({\r\n selector: 'dpe-builder',\r\n standalone: true,\r\n imports: [\r\n DpeCanvasComponent,\r\n DpeDiagnosticsPanelComponent,\r\n DpeNodeInspectorComponent,\r\n DpeNodePaletteComponent,\r\n DpeSchemaPanelComponent,\r\n DpeSqlPreviewComponent,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [DpeDocumentStore, DpeLayoutService, DpeValidationService, DpeMetadataStore],\r\n /**\r\n * `Ctrl+S` sul **componente**, non su `document`: due editor nella stessa pagina non devono\r\n * salvarsi a vicenda, e un ascoltatore globale installato dalla libreria intercetterebbe la\r\n * scorciatoia anche quando l'utente sta lavorando altrove nell'applicazione ospite.\r\n */\r\n host: { '(keydown)': 'onKeyDown($event)' },\r\n templateUrl: './dpe-builder.component.html',\r\n styleUrl: './dpe-builder.component.css',\r\n})\r\nexport class DpeBuilderComponent {\r\n protected readonly store = inject(DpeDocumentStore);\r\n protected readonly validation = inject(DpeValidationService);\r\n private readonly layout = inject(DpeLayoutService);\r\n\r\n /** La definizione da editare. Cambiarne l'identita' ricarica il documento. */\r\n readonly definition = input.required<DpeDefinition>();\r\n\r\n readonly isEditable = input(true);\r\n\r\n /**\r\n * Emessa a ogni mutazione. L'ospite **non deve** rimandarla dentro `definition`: sarebbe un\r\n * ciclo, e ricaricare azzera la cronologia. Serve per salvare, non per pilotare l'editor.\r\n */\r\n readonly definitionChange = output<DpeDefinition>();\r\n\r\n protected readonly dialectLabels = DPE_DIALECT_LABELS;\r\n\r\n protected readonly bottomTab = signal<DpeBottomTab>('diagnostics');\r\n\r\n private readonly canvas = viewChild(DpeCanvasComponent);\r\n\r\n /**\r\n * Il dialetto **della definizione**: e' quello con cui il backend compilera' (ADR 0009), quindi\r\n * e' quello che il badge mostra. In sola lettura: nessun comando dell'interfaccia lo cambia\r\n * (ADR 0017), perche' il database di destinazione e' un fatto dell'ambiente e non una\r\n * preferenza dell'autore.\r\n */\r\n protected readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n /**\r\n * Disallineamento fra cio' che l'ambiente dichiara e cio' che la definizione porta. Si\r\n * **segnala** e non si corregge: correggere vorrebbe dire migrare le espressioni SQL native\r\n * (ADR 0006), che e' dell'host. Assente `getEnvironment`, non c'e' niente da confrontare.\r\n */\r\n protected readonly dialectMismatch = computed<SqlDialectKind | undefined>(() => {\r\n const declared = this.validation.environmentDialect();\r\n return declared !== undefined && declared !== this.dialect() ? declared : undefined;\r\n });\r\n\r\n protected readonly canSave = computed(\r\n () => this.validation.isSaveAvailable() && !this.validation.isSaving() && this.store.isDirty(),\r\n );\r\n\r\n protected readonly nodeCount = computed(() => dpeAllNodes(this.store.definition()).length);\r\n\r\n constructor() {\r\n // Caricamento: si reagisce all'**identita'** dell'input, non al suo contenuto. Lo store\r\n // diventa la fonte di verita' da qui in poi.\r\n effect(() => {\r\n const incoming = this.definition();\r\n // `untracked` non e' prudenza: senza, questo effect **si richiama da solo**. Legge il\r\n // documento dello store (attraverso `load`, e a maggior ragione se un domani si leggesse\r\n // qualcosa dello store qui) e lo riscrive, quindi ogni scrittura successiva — anche quella\r\n // del layout automatico — lo farebbe ripartire e riportare il documento all'input,\r\n // cancellando il layout appena calcolato e ricominciando. Il sintomo non e' un errore: e'\r\n // una pagina che non si ferma piu' e uno schermo che sembra solo lento.\r\n untracked(() => this.store.load(incoming));\r\n });\r\n\r\n // Un documento senza coordinate (ADR 0013: sono opzionali) si dispone da solo, una volta.\r\n // Farlo a ogni cambio combatterebbe con chi sposta i nodi a mano.\r\n effect(() => {\r\n const nodes = dpeAllNodes(this.store.definition()).map((located) => located.node);\r\n if (nodes.length === 0 || dpeHasCompleteLayout(nodes)) {\r\n return;\r\n }\r\n // Il calcolo legge il grafo e le misure delle card: fuori da `untracked` diventerebbero\r\n // dipendenze di questo effect, che scrive proprio cio' che legge.\r\n untracked(() => this.runLayout(true));\r\n });\r\n\r\n // La definizione esce verso l'ospite a ogni mutazione: e' lui che sa se e quando salvare.\r\n effect(() => {\r\n this.definitionChange.emit(this.store.definition());\r\n });\r\n }\r\n\r\n /** Comando «Riordina»: e' un'azione dell'utente, quindi annullabile e \"modifica\". */\r\n protected runAutoLayout(): void {\r\n this.runLayout(false);\r\n }\r\n\r\n /**\r\n * `isInitial` distingue due cose che dagre calcola allo stesso modo e che l'editor deve trattare\r\n * in modo opposto: disporre un documento che **non porta** coordinate non e' una modifica\r\n * dell'utente; riordinare su richiesta lo e'.\r\n */\r\n private runLayout(isInitial: boolean): void {\r\n const canvas = this.canvas();\r\n if (!canvas) {\r\n return;\r\n }\r\n const positions = this.layout.layout(\r\n canvas.layoutInput(),\r\n this.store.graph().edges.map((edge) => ({\r\n from: edge.fromNodeName,\r\n to: edge.toNodeName,\r\n id: edge.id,\r\n })),\r\n );\r\n if (isInitial) {\r\n this.store.applyInitialPositions(positions);\r\n return;\r\n }\r\n this.store.applyPositions(positions);\r\n }\r\n\r\n protected onNodeDropped(event: { collection: DpeNodeCollectionName; x: number; y: number }): void {\r\n const name = this.store.createNodeAt(event.collection, { x: event.x, y: event.y });\r\n // Selezione immediata: chi ha appena creato un nodo lo deve configurare, e cercarlo con il\r\n // mouse subito dopo averlo rilasciato e' un passaggio inutile.\r\n this.store.select(name);\r\n }\r\n\r\n /** Clic sulla palette (via tastiera compresa): il nodo nasce in un punto libero e prevedibile. */\r\n protected onNodeRequested(collection: DpeNodeCollectionName): void {\r\n const existing = this.store.positions();\r\n let y = 60;\r\n for (const position of existing.values()) {\r\n y = Math.max(y, position.y + 140);\r\n }\r\n const name = this.store.createNodeAt(collection, { x: 80, y });\r\n this.store.select(name);\r\n }\r\n\r\n /**\r\n * `Ctrl+S` (e `Cmd+S`): stesse condizioni di abilitazione del bottone. `preventDefault` sempre\r\n * che la scorciatoia sia nostra, anche quando il salvataggio non e' possibile: lasciare passare\r\n * il «salva pagina» del browser proprio dentro un editor sarebbe la risposta sbagliata a un\r\n * gesto giusto.\r\n */\r\n protected onKeyDown(event: KeyboardEvent): void {\r\n if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== 's') {\r\n return;\r\n }\r\n event.preventDefault();\r\n if (this.canSave()) {\r\n this.validation.save();\r\n }\r\n }\r\n\r\n /**\r\n * Navigazione da una diagnostica: **selezione e vista**. Il `DiagnosticPath` promette di portare\r\n * sul nodo e sul campo; selezionare senza inquadrare mantiene meta' della promessa, e il nodo\r\n * resta fuori schermo mentre l'ispettore parla di lui.\r\n */\r\n protected onNavigate(event: { nodeName: string }): void {\r\n this.store.select(event.nodeName);\r\n // Si muove la **vista**, non il documento: le coordinate del nodo non si toccano.\r\n this.canvas()?.revealNode(event.nodeName);\r\n }\r\n\r\n /**\r\n * Stato **sporco** del documento, per l'ospite che deve decidere se lasciar navigare via\r\n * (ADR 0019). Delega a `DpeDocumentStore.isDirty`.\r\n *\r\n * Si legge tramite `viewChild` **quando serve**, non si rispecchia in uno stato dell'ospite: un\r\n * mirror di stato sporco che va fuori sincrono e' peggio del problema che risolve. La conferma\r\n * prima di abbandonare le modifiche e' dell'ospite, perche' e' l'ospite che naviga — la libreria\r\n * non sa se andare via significhi cambiare schermata, scheda o applicazione.\r\n */\r\n readonly isDirty: Signal<boolean> = this.store.isDirty;\r\n\r\n /**\r\n * Da chiamare dopo un salvataggio riuscito: da quel momento il documento risulta \"senza\r\n * modifiche\". Lo decide l'ospite, perche' solo lui sa se il salvataggio e' andato a buon fine.\r\n */\r\n markSaved(): void {\r\n this.store.markSaved();\r\n }\r\n}\r\n","<!--\r\n `.dpe-builder` porta le variabili del tema: e’ la classe radice su cui l’app ospite le\r\n sovrascrive, e `data-dpe-theme=\"dark\"` sul contenitore ridefinisce i soli token.\r\n-->\r\n<div class=\"dpe-builder dpe-shell\">\r\n <header class=\"dpe-shell__bar\">\r\n <div class=\"dpe-shell__title\">\r\n <strong>{{ store.definition().label || store.definition().name || 'Definizione DPE' }}</strong>\r\n <span class=\"dpe-shell__sub\">{{ nodeCount() }} nodi</span>\r\n <!--\r\n Stato **sporco** rispetto all’ultimo salvataggio, non un conteggio di operazioni: serve a\r\n decidere se salvare, e un contatore che sale quando si annulla risponde alla domanda\r\n sbagliata. Annullare fino allo stato di partenza torna qui a «nessuna modifica».\r\n -->\r\n <span\r\n class=\"dpe-shell__dirty\"\r\n [class.dpe-shell__dirty--on]=\"store.isDirty()\"\r\n [title]=\"\r\n store.isDirty()\r\n ? 'Il documento differisce dall’ultimo salvataggio'\r\n : 'Il documento coincide con l’ultimo salvataggio'\r\n \"\r\n >\r\n @if (store.isDirty()) {\r\n ● modificata\r\n } @else {\r\n ○ nessuna modifica\r\n }\r\n </span>\r\n </div>\r\n\r\n <!--\r\n Badge in **sola lettura** (ADR 0017): il dialetto e’ dichiarato dall’ambiente, non scelto\r\n qui. Mostra quello della definizione, che e’ quello con cui il backend compilera’ (ADR\r\n 0009). Il titolo dice le due cose che contano — chi lo decide, e che le espressioni sono\r\n SQL nativo di quel dialetto (ADR 0006).\r\n -->\r\n <span\r\n class=\"dpe-shell__dialect\"\r\n title=\"Il dialetto e’ dichiarato dall’ambiente e non si modifica dall’editor. Le espressioni sono SQL nativo di questo dialetto: la definizione gli appartiene.\"\r\n >\r\n Dialetto · <strong>{{ dialectLabels[dialect()] }}</strong>\r\n </span>\r\n\r\n <div class=\"dpe-shell__group\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn\"\r\n [disabled]=\"!store.canUndo()\"\r\n title=\"Annulla (la cronologia e’ una conseguenza dell’immutabilita’ dello stato)\"\r\n (click)=\"store.undo()\"\r\n >\r\n ↶ Annulla\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn\"\r\n [disabled]=\"!store.canRedo()\"\r\n title=\"Ripeti\"\r\n (click)=\"store.redo()\"\r\n >\r\n ↷ Ripeti\r\n </button>\r\n <button type=\"button\" class=\"dpe-shell__btn\" title=\"Riordina il grafo\" (click)=\"runAutoLayout()\">\r\n ⌗ Riordina\r\n </button>\r\n </div>\r\n\r\n <!--\r\n Salvataggio attraverso il contratto (`DpeBuilderApi.save`, opzionale). E’ il comando\r\n **primario**, separato dal gruppo annulla/ripeti/riordina: quelli disfano, questo scrive.\r\n\r\n **Sempre presente, mai nascosto.** Un bottone assente dice «questo editor non salva»; un\r\n bottone disabilitato con il motivo dice «qui non si salva, ed ecco perche’» — ed e’ la\r\n verita’ quando l’host non espone `save()`. La disponibilita’ si sa **prima del clic**\r\n (`core/dpe-capabilities.ts`), non dal primo fallimento.\r\n -->\r\n <div class=\"dpe-shell__group dpe-shell__group--primary\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn dpe-shell__btn--primary\"\r\n [disabled]=\"!canSave()\"\r\n [title]=\"\r\n !validation.isSaveAvailable()\r\n ? 'Salvataggio non disponibile su questo ambiente: l’host non espone save()'\r\n : validation.isSaving()\r\n ? 'Salvataggio in corso'\r\n : store.isDirty()\r\n ? 'Salva la definizione (Ctrl+S)'\r\n : 'Nessuna modifica da salvare'\r\n \"\r\n (click)=\"validation.save()\"\r\n >\r\n @if (validation.isSaving()) {\r\n ⤓ Salvataggio…\r\n } @else {\r\n ⤓ Salva\r\n }\r\n </button>\r\n @if (validation.justSaved()) {\r\n <!-- Avviso transitorio: il fatto durevole e’ «nessuna modifica» nell’indicatore. -->\r\n <span class=\"dpe-shell__toast\" role=\"status\">✓ Salvata</span>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-shell__status\">\r\n @if (validation.isValidating()) {\r\n <span class=\"dpe-shell__pill dpe-shell__pill--busy\">Validazione in corso…</span>\r\n } @else if (validation.error(); as error) {\r\n <!--\r\n Un guasto di trasporto non cancella le diagnostiche precedenti: dire «va tutto bene»\r\n quando non lo sappiamo piu’ e’ peggio che mostrare un risultato vecchio dichiarandolo.\r\n -->\r\n <span class=\"dpe-shell__pill dpe-shell__pill--error\" [title]=\"error.message\">\r\n Backend non raggiungibile ({{ error.category }})\r\n </span>\r\n } @else if (store.validateResult()) {\r\n <span\r\n class=\"dpe-shell__pill\"\r\n [class.dpe-shell__pill--error]=\"store.validateResult()!.hasErrors\"\r\n [class.dpe-shell__pill--ok]=\"!store.validateResult()!.hasErrors\"\r\n >\r\n @if (store.validateResult()!.hasErrors) {\r\n Con errori\r\n } @else {\r\n Nessun errore\r\n }\r\n </span>\r\n }\r\n </div>\r\n </header>\r\n\r\n @if (dialectMismatch(); as declared) {\r\n <!--\r\n Disallineamento fra la dichiarazione dell’ambiente e la definizione (ADR 0017). Si nominano\r\n **entrambi** i dialetti e non si offre di correggere: correggere significherebbe migrare le\r\n espressioni SQL native, ed e’ dell’host. Non e’ una regola di dominio duplicata — non giudica\r\n la definizione, riporta il disaccordo fra due fatti che l’ospite ha fornito.\r\n -->\r\n <div class=\"dpe-shell__warn\" role=\"alert\">\r\n <strong>\r\n L’ambiente dichiara {{ dialectLabels[declared] }}, la definizione e’ scritta per\r\n {{ dialectLabels[dialect()] }}.\r\n </strong>\r\n <p>\r\n Il backend compilera’ con il dialetto <strong>della definizione</strong>. Allinearli e’ una\r\n migrazione delle espressioni SQL native e non si fa da qui.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (validation.saveError(); as error) {\r\n <!--\r\n Banner **persistente**: un salvataggio fallito in silenzio e’ peggio di nessun salvataggio,\r\n perche’ l’indicatore «modificata» sparirebbe per un’operazione che non e’ avvenuta. Qui non\r\n sparisce: `markSaved()` viene chiamato solo al successo.\r\n -->\r\n <div class=\"dpe-shell__warn dpe-shell__warn--error\" role=\"alert\">\r\n <strong>Salvataggio non riuscito ({{ error.category }})</strong>\r\n <p>{{ error.message }}</p>\r\n <div class=\"dpe-shell__group\">\r\n <button type=\"button\" class=\"dpe-shell__btn\" (click)=\"validation.dismissSaveError()\">\r\n Ho capito\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-shell__body\">\r\n <dpe-node-palette class=\"dpe-shell__palette\" (nodeRequested)=\"onNodeRequested($event)\" />\r\n\r\n <dpe-canvas\r\n class=\"dpe-shell__canvas\"\r\n [isEditable]=\"isEditable()\"\r\n (nodeDropped)=\"onNodeDropped($event)\"\r\n />\r\n\r\n <dpe-node-inspector class=\"dpe-shell__inspector\" (layoutRequested)=\"runAutoLayout()\" />\r\n </div>\r\n\r\n <div class=\"dpe-shell__bottom\">\r\n <div class=\"dpe-shell__tabs\" role=\"tablist\" aria-label=\"Pannelli\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'diagnostics'\"\r\n [attr.aria-selected]=\"bottomTab() === 'diagnostics'\"\r\n (click)=\"bottomTab.set('diagnostics')\"\r\n >\r\n Diagnostiche\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'schema'\"\r\n [attr.aria-selected]=\"bottomTab() === 'schema'\"\r\n (click)=\"bottomTab.set('schema')\"\r\n >\r\n Schema\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'sql'\"\r\n [attr.aria-selected]=\"bottomTab() === 'sql'\"\r\n (click)=\"bottomTab.set('sql')\"\r\n >\r\n SQL generato\r\n </button>\r\n </div>\r\n\r\n @switch (bottomTab()) {\r\n @case ('diagnostics') {\r\n <dpe-diagnostics-panel class=\"dpe-shell__panel\" (navigate)=\"onNavigate($event)\" />\r\n }\r\n @case ('schema') {\r\n <dpe-schema-panel class=\"dpe-shell__panel\" />\r\n }\r\n @case ('sql') {\r\n <dpe-sql-preview class=\"dpe-shell__panel\" />\r\n }\r\n }\r\n </div>\r\n</div>\r\n","/**\r\n * Il catalogo delle definizioni: `<dpe-catalog>` (ADR 0019).\r\n *\r\n * **E' fratello dell'editor, non suo genitore.** `DpeBuilderComponent` non lo importa, non lo\r\n * conosce e non lo monta: `definition` resta `input.required`, l'ospite che vuole solo l'editor\r\n * non paga nulla, e due editor nella stessa pagina non diventano due cataloghi affiancati.\r\n *\r\n * Cosa fa: elenca, filtra in locale, crea, duplica, cancella. Cosa **non** fa: aprire. Emette il\r\n * **nome** con `open` e si ferma li', perche' chi apre puo' voler instradare, controllare permessi\r\n * o aprire in un'altra scheda — decisioni dell'ospite, non nostre.\r\n *\r\n * Provider dello store a livello di **componente**, come per l'editor: due cataloghi in due punti\r\n * dell'ospite sono due elenchi indipendenti.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n Injector,\r\n afterNextRender,\r\n computed,\r\n inject,\r\n output,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\n\r\nimport { DpeCatalogStore } from '../../core/dpe-catalog.store';\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { DpeDefinitionSummary } from '../../model/dpe-api.model';\r\n\r\n@Component({\r\n selector: 'dpe-catalog',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [DpeCatalogStore],\r\n templateUrl: './dpe-catalog.component.html',\r\n styleUrl: './dpe-catalog.component.css',\r\n})\r\nexport class DpeCatalogComponent {\r\n protected readonly store = inject(DpeCatalogStore);\r\n private readonly injector = inject(Injector);\r\n\r\n /**\r\n * Il **nome** della definizione da aprire. Non la definizione: caricarla e' dell'ospite, che\r\n * potrebbe volerlo fare per vie proprie.\r\n */\r\n readonly open = output<string>();\r\n\r\n protected readonly dialectLabels = DPE_DIALECT_LABELS;\r\n\r\n /** Filtro **locale** sui sommari gia' ricevuti: non e' una query al backend (ADR 0019). */\r\n protected readonly filter = signal('');\r\n\r\n protected readonly newName = signal('');\r\n protected readonly newLabel = signal('');\r\n\r\n /**\r\n * Conferma in **due passi**: un elenco in cui un clic distratto cancella non e' un elenco.\r\n * Tiene il nome invece di un booleano perche' la conferma appartiene a **quella** riga.\r\n */\r\n protected readonly pendingDelete = signal<string | null>(null);\r\n\r\n /** Riga in duplicazione, con i due campi del nome e dell'etichetta nuovi. */\r\n protected readonly duplicateSource = signal<string | null>(null);\r\n protected readonly duplicateName = signal('');\r\n protected readonly duplicateLabel = signal('');\r\n\r\n private readonly duplicateNameField =\r\n viewChild<ElementRef<HTMLInputElement>>('duplicateNameField');\r\n\r\n /**\r\n * Il filtro non tocca l'ordine: si tolgono righe, non si riordinano. `toLocaleLowerCase` e non\r\n * `toLowerCase` perche' un elenco di definizioni italiane si filtra anche per lettere accentate.\r\n */\r\n protected readonly visible = computed<readonly DpeDefinitionSummary[]>(() => {\r\n const needle = this.filter().trim().toLocaleLowerCase();\r\n if (needle.length === 0) {\r\n return this.store.summaries();\r\n }\r\n return this.store\r\n .summaries()\r\n .filter(\r\n (summary) =>\r\n summary.name.toLocaleLowerCase().includes(needle) ||\r\n summary.label.toLocaleLowerCase().includes(needle),\r\n );\r\n });\r\n\r\n /** Vero quando il filtro ha nascosto tutto: e' un messaggio diverso da «nessuna definizione». */\r\n protected readonly isFilteredEmpty = computed(\r\n () => this.store.summaries().length > 0 && this.visible().length === 0,\r\n );\r\n\r\n /**\r\n * Duplicare richiede **due** primitive, `load` e `createDefinition`: non esiste una primitiva\r\n * di duplicazione, il comando si compone da queste.\r\n */\r\n protected readonly canDuplicate = computed(\r\n () => this.store.capabilities.load && this.store.capabilities.createDefinition,\r\n );\r\n\r\n protected readonly duplicateReason = computed(() =>\r\n this.canDuplicate()\r\n ? 'Duplica: carica questa definizione e la ricrea con un nome nuovo'\r\n : 'Duplicazione non disponibile: questo ambiente non implementa load e createDefinition.',\r\n );\r\n\r\n /** Validazione **di forma**, l'unica ammessa nel frontend: due campi non vuoti. */\r\n protected readonly canSubmitNew = computed(\r\n () =>\r\n this.store.createCommand.isAvailable &&\r\n !this.store.isMutating() &&\r\n this.newName().trim().length > 0 &&\r\n this.newLabel().trim().length > 0,\r\n );\r\n\r\n protected readonly canSubmitDuplicate = computed(\r\n () =>\r\n this.canDuplicate() &&\r\n !this.store.isMutating() &&\r\n this.duplicateName().trim().length > 0 &&\r\n this.duplicateLabel().trim().length > 0,\r\n );\r\n\r\n protected onOpen(name: string): void {\r\n this.open.emit(name);\r\n }\r\n\r\n protected refresh(): void {\r\n this.pendingDelete.set(null);\r\n this.store.refresh();\r\n }\r\n\r\n /**\r\n * Crea e **apre il nome tornato dall'ospite**, non quello digitato: l'ospite puo' averlo\r\n * normalizzato, e aprire quello digitato aprirebbe una definizione che non esiste.\r\n */\r\n protected createNew(): void {\r\n if (!this.canSubmitNew()) {\r\n return;\r\n }\r\n const dialect = this.store.environmentDialect();\r\n if (dialect === undefined) {\r\n // Non dovrebbe accadere: `createCommand` lo esige. Se accade, non si ripiega su un\r\n // dialetto qualsiasi — sarebbe una definizione per il database sbagliato.\r\n return;\r\n }\r\n this.store\r\n .create(this.newName().trim(), this.newLabel().trim(), dialect)\r\n .subscribe((summary) => {\r\n this.newName.set('');\r\n this.newLabel.set('');\r\n this.open.emit(summary.name);\r\n });\r\n }\r\n\r\n protected startDuplicate(summary: DpeDefinitionSummary): void {\r\n this.pendingDelete.set(null);\r\n this.duplicateSource.set(summary.name);\r\n this.duplicateName.set(`${summary.name}Copia`);\r\n this.duplicateLabel.set(`${summary.label} (copia)`);\r\n // `afterNextRender` e non `setTimeout`: il rinvio al task successivo scatta **prima** del\r\n // refresh della view, la query e' ancora vuota e il focus non arriva — senza nessun errore.\r\n afterNextRender(() => this.duplicateNameField()?.nativeElement.focus(), {\r\n injector: this.injector,\r\n });\r\n }\r\n\r\n protected cancelDuplicate(): void {\r\n this.duplicateSource.set(null);\r\n }\r\n\r\n protected confirmDuplicate(): void {\r\n const source = this.duplicateSource();\r\n if (source === null || !this.canSubmitDuplicate()) {\r\n return;\r\n }\r\n this.store\r\n .duplicate(source, this.duplicateName().trim(), this.duplicateLabel().trim())\r\n .subscribe(() => {\r\n // Si resta nell'elenco: la riga nuova che compare **e'** la conferma. Aprire la copia\r\n // porterebbe via dall'elenco proprio chi sta riorganizzando il catalogo.\r\n this.duplicateSource.set(null);\r\n });\r\n }\r\n\r\n protected askDelete(name: string): void {\r\n this.duplicateSource.set(null);\r\n this.pendingDelete.set(name);\r\n }\r\n\r\n protected cancelDelete(): void {\r\n this.pendingDelete.set(null);\r\n }\r\n\r\n protected confirmDelete(name: string): void {\r\n this.pendingDelete.set(null);\r\n this.store.remove(name);\r\n }\r\n\r\n /** Solo la data, senza ora: un elenco non e' un registro di audit. */\r\n protected formatDate(value: string): string {\r\n const parsed = new Date(value);\r\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString();\r\n }\r\n}\r\n","<!--\r\n `.dpe-theme` porta le variabili del tema anche fuori dall’editor: il catalogo e’ un componente\r\n **fratello**, quindi non puo’ contare sulla classe radice di `<dpe-builder>`. La variante scura\r\n resta quella prevista, `data-dpe-theme=\"dark\"` su un contenitore dell’ospite.\r\n-->\r\n<section class=\"dpe-theme dpe-cat\" aria-labelledby=\"dpe-cat-title\">\r\n <header class=\"dpe-cat__bar\">\r\n <h2 class=\"dpe-cat__title\" id=\"dpe-cat-title\">Definizioni DPE</h2>\r\n\r\n <span class=\"dpe-cat__count\">\r\n @if (store.isLoading()) {\r\n caricamento…\r\n } @else if (!store.capabilities.listDefinitions) {\r\n elenco non disponibile\r\n } @else {\r\n {{ visible().length }} di {{ store.summaries().length }}\r\n }\r\n </span>\r\n\r\n <input\r\n class=\"dpe-cat__filter\"\r\n type=\"search\"\r\n placeholder=\"Filtra per nome o etichetta\"\r\n aria-label=\"Filtra le definizioni\"\r\n [value]=\"filter()\"\r\n (input)=\"filter.set($any($event.target).value)\"\r\n />\r\n\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!store.capabilities.listDefinitions || store.isLoading()\"\r\n [title]=\"\r\n store.capabilities.listDefinitions\r\n ? 'Ricarica l’elenco'\r\n : 'Questo ambiente non implementa listDefinitions.'\r\n \"\r\n (click)=\"refresh()\"\r\n >\r\n ⟳ Aggiorna\r\n </button>\r\n </header>\r\n\r\n @if (store.error(); as error) {\r\n <!--\r\n Banner persistente: un errore di catalogo che svanisce lascia un elenco vecchio senza dire\r\n che e’ vecchio. La categoria si mostra perche’ distingue «riprova» da «chiedi all’ospite».\r\n -->\r\n <p class=\"dpe-cat__error\" role=\"alert\">\r\n <strong>{{ error.category }}</strong> {{ error.message }}\r\n <button type=\"button\" class=\"dpe-cat__dismiss\" aria-label=\"Chiudi\" (click)=\"store.dismissError()\">\r\n ×\r\n </button>\r\n </p>\r\n }\r\n\r\n <ul class=\"dpe-cat__list\">\r\n @for (summary of visible(); track summary.name) {\r\n <li class=\"dpe-cat__item\" [class.dpe-cat__item--busy]=\"store.isMutating()\">\r\n <div class=\"dpe-cat__row\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__open\"\r\n [title]=\"'Apri ' + summary.label\"\r\n (click)=\"onOpen(summary.name)\"\r\n >\r\n <span class=\"dpe-cat__label\">{{ summary.label }}</span>\r\n <span class=\"dpe-cat__meta\">\r\n <!--\r\n Solo i fatti **presenti**: cio’ che il sommario non porta non si stima. Contare i\r\n nodi lato client vorrebbe dire caricare tutte le definizioni per disegnare un\r\n elenco (ADR 0019).\r\n -->\r\n <code class=\"dpe-cat__name\">{{ summary.name }}</code>\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ dialectLabels[summary.dialect] }}\r\n @if (summary.status) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.status === 'Active' ? 'attiva' : 'non attiva' }}\r\n }\r\n @if (summary.runMode) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.runMode === 'Batch' ? 'batch' : 'a richiesta' }}\r\n }\r\n @if (summary.isTemplate) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n modello\r\n }\r\n @if (summary.nodeCount !== undefined) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.nodeCount }} {{ summary.nodeCount === 1 ? 'nodo' : 'nodi' }}\r\n }\r\n @if (summary.updatedAt) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ formatDate(summary.updatedAt) }}\r\n @if (summary.updatedBy) {\r\n · {{ summary.updatedBy }}\r\n }\r\n }\r\n </span>\r\n @if (summary.description) {\r\n <span class=\"dpe-cat__desc\">{{ summary.description }}</span>\r\n }\r\n </button>\r\n\r\n <!--\r\n `hasErrors` e’ **riportato, non ricalcolato** (ADR 0019): il frontend non valida\r\n niente. Per questo l’etichetta dice «ultima validazione nota» e non «invalida»: puo’\r\n essere vecchia, e spacciarla per verita’ sarebbe una validazione fatta dal client per\r\n interposta persona. Assente, non compare nulla.\r\n -->\r\n @if (summary.hasErrors !== undefined) {\r\n <span\r\n class=\"dpe-cat__flag\"\r\n [class.dpe-cat__flag--errors]=\"summary.hasErrors\"\r\n [title]=\"\r\n summary.hasErrors\r\n ? 'Ultima validazione nota all’ambiente: con errori. E’ uno stato riportato, non ricalcolato qui.'\r\n : 'Ultima validazione nota all’ambiente: senza errori. E’ uno stato riportato, non ricalcolato qui.'\r\n \"\r\n >\r\n {{ summary.hasErrors ? 'con errori (stato noto)' : 'senza errori (stato noto)' }}\r\n </span>\r\n }\r\n\r\n <div class=\"dpe-cat__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!canDuplicate() || store.isMutating()\"\r\n [title]=\"duplicateReason()\"\r\n (click)=\"startDuplicate(summary)\"\r\n >\r\n Duplica\r\n </button>\r\n\r\n @if (pendingDelete() === summary.name) {\r\n <!-- Conferma in **due passi**: la prima pressione chiede, la seconda cancella. -->\r\n <span class=\"dpe-cat__confirm\">\r\n Eliminare «{{ summary.name }}»?\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--danger\"\r\n (click)=\"confirmDelete(summary.name)\"\r\n >\r\n Elimina\r\n </button>\r\n <button type=\"button\" class=\"dpe-cat__btn\" (click)=\"cancelDelete()\">Annulla</button>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!store.capabilities.deleteDefinition || store.isMutating()\"\r\n [title]=\"\r\n store.capabilities.deleteDefinition\r\n ? 'Elimina (chiede conferma)'\r\n : 'Eliminazione non disponibile: questo ambiente non implementa deleteDefinition.'\r\n \"\r\n (click)=\"askDelete(summary.name)\"\r\n >\r\n Elimina\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (duplicateSource() === summary.name) {\r\n <!--\r\n Duplicare e’ `load` piu’ `createDefinition`: nessuna primitiva nuova sul contratto.\r\n Il dialetto resta quello della definizione copiata — le espressioni sono SQL nativo.\r\n -->\r\n <div class=\"dpe-cat__form dpe-cat__form--inline\">\r\n <label class=\"dpe-cat__field\">\r\n <span>Nome della copia</span>\r\n <input\r\n #duplicateNameField\r\n class=\"dpe-cat__input\"\r\n [value]=\"duplicateName()\"\r\n (input)=\"duplicateName.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <label class=\"dpe-cat__field\">\r\n <span>Etichetta della copia</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n [value]=\"duplicateLabel()\"\r\n (input)=\"duplicateLabel.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--primary\"\r\n [disabled]=\"!canSubmitDuplicate()\"\r\n (click)=\"confirmDuplicate()\"\r\n >\r\n Duplica\r\n </button>\r\n <button type=\"button\" class=\"dpe-cat__btn\" (click)=\"cancelDuplicate()\">Annulla</button>\r\n </div>\r\n }\r\n </li>\r\n } @empty {\r\n <li class=\"dpe-cat__empty\">\r\n @if (!store.capabilities.listDefinitions) {\r\n Questo ambiente non implementa <code>listDefinitions</code>: l’elenco lo fornisce\r\n l’applicazione ospite.\r\n } @else if (store.isLoading()) {\r\n Caricamento dell’elenco…\r\n } @else if (isFilteredEmpty()) {\r\n Nessuna definizione corrisponde al filtro.\r\n } @else if (store.hasLoaded()) {\r\n Nessuna definizione. Creane una qui sotto.\r\n } @else {\r\n Elenco non disponibile.\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <footer class=\"dpe-cat__foot\">\r\n <div class=\"dpe-cat__form\">\r\n <label class=\"dpe-cat__field\">\r\n <span>Nome tecnico</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n placeholder=\"RiepilogoOrdini\"\r\n [value]=\"newName()\"\r\n [disabled]=\"!store.createCommand.isAvailable\"\r\n (input)=\"newName.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <label class=\"dpe-cat__field\">\r\n <!--\r\n Si chiedono **due** campi e non uno: passare il nome anche come etichetta produce per\r\n sempre un catalogo di nomi tecnici, e un default sbagliato non si corregge piu’.\r\n -->\r\n <span>Etichetta</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n placeholder=\"Riepilogo ordini\"\r\n [value]=\"newLabel()\"\r\n [disabled]=\"!store.createCommand.isAvailable\"\r\n (input)=\"newLabel.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--primary\"\r\n [disabled]=\"!canSubmitNew()\"\r\n [title]=\"\r\n store.createCommand.reason ??\r\n 'Crea la definizione e la apre. Il dialetto viene dall’ambiente, non si sceglie qui.'\r\n \"\r\n (click)=\"createNew()\"\r\n >\r\n + Crea e apri\r\n </button>\r\n </div>\r\n\r\n <p class=\"dpe-cat__hint\">\r\n @if (store.createCommand.isAvailable) {\r\n <!--\r\n Detto **al momento della creazione**, non lasciato scoprire: una definizione nuova non\r\n ha sorgenti ne’ writeback, quindi l’editor la segnalera’ invalida. E’ normale — il\r\n modello tollera l’incompleto e la validazione lo racconta.\r\n -->\r\n Il dialetto della definizione nuova e’ quello dichiarato dall’ambiente\r\n @if (store.environmentDialect(); as declared) {\r\n (<strong>{{ dialectLabels[declared] }}</strong>)\r\n }\r\n e non si sceglie qui: le espressioni sono SQL nativo di quel dialetto. Una definizione appena creata\r\n e’ <strong>invalida</strong> — servono almeno una sorgente e un writeback — ed e’ normale.\r\n } @else {\r\n {{ store.createCommand.reason }}\r\n }\r\n </p>\r\n </footer>\r\n</section>\r\n","/*\r\n * Superficie pubblica di `@esfaenza/dpe-builder`.\r\n *\r\n * Cio' che non e' esportato qui non e' API: chi integra la libreria usa questi tipi e nulla\r\n * di piu'. In questa tranche esistono contratto, modello e `core/`; i componenti dell'editor\r\n * arrivano nella successiva.\r\n */\r\n\r\n// Contratto verso il backend: il contratto **e'** la classe astratta (ADR 0007).\r\nexport * from './lib/api/dpe-builder-api';\r\nexport * from './lib/api/dpe-api-error';\r\n// Client HTTP di libreria (ADR 0020, che revisiona la collocazione decisa dall'ADR 0007). E'\r\n// **una** implementazione del contratto, non il contratto: chi non usa HTTP non la registra e\r\n// `sideEffects: false` la rende eliminabile dal bundle.\r\nexport * from './lib/api/http-dpe-builder-api';\r\n\r\n// Modello: allineato a mano ai record C#.\r\nexport * from './lib/model/dpe-definition.model';\r\nexport * from './lib/model/dpe-diagnostics.model';\r\nexport * from './lib/model/dpe-api.model';\r\n\r\n// Stato e utility pure.\r\nexport * from './lib/core/dpe-capabilities';\r\nexport * from './lib/core/dpe-catalog.store';\r\nexport * from './lib/core/dpe-document.store';\r\nexport * from './lib/core/dpe-diagnostics.util';\r\nexport * from './lib/core/dpe-graph';\r\nexport * from './lib/core/dpe-layout.service';\r\nexport * from './lib/core/dpe-metadata.store';\r\nexport * from './lib/core/dpe-node-catalog';\r\nexport * from './lib/core/dpe-node-icons';\r\nexport * from './lib/core/dpe-node-factory';\r\nexport * from './lib/core/dpe-node-layout';\r\nexport * from './lib/core/dpe-validation.service';\r\nexport * from './lib/core/dpe-viewport';\r\n\r\n// UI: il componente radice e i pezzi montabili da soli.\r\nexport * from './lib/ui/dpe-builder.component';\r\nexport * from './lib/ui/canvas/dpe-canvas.component';\r\n// Il catalogo (ADR 0019) e' **fratello** dell'editor: esportato perche' l'ospite possa montarlo,\r\n// e non importato da `DpeBuilderComponent`. Chi vuole solo l'editor non lo paga.\r\nexport * from './lib/ui/catalog/dpe-catalog.component';\r\nexport * from './lib/ui/canvas/dpe-canvas.model';\r\nexport * from './lib/ui/palette/dpe-node-palette.component';\r\nexport * from './lib/ui/inspector/dpe-node-inspector.component';\r\nexport * from './lib/ui/inspector/dpe-node-inspector-base';\r\nexport * from './lib/ui/diagnostics/dpe-diagnostics-panel.component';\r\nexport * from './lib/ui/schema/dpe-schema-panel.component';\r\nexport * from './lib/ui/preview/dpe-sql-preview.component';\r\nexport * from './lib/ui/shared/dpe-expression-editor.component';\r\nexport * from './lib/ui/shared/dpe-column-type-editor.component';\r\nexport * from './lib/ui/shared/dpe-select-value.directive';\r\nexport * from './lib/ui/shared/dpe-node-icon.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["FUNCTIONS","KINDS","DELIMITERS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"esfaenza-dpe-builder.mjs","sources":["../../../projects/dpe-builder/src/lib/api/dpe-api-error.ts","../../../projects/dpe-builder/src/lib/api/dpe-builder-api.ts","../../../projects/dpe-builder/src/lib/api/http-dpe-builder-api.ts","../../../projects/dpe-builder/src/lib/model/dpe-definition.model.ts","../../../projects/dpe-builder/src/lib/model/dpe-diagnostics.model.ts","../../../projects/dpe-builder/src/lib/model/dpe-api.model.ts","../../../projects/dpe-builder/src/lib/core/dpe-capabilities.ts","../../../projects/dpe-builder/src/lib/core/dpe-graph.ts","../../../projects/dpe-builder/src/lib/core/dpe-diagnostics.util.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-layout.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-catalog.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-factory.ts","../../../projects/dpe-builder/src/lib/core/dpe-document.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-catalog.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-layout.service.ts","../../../projects/dpe-builder/src/lib/core/dpe-metadata.store.ts","../../../projects/dpe-builder/src/lib/core/dpe-node-icons.ts","../../../projects/dpe-builder/src/lib/core/dpe-validation.service.ts","../../../projects/dpe-builder/src/lib/core/dpe-viewport.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-node-icon.component.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.model.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.component.ts","../../../projects/dpe-builder/src/lib/ui/canvas/dpe-canvas.component.html","../../../projects/dpe-builder/src/lib/ui/diagnostics/dpe-diagnostics-panel.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-select-value.directive.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-node-inspector-base.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-aggregate-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-append-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-atomic-writeback-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-column-type-editor.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-custom-node-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-data-source-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-filter-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-forecast-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-hierarchy-path-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-join-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/shared/dpe-expression-editor.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-transform-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-writeback-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/inspector/dpe-node-inspector.component.ts","../../../projects/dpe-builder/src/lib/ui/palette/dpe-node-palette.component.ts","../../../projects/dpe-builder/src/lib/ui/preview/dpe-sql-preview.component.ts","../../../projects/dpe-builder/src/lib/ui/schema/dpe-schema-panel.component.ts","../../../projects/dpe-builder/src/lib/ui/dpe-builder.component.ts","../../../projects/dpe-builder/src/lib/ui/dpe-builder.component.html","../../../projects/dpe-builder/src/lib/ui/catalog/dpe-catalog.component.ts","../../../projects/dpe-builder/src/lib/ui/catalog/dpe-catalog.component.html","../../../projects/dpe-builder/src/public-api.ts","../../../projects/dpe-builder/src/esfaenza-dpe-builder.ts"],"sourcesContent":["/**\r\n * Errore categorizzato del contratto verso il backend.\r\n *\r\n * L'editor si comporta in base alla **categoria**, mai leggendo il messaggio: chi implementa\r\n * {@link DpeBuilderApi} traduce l'errore di trasporto (status HTTP, payload, timeout) in un\r\n * `DpeApiError`, e da lì in poi nella libreria non esiste piu' nessuna nozione di HTTP\r\n * (ADR 0007).\r\n */\r\n\r\n/**\r\n * Le categorie sono **tre** e chiuse, perche' sono tre comportamenti diversi della UI:\r\n *\r\n * - `MissingService`: la primitiva non e' implementata su questo ambiente. Degrada il\r\n * **singolo comando** (l'anteprima SQL si disabilita), non l'editor;\r\n * - `Transport`: la chiamata non e' arrivata o non e' tornata. Si puo' ritentare;\r\n * - `Backend`: il backend ha risposto rifiutando. Non si ritenta da soli.\r\n *\r\n * Un errore di validazione **non e'** una categoria: le diagnostiche sono un *risultato*\r\n * (`DpeValidateResult.diagnostics`), non un fallimento — e' la stessa regola del backend,\r\n * dove il fallimento previsto e' un risultato e non un'eccezione.\r\n */\r\nexport type DpeApiErrorCategory = 'MissingService' | 'Transport' | 'Backend';\r\n\r\nexport class DpeApiError extends Error {\r\n constructor(\r\n readonly category: DpeApiErrorCategory,\r\n message: string,\r\n /** Payload di dettaglio dell'host, opaco per la libreria. */\r\n readonly details?: unknown,\r\n ) {\r\n super(message);\r\n this.name = 'DpeApiError';\r\n }\r\n\r\n static is(value: unknown): value is DpeApiError {\r\n return value instanceof DpeApiError;\r\n }\r\n\r\n /** Vero quando il comando corrispondente va disabilitato invece che segnalato. */\r\n static isMissingService(value: unknown): boolean {\r\n return DpeApiError.is(value) && value.category === 'MissingService';\r\n }\r\n}\r\n\r\n/** Messaggi di ripiego: il `message` dell'host, quando c'e', ha la precedenza. */\r\nexport const DPE_API_ERROR_FALLBACK_MESSAGE: Record<DpeApiErrorCategory, string> = {\r\n MissingService: 'Funzione non configurata su questo ambiente.',\r\n Transport: 'Il backend non e’ raggiungibile.',\r\n Backend: 'Il backend ha rifiutato la richiesta.',\r\n};\r\n","/**\r\n * L'unica porta verso il backend — `docs/contracts.md` §7.\r\n *\r\n * **Non esiste un documento di endpoint: il contratto e' questa classe astratta** (ADR 0007).\r\n * Fa anche da token di dependency injection: chi integra l'editor fornisce una\r\n * implementazione e la registra come provider di `DpeBuilderApi`.\r\n *\r\n * Due conseguenze da non aggirare:\r\n *\r\n * 1. **questo file non conosce HTTP.** Nessun `HttpClient`, nessun `fetch`, nessun URL qui ne'\r\n * in nessuno store o componente. L'ADR 0020 ha spostato il client HTTP **dentro** la libreria\r\n * (`lib/api/http-dpe-builder-api.ts`), quindi la regola non e' piu' «zero HTTP in\r\n * `projects/dpe-builder`» ma «zero HTTP fuori da quel file»: e' *una* implementazione fra le\r\n * possibili, non la definizione del contratto, che resta questa classe;\r\n * 2. **un dato nuovo dal backend e' un metodo nuovo qui**, mai una chiamata dentro un\r\n * componente.\r\n *\r\n * I metodi con implementazione di default rifiutano con `DpeApiError('MissingService', ...)`:\r\n * un ambiente che non li espone lascia l'editor funzionante con il singolo comando\r\n * disabilitato. Un'anteprima SQL non disponibile disabilita l'anteprima, non l'editor.\r\n *\r\n * I metodi restituiscono `Observable` perche' l'I/O del frontend e' asincrono per natura. Il\r\n * vincolo di sincronia della libreria C# riguarda il backend: qui si traduce solo nel fatto\r\n * che una chiamata occupa il chiamante finche' non termina, quindi chi la invoca mostra\r\n * l'attesa e non incatena una validazione a ogni battitura senza debounce.\r\n */\r\n\r\nimport { Observable, throwError } from 'rxjs';\r\n\r\nimport { DpeDefinition } from '../model/dpe-definition.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeDefinitionSummary,\r\n DpeEnvironment,\r\n DpeParameterValue,\r\n DpeValidateResult,\r\n TableLookupResult,\r\n TableSummary,\r\n} from '../model/dpe-api.model';\r\nimport { DpeApiError } from './dpe-api-error';\r\n// Import di **solo tipo**: `core/dpe-capabilities` importa questa classe, e senza `import type`\r\n// il ciclo sarebbe reale a runtime. Il tipo si cancella in compilazione, il ciclo no.\r\nimport type { DpeOptionalPrimitive } from '../core/dpe-capabilities';\r\n\r\n/** Ripiego dei metodi opzionali non implementati dall'host. */\r\nfunction missing(primitive: string): Observable<never> {\r\n return throwError(\r\n () => new DpeApiError('MissingService', `Primitiva non disponibile su questo ambiente: ${primitive}.`),\r\n );\r\n}\r\n\r\nexport abstract class DpeBuilderApi {\r\n /**\r\n * Primitive opzionali che **questo ambiente non serve**, dichiarate dall'ospite (ADR 0020,\r\n * `contracts.md` §7).\r\n *\r\n * Perche' esiste, dato che la rilevazione per identita' del metodo bastava: da quando la\r\n * libreria spedisce un client HTTP che implementa **tutte** le primitive\r\n * (`HttpDpeBuilderApi`), chi lo eredita non ha modo di *dis*-sovrascrivere un metodo. Si\r\n * ritroverebbe comandi attivi su endpoint che il suo backend non serve — esattamente il\r\n * difetto che la regola dell'identita' esisteva per prevenire.\r\n *\r\n * E' **solo sottrattiva**: non rende disponibile cio' che non e' implementato, e il tipo\r\n * `DpeOptionalPrimitive` le impedisce di nominare le tre primitive obbligatorie. Vuoto per\r\n * default, cosi' un'implementazione che non la tocca conserva esattamente il comportamento\r\n * di prima.\r\n *\r\n * Chi la usa deve anche rigettare la primitiva con `DpeApiError('MissingService', ...)`\r\n * **senza emettere la richiesta**: sapere in anticipo che un servizio non c'e' e chiederglielo\r\n * comunque e' il difetto che questa dichiarazione evita.\r\n */\r\n readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[] = [];\r\n\r\n /**\r\n * `IDpeService.Validate` — **non produce SQL e non legge dati** (`contracts.md` §5). E' la\r\n * primitiva del feedback durante l'editing: diagnostiche, schemi di ogni nodo, ordine di\r\n * esecuzione e sequenza dei writeback in una sola risposta.\r\n *\r\n * Prende la definizione **in lavorazione**, non quella salvata: cio' che l'editor mostra\r\n * deve riferirsi a cio' che l'utente sta scrivendo. Va invocata con debounce.\r\n */\r\n abstract validate(definition: DpeDefinition): Observable<DpeValidateResult>;\r\n\r\n /**\r\n * `IDpeService.GetTables` — passaggio diretto al provider di metadati dell'host, **non ai\r\n * cataloghi del database** (`contracts.md` §2). L'elenco puo' essere grande: chi lo consuma\r\n * carica in modo asincrono e filtra, non lo riversa in un `<select>`.\r\n */\r\n abstract getTables(): Observable<TableSummary[]>;\r\n\r\n /**\r\n * `IDpeService.GetTable` — i **tre** esiti dell'ADR 0004 restano distinti fino alla UI:\r\n * `Declared`, `DeclaredWithoutFields` (\"la tabella c'e', i campi non li so\") e `Unknown`.\r\n * Appiattirli e' esattamente cio' che il contratto vieta.\r\n */\r\n abstract getTable(tableName: string): Observable<TableLookupResult>;\r\n\r\n /**\r\n * `IDpeService.Compile` — l'anteprima dell'SQL generato, in sola lettura.\r\n *\r\n * Opzionale: senza di essa il comando di anteprima si disabilita e il resto dell'editor\r\n * continua a funzionare.\r\n *\r\n * `parameterValues` e' opzionale e corrisponde a `DpeCompileRequest.ParameterValues`.\r\n * Ometterlo e' un comportamento **dichiarato**, non un ripiego: l'anteprima usa allora i\r\n * `defaultValue` dei parametri. Passarli serve perche' senza di essi l'anteprima resterebbe\r\n * muta proprio sui parametri **privi** di default, cioe' quelli che l'utente vuole provare.\r\n */\r\n compilePreview(\r\n definition: DpeDefinition,\r\n parameterValues?: DpeParameterValue[],\r\n ): Observable<DpeCompileResult> {\r\n void definition;\r\n void parameterValues;\r\n return missing('compilePreview');\r\n }\r\n\r\n /**\r\n * Caricamento di una definizione per nome. Opzionale: dove non c'e', l'editor lavora sulla\r\n * definizione che gli viene passata dall'ospite.\r\n *\r\n * La deserializzazione (`IDpeService.Deserialize`) resta del backend: qui arriva un\r\n * documento già letto, con le sue eventuali diagnostiche già emesse.\r\n */\r\n load(name: string): Observable<DpeDefinition> {\r\n void name;\r\n return missing('load');\r\n }\r\n\r\n /** Salvataggio. Opzionale: un editor in sola lettura e' un uso legittimo. */\r\n save(definition: DpeDefinition): Observable<void> {\r\n void definition;\r\n return missing('save');\r\n }\r\n\r\n /**\r\n * La dichiarazione dell'ambiente (ADR 0017). Oggi porta **solo** il dialetto del database di\r\n * destinazione, che e' un fatto dell'installazione e non una preferenza dell'autore della\r\n * definizione: per questo l'editor non offre nessun comando per cambiarlo.\r\n *\r\n * Cosa l'editor fa con la risposta, e cosa non fa: mostra il dialetto in sola lettura e, se\r\n * differisce da quello della definizione (ADR 0009: e' li' che vive, ed e' da li' che il\r\n * backend lo legge), **lo segnala senza correggere**. Riscrivere `definition.dialect` sarebbe\r\n * una migrazione silenziosa di tutte le espressioni SQL native (ADR 0006), per giunta eseguita\r\n * all'apertura e capace di marcare come «modificata» una definizione che nessuno ha toccato.\r\n *\r\n * Opzionale come le altre: dove manca, l'editor mostra il dialetto della definizione e non\r\n * dice nient'altro.\r\n */\r\n getEnvironment(): Observable<DpeEnvironment> {\r\n return missing('getEnvironment');\r\n }\r\n\r\n /**\r\n * Elenco delle definizioni disponibili — **catalogo** (ADR 0019). Opzionale: dove manca, un\r\n * catalogo montato dall'ospite mostra il perche' invece di un elenco vuoto.\r\n *\r\n * **Nessun oggetto di interrogazione**, di proposito: niente ricerca, niente paginazione. Il\r\n * filtro di testo del catalogo e' locale sui sommari ricevuti, e aggiungere una query in\r\n * seguito e' additivo. Un parametro che nessuno esercita e' un parametro che nessuno verifica.\r\n *\r\n * L'ospite e' tenuto a restituire i sommari in un **ordine stabile**: il catalogo non riordina,\r\n * perche' riordinare lato client combatterebbe una scelta che l'ospite ha gia' fatto.\r\n */\r\n listDefinitions(): Observable<DpeDefinitionSummary[]> {\r\n return missing('listDefinitions');\r\n }\r\n\r\n /**\r\n * Creazione di una definizione. Opzionale.\r\n *\r\n * **Restituisce il sommario, non `void`**: l'ospite puo' aver normalizzato il nome, e chi crea\r\n * apre **il nome tornato**, non quello digitato. Il risultato di una scrittura non si crede\r\n * sulla parola.\r\n *\r\n * Distinta da `save` per una ragione di merito: `save(definition)` significa «scrivi questa\r\n * definizione» e non distingue inserimento da aggiornamento, quindi farle significare anche\r\n * «creala» toglierebbe all'ospite l'unico posto in cui puo' **rifiutare un nome duplicato**.\r\n *\r\n * Non esiste una primitiva di duplicazione: duplicare e' `load` piu' `createDefinition`, e il\r\n * comando vive nel catalogo.\r\n */\r\n createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary> {\r\n void definition;\r\n return missing('createDefinition');\r\n }\r\n\r\n /**\r\n * Cancellazione per nome. Opzionale: un catalogo di sola lettura e' un uso legittimo.\r\n *\r\n * Non esiste una primitiva di rinomina: rinominare cambia la chiave, quindi e'\r\n * creare-e-cancellare, cioe' una decisione di storage che e' dell'ospite (ADR 0019).\r\n */\r\n deleteDefinition(name: string): Observable<void> {\r\n void name;\r\n return missing('deleteDefinition');\r\n }\r\n}\r\n","/**\r\n * Implementazione HTTP di {@link DpeBuilderApi}, sulle rotte **normative** di\r\n * `docs/contracts.md` §7-bis.\r\n *\r\n * Vive nella libreria per decisione del committente (ADR 0020, che revisiona la sola clausola\r\n * dell'ADR 0007 sulla collocazione): l'integrazione e' due righe invece che un file da copiare.\r\n * Il prezzo, accettato e scritto: **le rotte sono contratto pubblico**, e cambiarne una e' un\r\n * breaking change. Da qui in poi questa classe non e' «un esempio» — una classe esportata da una\r\n * libreria viene usata in produzione a prescindere da come la chiamiamo nel commento, e chiamarla\r\n * esempio servirebbe solo a esentarla dai test.\r\n *\r\n * Resta vero cio' che conta dell'ADR 0007: **il contratto e' la classe astratta**, non questo\r\n * client. Nessun componente e nessuno store della libreria lo importa. Chi ha rotte diverse ha due\r\n * strade, e nessuna tocca l'editor:\r\n *\r\n * 1. **estendere questa classe** e sovrascrivere i soli metodi divergenti. I punti di estensione\r\n * sono `protected` di proposito: `url()` per il prefisso e la forma del percorso, `segment()`\r\n * per la codifica, i quattro verbi per il trasporto, `fail()` per la traduzione degli errori,\r\n * `request()` per cio' che avvolge ogni chiamata;\r\n * 2. **scrivere un'altra implementazione di `DpeBuilderApi` da zero** — legittima e supportata.\r\n *\r\n * Le tre cose che chi legge questo file deve sapere, e che nessun compilatore gli dira':\r\n *\r\n * 1. **il corpo e' il documento nudo** dove il backend analizza o archivia la definizione\r\n * (`validate`, `createDefinition`, `save`). L'unico involucro e' `compilePreview`, perche' li'\r\n * il corpo porta anche i valori dei parametri. Sbagliare involucro **non produce nessun\r\n * errore**: un backend che deserializza una `DpeDefinition` da `{definition: …}` non riconosce\r\n * nessuna proprieta', risponde `200`, e l'editor mostra la validazione di una definizione\r\n * vuota;\r\n * 2. **la serializzazione e' camelCase.** I tipi TypeScript sono allineati a mano ai record C#: un\r\n * backend che risponde in PascalCase non produce nessun errore, produce campi `undefined`;\r\n * 3. **l'errore di trasporto diventa una categoria.** L'editor si comporta in base alla categoria\r\n * e non legge mai il messaggio: `MissingService` disabilita un comando, `Transport` e'\r\n * ritentabile, `Backend` no.\r\n *\r\n * Cosa questo client **non** fa, e non per dimenticanza: nessun `retry`, nessun `shareReplay`,\r\n * nessuna cache, nessun debounce, nessuna intestazione propria. Traduce trasporto ed errori e\r\n * nient'altro — la cache vive negli store, il debounce nel chiamante, i tentativi e\r\n * l'autenticazione negli interceptor dell'ospite. E non tocca `definition.dialect` in nessun\r\n * metodo (ADR 0009 e 0017): sarebbe una migrazione silenziosa delle espressioni SQL native.\r\n */\r\n\r\nimport { HttpClient, HttpErrorResponse } from '@angular/common/http';\r\nimport {\r\n EnvironmentProviders,\r\n InjectionToken,\r\n Injectable,\r\n inject,\r\n makeEnvironmentProviders,\r\n} from '@angular/core';\r\nimport { Observable, catchError, defer, throwError } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from './dpe-builder-api';\r\nimport { DpeApiError, DpeApiErrorCategory } from './dpe-api-error';\r\nimport { DpeDefinition } from '../model/dpe-definition.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeDefinitionSummary,\r\n DpeEnvironment,\r\n DpeParameterValue,\r\n DpeValidateResult,\r\n TableLookupResult,\r\n TableSummary,\r\n} from '../model/dpe-api.model';\r\nimport type { DpeOptionalPrimitive } from '../core/dpe-capabilities';\r\n\r\n/**\r\n * Configurazione del client. Iniettata e non cablata: in una libreria una costante non e' una\r\n * scelta, e `const BASE = '/api/dpe'` in un file di libreria toglierebbe all'ospite la sua.\r\n */\r\nexport interface DpeBuilderHttpConfig {\r\n /** Prefisso comune degli endpoint, es. `/api/dpe` o `https://host/api/dpe`. Senza slash finale. */\r\n baseUrl?: string;\r\n /**\r\n * Primitive opzionali che questo ambiente **non serve** (`contracts.md` §7, dichiarazione\r\n * sottrattiva). E' l'unico modo che ha l'ospite di spegnere una primitiva che questo client\r\n * implementa per forza: conoscendo tutti e dieci gli endpoint, li dichiarerebbe altrimenti tutti\r\n * disponibili, e un comando attivo su un endpoint non servito fallisce alla pressione.\r\n */\r\n unsupported?: readonly DpeOptionalPrimitive[];\r\n}\r\n\r\n/** Base di default delle rotte, in un solo posto: token e funzione di registrazione la condividono. */\r\nconst DPE_BUILDER_DEFAULT_BASE_URL = '/api/dpe';\r\n\r\nexport const DPE_BUILDER_HTTP_CONFIG = new InjectionToken<DpeBuilderHttpConfig>(\r\n 'DPE_BUILDER_HTTP_CONFIG',\r\n { factory: () => ({ baseUrl: DPE_BUILDER_DEFAULT_BASE_URL }) },\r\n);\r\n\r\n@Injectable()\r\nexport class HttpDpeBuilderApi extends DpeBuilderApi {\r\n protected readonly http = inject(HttpClient);\r\n protected readonly config = inject(DPE_BUILDER_HTTP_CONFIG);\r\n\r\n /**\r\n * Deriva da `DpeBuilderHttpConfig.unsupported`: e' il ponte fra la configurazione e la regola\r\n * di `contracts.md` §7. Non e' un doppione della configurazione — e' il campo che\r\n * `core/dpe-capabilities.ts` legge, e leggerlo dal token li' significherebbe portare la\r\n * configurazione HTTP dentro il calcolo delle capacita'.\r\n */\r\n override readonly unsupportedPrimitives: readonly DpeOptionalPrimitive[] =\r\n this.config.unsupported ?? [];\r\n\r\n // --- punti di estensione ---------------------------------------------------\r\n\r\n /**\r\n * Composizione dell'URL. Sovrascriverlo basta a spostare tutte e dieci le rotte sotto un altro\r\n * prefisso senza toccare un metodo.\r\n *\r\n * `?? ''` e non un default: `baseUrl: ''` e' una configurazione **valida** e significa «rotte\r\n * relative alla radice», quindi non va rimpiazzata dal default del token. Il percorso porta\r\n * sempre lo slash iniziale, cosi' non nasce un doppio slash.\r\n */\r\n protected url(path: string): string {\r\n return `${this.config.baseUrl ?? ''}${path}`;\r\n }\r\n\r\n /** Codifica di un segmento variabile. Un nome di definizione puo' contenere `/`, spazi, `&`. */\r\n protected segment(value: string): string {\r\n return encodeURIComponent(value);\r\n }\r\n\r\n /**\r\n * Cio' che avvolge **ogni** chiamata, e l'unico posto in cui si decide se una chiamata parte.\r\n *\r\n * `defer` non e' un vezzo: rende l'`Observable` **freddo** anche per il controllo delle\r\n * primitive non servite, cosi' chi non sottoscrive non valuta nulla e chi si disiscrive annulla\r\n * davvero la richiesta HTTP. E' la proprieta' per cui il contratto §7 e' `Observable` e non\r\n * `Promise` — l'editor la usa per non accumulare validazioni in volo.\r\n *\r\n * Il rigetto per primitiva non servita sta **fuori** dal `catchError`: passandogli dentro, un\r\n * `DpeApiError('MissingService')` verrebbe riclassificato `Transport` da `fail()`, che tratta\r\n * come guasto di rete tutto cio' che non e' una `HttpErrorResponse`.\r\n */\r\n protected request<T>(primitive: DpeOptionalPrimitive | string, call: () => Observable<T>): Observable<T> {\r\n return defer(() => {\r\n if (this.isUnsupported(primitive)) {\r\n return this.missing(primitive);\r\n }\r\n return call().pipe(catchError((error: unknown) => this.fail(error, primitive)));\r\n });\r\n }\r\n\r\n /** Vero se l'ospite ha dichiarato di non servire questa primitiva. */\r\n protected isUnsupported(primitive: string): boolean {\r\n return (this.unsupportedPrimitives as readonly string[]).includes(primitive);\r\n }\r\n\r\n /**\r\n * Rigetto di una primitiva dichiarata non servita, **senza toccare la rete**: sapere in anticipo\r\n * che un servizio non c'e' e chiederglielo comunque e' il difetto che `unsupportedPrimitives`\r\n * esiste per evitare, ed e' il motivo per cui il `501` -> `MissingService` non basta da solo.\r\n */\r\n protected missing(primitive: string): Observable<never> {\r\n return throwError(\r\n () =>\r\n new DpeApiError(\r\n 'MissingService',\r\n `Primitiva non servita da questo ambiente: ${primitive}.`,\r\n ),\r\n );\r\n }\r\n\r\n /**\r\n * `501 Not Implemented` diventa `MissingService`: e' cosi' che un ambiente incompleto degrada\r\n * **un comando** invece di rompere l'editor. Uno `0` (rete assente, CORS) e' `Transport`, come\r\n * qualunque errore che non sia una `HttpErrorResponse`; tutto il resto e' `Backend`.\r\n *\r\n * Il `404` resta deliberatamente `Backend` e non ha un ramo suo: qui non e' «primitiva assente»\r\n * ma «risorsa assente» — una definizione cancellata da altri, un nome che non esiste piu'. Chi\r\n * volesse distinguerlo lo mappi su una categoria propria, non su `MissingService`: disabilitare\r\n * un comando perche' un singolo nome non e' stato trovato sarebbe la reazione sbagliata.\r\n *\r\n * Il messaggio si prende in ordine — corpo dell'errore, messaggio della risposta, ripiego che\r\n * nomina la primitiva — e serve solo all'umano: l'editor guarda la categoria.\r\n */\r\n protected fail(error: unknown, primitive: string): Observable<never> {\r\n const response = error instanceof HttpErrorResponse ? error : undefined;\r\n let category: DpeApiErrorCategory = 'Backend';\r\n if (response?.status === 501) {\r\n category = 'MissingService';\r\n } else if (!response || response.status === 0) {\r\n category = 'Transport';\r\n }\r\n const message =\r\n (response?.error as { message?: string } | undefined)?.message ??\r\n response?.message ??\r\n `Chiamata ${primitive} fallita.`;\r\n return throwError(() => new DpeApiError(category, message, error));\r\n }\r\n\r\n // --- verbi ----------------------------------------------------------------\r\n // Sovrascriverne uno cambia il trasporto di tutte le rotte che lo usano: e' il livello a cui\r\n // agisce chi deve aggiungere `withCredentials` o un `responseType` diverso.\r\n\r\n protected httpGet<T>(path: string): Observable<T> {\r\n return this.http.get<T>(this.url(path));\r\n }\r\n\r\n protected httpPost<T>(path: string, body: unknown): Observable<T> {\r\n return this.http.post<T>(this.url(path), body);\r\n }\r\n\r\n protected httpPut<T>(path: string, body: unknown): Observable<T> {\r\n return this.http.put<T>(this.url(path), body);\r\n }\r\n\r\n protected httpDelete<T>(path: string): Observable<T> {\r\n return this.http.delete<T>(this.url(path));\r\n }\r\n\r\n // --- primitive obbligatorie -----------------------------------------------\r\n\r\n override validate(definition: DpeDefinition): Observable<DpeValidateResult> {\r\n // Il documento va **nudo** nel body: e' la definizione in lavorazione, non un involucro.\r\n return this.request('validate', () =>\r\n this.httpPost<DpeValidateResult>('/validate', definition),\r\n );\r\n }\r\n\r\n override getTables(): Observable<TableSummary[]> {\r\n return this.request('getTables', () => this.httpGet<TableSummary[]>('/tables'));\r\n }\r\n\r\n override getTable(tableName: string): Observable<TableLookupResult> {\r\n return this.request('getTable', () =>\r\n this.httpGet<TableLookupResult>(`/tables/${this.segment(tableName)}`),\r\n );\r\n }\r\n\r\n // --- primitive opzionali --------------------------------------------------\r\n\r\n /** L'**unica** rotta con involucro: il corpo porta anche i valori dei parametri (§7-bis). */\r\n override compilePreview(\r\n definition: DpeDefinition,\r\n parameterValues?: DpeParameterValue[],\r\n ): Observable<DpeCompileResult> {\r\n return this.request('compilePreview', () =>\r\n this.httpPost<DpeCompileResult>('/compile', { definition, parameterValues }),\r\n );\r\n }\r\n\r\n override load(name: string): Observable<DpeDefinition> {\r\n return this.request('load', () =>\r\n this.httpGet<DpeDefinition>(`/definitions/${this.segment(name)}`),\r\n );\r\n }\r\n\r\n override save(definition: DpeDefinition): Observable<void> {\r\n return this.request('save', () =>\r\n this.httpPut<void>(`/definitions/${this.segment(definition.name)}`, definition),\r\n );\r\n }\r\n\r\n /**\r\n * La dichiarazione dell'ambiente (ADR 0017). Questo client la implementa perche' conosce\r\n * l'endpoint, non perche' sappia se l'ospite lo serve — ed e' precisamente la ragione per cui\r\n * l'ADR 0020 ha aggiunto `unsupportedPrimitives`.\r\n *\r\n * Non e' un dettaglio: l'abilitazione della creazione nel catalogo (ADR 0019) dipende da questa\r\n * primitiva, quindi un ambiente che non la serve deve lasciare il comando disabilitato **con il\r\n * motivo**. Da qui i **tre** rami, che sono tre cose diverse e vanno tenute distinte:\r\n *\r\n * - **primitiva non implementata**: il metodo non viene sovrascritto, e il `MissingService` lo\r\n * produce l'identita' stessa del metodo. E' la strada di chi scrive la propria\r\n * implementazione di `DpeBuilderApi`, non di chi eredita questo client;\r\n * - **primitiva implementata ma non servita da questo ambiente**: e' il ramo centrale, quello\r\n * che questo file rende necessario. L'ospite mette `'getEnvironment'` in\r\n * `DpeBuilderHttpConfig.unsupported`, il comando resta disabilitato con il motivo, e **nessuna\r\n * richiesta parte**. Un metodo ereditato non si puo' dis-sovrascrivere: senza questa\r\n * dichiarazione il comando risulterebbe attivo;\r\n * - **primitiva servita che fallisce**: l'endpoint risponde male, e l'errore e' `Transport` o\r\n * `Backend`. Un ambiente rotto, non un ambiente incompleto.\r\n *\r\n * Rispondere `501` da questo endpoint per significare «non lo dichiaro» arriva allo stesso posto\r\n * nel modo sbagliato: costa un giro di rete a ogni apertura dell'editor per comunicare un fatto\r\n * che si conosce a tempo di configurazione.\r\n *\r\n * Cio' che l'editor fa della risposta resta suo: mostra il dialetto in sola lettura e segnala\r\n * senza correggere se differisce da quello della definizione.\r\n */\r\n override getEnvironment(): Observable<DpeEnvironment> {\r\n return this.request('getEnvironment', () => this.httpGet<DpeEnvironment>('/environment'));\r\n }\r\n\r\n // --- catalogo (ADR 0019) --------------------------------------------------\r\n\r\n /** Nessun parametro di interrogazione: il filtro del catalogo e' locale, di proposito. */\r\n override listDefinitions(): Observable<DpeDefinitionSummary[]> {\r\n return this.request('listDefinitions', () =>\r\n this.httpGet<DpeDefinitionSummary[]>('/definitions'),\r\n );\r\n }\r\n\r\n /**\r\n * `POST` e non `PUT`: e' una **creazione**, quindi il backend puo' rifiutare un nome duplicato —\r\n * ed e' l'unica ragione per cui questa primitiva esiste separata da `save`. La risposta e' il\r\n * **sommario**, che chi crea deve adottare: il nome puo' essere stato normalizzato.\r\n */\r\n override createDefinition(definition: DpeDefinition): Observable<DpeDefinitionSummary> {\r\n return this.request('createDefinition', () =>\r\n this.httpPost<DpeDefinitionSummary>('/definitions', definition),\r\n );\r\n }\r\n\r\n override deleteDefinition(name: string): Observable<void> {\r\n return this.request('deleteDefinition', () =>\r\n this.httpDelete<void>(`/definitions/${this.segment(name)}`),\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Registra il client e la sua configurazione: l'integrazione in una riga che l'ADR 0020 chiedeva.\r\n *\r\n * **Non** chiama `provideHttpClient()`, e non e' una dimenticanza: il backend (`withFetch`), gli\r\n * interceptor, l'autenticazione e i cookie sono scelte dell'applicazione ospite, e una libreria\r\n * che le prende al posto suo la costringe a disfarle.\r\n *\r\n * `baseUrl` omesso ricade sul default, `baseUrl: ''` **no**: la stringa vuota e' una\r\n * configurazione valida («rotte relative alla radice») e un `||` la scambierebbe per assente.\r\n */\r\nexport function provideDpeBuilderHttpApi(config?: DpeBuilderHttpConfig): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n {\r\n provide: DPE_BUILDER_HTTP_CONFIG,\r\n useValue: {\r\n baseUrl: config?.baseUrl ?? DPE_BUILDER_DEFAULT_BASE_URL,\r\n unsupported: config?.unsupported ?? [],\r\n } satisfies DpeBuilderHttpConfig,\r\n },\r\n { provide: DpeBuilderApi, useClass: HttpDpeBuilderApi },\r\n ]);\r\n}\r\n","/**\r\n * Modello della definizione DPE — traduzione **letterale** dei record C# di\r\n * `docs/domain-model.md`.\r\n *\r\n * Questi tipi sono allineati **a mano** ai record di `Jace.DPE.Model` (ADR 0007: nessun\r\n * generatore di tipi, nessuno JSON Schema). Sono due modelli in due linguaggi e il\r\n * compilatore non dira' mai quando divergono: la fonte di verita' e' `docs/contracts.md` +\r\n * `docs/domain-model.md`, e chi cambia un record C# aggiorna questo file nello stesso\r\n * momento.\r\n *\r\n * Convenzioni, tutte conseguenza del contratto:\r\n *\r\n * - proprieta' in **camelCase**, perche' il JSON prodotto dal backend e' camelCase\r\n * (`domain-model.md`, convenzioni generali);\r\n * - gli enum C# diventano **unioni di stringhe letterali** con i nomi esatti dei valori: un\r\n * `enum` TypeScript non e' assegnabile da una stringa arrivata dalla rete, e un valore\r\n * numerico non e' cio' che il backend serializza;\r\n * - le collezioni nel backend non sono mai nulle, ma il JSON le **omette quando vuote**\r\n * (ADR 0003): qui sono opzionali e chi legge non presume che esistano;\r\n * - `extensionData` esiste su **ogni** record (**I7**): sono proprieta' JSON non riconosciute,\r\n * con valori **opachi**. L'editor le trasporta senza interpretarle.\r\n *\r\n * Nessuna regola di dominio vive qui: obbligatorieta' condizionali, unicita' dei nomi e\r\n * compatibilita' dei tipi sono del backend. Le note `condiz.` nei commenti sono descrittive\r\n * e servono a chi costruira' gli ispettori, non sono validazione.\r\n */\r\n\r\n/** Proprieta' JSON non riconosciute, conservate verbatim (**I7**). Valori opachi. */\r\nexport type DpeExtensionData = Record<string, unknown>;\r\n\r\n/** Base di ogni record del modello: `ExtensionData` sta su tutti, non solo sulla radice. */\r\nexport interface DpeExtensible {\r\n extensionData?: DpeExtensionData;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 1. Elementi trasversali\r\n// ---------------------------------------------------------------------------\r\n\r\n/** I sei tipi logici, nessun altro valore mai (ADR 0002). */\r\nexport type LogicalType = 'String' | 'Number' | 'Integer' | 'DateTime' | 'Boolean' | 'Enum';\r\n\r\nexport interface ColumnType extends DpeExtensible {\r\n kind: LogicalType;\r\n /** Condiz.: richiesto per `String` nei campi dichiarati. */\r\n length?: number;\r\n /** Solo `Number`. */\r\n precision?: number;\r\n /** Condiz.: richiesto per `Number` nei campi dichiarati. */\r\n scale?: number;\r\n /** Condiz.: non vuoto quando `kind === 'Enum'`. */\r\n allowedValues?: string[];\r\n}\r\n\r\nexport type SortDirection = 'Ascending' | 'Descending';\r\n\r\nexport interface OrderByField extends DpeExtensible {\r\n /** Alias della colonna a monte. */\r\n columnName: string;\r\n /** Default `Ascending`. */\r\n direction?: SortDirection;\r\n}\r\n\r\nexport type AggregateFunction =\r\n | 'Count'\r\n | 'CountDistinct'\r\n | 'Sum'\r\n | 'Min'\r\n | 'Max'\r\n | 'Avg'\r\n | 'StdDev'\r\n | 'StdDevPop'\r\n | 'Variance'\r\n | 'VariancePop';\r\n\r\n/** Base di tutti i nodi. `name` e' univoco nell'intera definizione (**I1**). */\r\nexport interface DpeNode extends DpeExtensible {\r\n name: string;\r\n label: string;\r\n description?: string;\r\n}\r\n\r\n/**\r\n * I riferimenti a un nodo a monte sono dichiarati **opzionali** anche dove\r\n * `domain-model.md` li marca obbligatori, e non e' un ammorbidimento del contratto: e' cio'\r\n * che il contratto dice. In C# sono `string` con default `null`, l'obbligatorieta' e'\r\n * verificata dalla validazione e \"un modello incompleto e' un fatto normale (l'editor ne\r\n * produce uno a ogni tasto)\". Un nodo appena creato o appena scollegato **non ha** una\r\n * sorgente: rappresentarla con la stringa vuota sarebbe un valore magico che il backend\r\n * legge diversamente da un'assenza.\r\n */\r\n\r\n\r\n// ---------------------------------------------------------------------------\r\n// 2. Radice\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type SqlDialectKind = 'Sqlite' | 'SqlServer' | 'PostgreSql' | 'Oracle';\r\nexport type DefinitionStatus = 'Active' | 'Inactive';\r\nexport type DefinitionRunMode = 'Batch' | 'OnDemand';\r\n\r\nexport interface DpeDefinition extends DpeExtensible {\r\n /** Default `1`, sempre serializzato per primo. */\r\n formatVersion: number;\r\n name: string;\r\n label: string;\r\n description?: string;\r\n /** Il dialetto e' **parte della definizione** (ADR 0009): cambiarlo e' una migrazione. */\r\n dialect: SqlDialectKind;\r\n /** Default `Inactive`. */\r\n status?: DefinitionStatus;\r\n /** Default `Batch`. */\r\n runMode?: DefinitionRunMode;\r\n /** Default `false`. */\r\n isTemplate?: boolean;\r\n parameters?: DpeParameter[];\r\n /** Obbligatoria (>=1) in una definizione valida; assente in una in lavorazione. */\r\n dataSources?: DataSourceNode[];\r\n filters?: FilterNode[];\r\n joins?: JoinNode[];\r\n aggregates?: AggregateNode[];\r\n transforms?: TransformNode[];\r\n appends?: AppendNode[];\r\n hierarchyPaths?: HierarchyPathNode[];\r\n /** Modellati, non compilabili in v1 (`DPE_NODE_NOT_COMPILABLE`). */\r\n forecasts?: ForecastNode[];\r\n /** Modellati, non compilabili in v1. */\r\n customNodes?: CustomNode[];\r\n /** Obbligatoria (>=1) in una definizione valida. */\r\n writebacks?: WritebackNode[];\r\n atomicWritebacks?: AtomicWritebackNode[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 3. Parametri\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type ParameterRole = 'Value' | 'Filter' | 'Expression';\r\n\r\nexport interface DpeParameter extends DpeExtensible {\r\n name: string;\r\n label: string;\r\n description?: string;\r\n role: ParameterRole;\r\n /** Condiz.: richiesto quando `role === 'Value'`. */\r\n valueType?: ColumnType;\r\n /** Testo, interpretato secondo `valueType`, cultura invariante. */\r\n defaultValue?: string;\r\n /** Default `false`; ammesso solo per `role === 'Value'`. */\r\n isMultiValue?: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 4. Nodi sorgente\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type DataSourceKind = 'Table' | 'Csv' | 'ExternalDataset';\r\nexport type CsvDelimiter = 'Comma' | 'Semicolon' | 'Tab' | 'Pipe' | 'Caret' | 'Backquote';\r\n\r\nexport interface CsvSourceOptions extends DpeExtensible {\r\n /** Default `Comma`. */\r\n delimiter?: CsvDelimiter;\r\n /** Default `true`. */\r\n hasHeaderRow?: boolean;\r\n /** Identificatore opaco risolto dall'host. */\r\n location: string;\r\n}\r\n\r\nexport interface DataSourceField extends DpeExtensible {\r\n /** Nome del campo nella tabella/file di origine. */\r\n name: string;\r\n /** Quando assente l'alias **e'** `name`: la normalizzazione e' del backend. */\r\n alias?: string;\r\n /** Condiz.: richiesto per `Csv`/`ExternalDataset`; per `Table` **ignorato**. */\r\n declaredType?: ColumnType;\r\n /** Default `false`. */\r\n isPrimaryKey?: boolean;\r\n}\r\n\r\nexport interface DataSourceNode extends DpeNode {\r\n kind: DataSourceKind;\r\n /** Condiz.: richiesto per `kind === 'Table'`; nome noto al provider di metadati. */\r\n tableName?: string;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: DataSourceField[];\r\n /** Condiz.: richiesto per `kind === 'Csv'`. */\r\n csvOptions?: CsvSourceOptions;\r\n /** Condiz.: richiesto per `kind === 'ExternalDataset'`. */\r\n externalDatasetName?: string;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 5. Nodi di trasformazione\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type FilterOperator =\r\n | 'Equals'\r\n | 'NotEquals'\r\n | 'GreaterThan'\r\n | 'GreaterThanOrEqual'\r\n | 'LessThan'\r\n | 'LessThanOrEqual'\r\n | 'StartsWith'\r\n | 'EndsWith'\r\n | 'Contains'\r\n | 'DoesNotContain'\r\n | 'IsNull'\r\n | 'IsNotNull'\r\n | 'In'\r\n | 'NotIn';\r\n\r\nexport interface FilterCriterion extends DpeExtensible {\r\n /** >=1, univoco nel nodo, referenziato da `condition`. */\r\n sequence: number;\r\n /** Alias a monte. */\r\n sourceFieldName: string;\r\n operator: FilterOperator;\r\n /** Condiz.: richiesto salvo `IsNull`/`IsNotNull` e salvo `inputVariable` presente. */\r\n value?: string;\r\n /** Nome di un `DpeParameter` con `role === 'Value'`; esclusivo con `value`. */\r\n inputVariable?: string;\r\n}\r\n\r\nexport interface FilterNode extends DpeNode {\r\n sourceName?: string;\r\n /** Default `false`. */\r\n isDynamic?: boolean;\r\n /** Condiz.: richiesto (>=1) quando `isDynamic` e' falso. */\r\n criteria?: FilterCriterion[];\r\n /**\r\n * Condiz.: richiesto quando `isDynamic` e' falso. Combinazione booleana dei `sequence`\r\n * dei criteri (`1 AND (2 OR 3)`), **non** un'espressione SQL: e' l'unico linguaggio che il\r\n * backend parsifica davvero.\r\n */\r\n condition?: string;\r\n /** Condiz.: richiesto quando `isDynamic`; riferisce un parametro con `role === 'Filter'`. */\r\n filterParameterName?: string;\r\n}\r\n\r\nexport type JoinKind = 'Inner' | 'LeftOuter' | 'RightOuter' | 'FullOuter' | 'Lookup';\r\n\r\nexport interface JoinKey extends DpeExtensible {\r\n primaryFieldName: string;\r\n secondaryFieldName: string;\r\n}\r\n\r\nexport interface JoinResultField extends DpeExtensible {\r\n /** Deve essere `primarySourceName` o `secondarySourceName` del nodo. */\r\n sourceName: string;\r\n sourceFieldName: string;\r\n /** Univoco nel nodo (**I1**). */\r\n alias: string;\r\n}\r\n\r\nexport interface JoinNode extends DpeNode {\r\n primarySourceName?: string;\r\n secondarySourceName?: string;\r\n kind: JoinKind;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n keys?: JoinKey[];\r\n /** Lo schema di output e' **esplicito**: solo questi campi. */\r\n fields?: JoinResultField[];\r\n /** Default `false`; significativo solo per `kind === 'Lookup'`. */\r\n allowsMultipleLookupValues?: boolean;\r\n}\r\n\r\nexport interface AggregateField extends DpeExtensible {\r\n /** Alias a monte; assente **solo** per `Count` (conteggio righe). */\r\n sourceFieldName?: string;\r\n function: AggregateFunction;\r\n alias: string;\r\n}\r\n\r\nexport interface AggregateNode extends DpeNode {\r\n sourceName?: string;\r\n /** Alias a monte; vuoto = aggregazione globale su una riga. */\r\n groupBy?: string[];\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: AggregateField[];\r\n}\r\n\r\nexport type TransformKind = 'Expression' | 'Slice' | 'ComputeRelative';\r\n\r\nexport interface ExpressionField extends DpeExtensible {\r\n alias: string;\r\n /** **SQL nativo del dialetto della definizione** (ADR 0006): passa verbatim. */\r\n expression: string;\r\n /** **Autorevole e non verificato** (ADR 0006). */\r\n declaredType: ColumnType;\r\n}\r\n\r\nexport interface TransformNode extends DpeNode {\r\n sourceName?: string;\r\n kind: TransformKind;\r\n /** Condiz.: richiesto (>=1) per `Expression`/`ComputeRelative`, vuoto per `Slice`. */\r\n expressionFields?: ExpressionField[];\r\n /** Condiz.: richiesto (>=1) per `Slice`, vuoto altrimenti. */\r\n droppedFields?: string[];\r\n /** Solo `ComputeRelative`. */\r\n partitionBy?: string[];\r\n /** Solo `ComputeRelative`. */\r\n orderBy?: OrderByField[];\r\n}\r\n\r\nexport interface AppendNode extends DpeNode {\r\n /** Obbligatorio (>=2) in un nodo valido. */\r\n sources?: string[];\r\n /** Default `false`. */\r\n allowsDisjointSchema?: boolean;\r\n}\r\n\r\nexport interface HierarchyPathNode extends DpeNode {\r\n sourceName?: string;\r\n /** Chiave del nodo corrente. */\r\n selfFieldName?: string;\r\n /** Riferimento al padre. */\r\n parentFieldName?: string;\r\n /** Alias della colonna di percorso prodotta (`String`). */\r\n pathFieldName?: string;\r\n /** Default `true`. */\r\n includesSelfValue?: boolean;\r\n /** Condiz.: richiesto (>=1) quando `isAggregationRequired`. */\r\n aggregateFields?: AggregateField[];\r\n /** Default `false`. */\r\n isAggregationRequired?: boolean;\r\n rollupPercentageFieldName?: string;\r\n}\r\n\r\nexport type ForecastPeriodType =\r\n | 'Year'\r\n | 'YearQuarter'\r\n | 'YearMonth'\r\n | 'YearWeek'\r\n | 'YearMonthDay'\r\n | 'FiscalYear'\r\n | 'FiscalYearQuarter'\r\n | 'FiscalYearMonth'\r\n | 'FiscalYearWeek';\r\n\r\nexport type ForecastModelType = 'Auto' | 'Additive' | 'Multiplicative';\r\nexport type ForecastAccuracy = 'None' | 'Eighty' | 'NinetyFive';\r\n\r\nexport type DatePart =\r\n | 'Second'\r\n | 'Minute'\r\n | 'Hour'\r\n | 'Day'\r\n | 'Week'\r\n | 'Month'\r\n | 'Quarter'\r\n | 'Year';\r\n\r\nexport interface ForecastAggregationField extends DpeExtensible {\r\n fieldName: string;\r\n function: AggregateFunction;\r\n resultAlias: string;\r\n}\r\n\r\nexport interface ForecastGroupField extends DpeExtensible {\r\n fieldName: string;\r\n /** Condiz.: richiesto quando il campo e' `DateTime`. */\r\n datePart?: DatePart;\r\n}\r\n\r\n/** Modellato per intero, **non compilabile in v1** (`DPE_NODE_NOT_COMPILABLE`). */\r\nexport interface ForecastNode extends DpeNode {\r\n sourceName?: string;\r\n dateFieldName?: string;\r\n periodType?: ForecastPeriodType;\r\n /** Default `1`, ammesso 1..100. */\r\n periodCount?: number;\r\n /** Alias della colonna di inizio periodo prodotta. */\r\n periodStartFieldName?: string;\r\n /** Default `Auto`. */\r\n modelType?: ForecastModelType;\r\n /** `null`/assente = automatica; ammesso 2..24. */\r\n seasonality?: number;\r\n /** Default `None`. */\r\n accuracyPercent?: ForecastAccuracy;\r\n /** Default `false`. */\r\n excludesLastPeriod?: boolean;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n aggregationFields?: ForecastAggregationField[];\r\n groupFields?: ForecastGroupField[];\r\n}\r\n\r\n/** Usato dove uno schema si **dichiara** invece di derivarlo. */\r\nexport interface DeclaredField extends DpeExtensible {\r\n name: string;\r\n type: ColumnType;\r\n}\r\n\r\nexport interface CustomNodeParameter extends DpeExtensible {\r\n name: string;\r\n value: string;\r\n}\r\n\r\n/** Modellato per intero, **non compilabile in v1**. */\r\nexport interface CustomNode extends DpeNode {\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n sources?: string[];\r\n extensionName: string;\r\n extensionNamespace?: string;\r\n parameters?: CustomNodeParameter[];\r\n /**\r\n * Obbligatorio (>=1): senza schema dichiarato la propagazione (**I4**) si interrompe e\r\n * tutto cio' che sta a valle diventa invalidabile.\r\n */\r\n outputFields?: DeclaredField[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 6. Nodi sink\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type WritebackTargetKind = 'Database' | 'Json' | 'Csv';\r\nexport type WritebackOperation = 'Insert' | 'Update' | 'Upsert' | 'Delete';\r\nexport type WritebackFieldRole = 'Value' | 'PrimaryKey' | 'QualifierKey';\r\n\r\nexport interface WritebackFieldMapping extends DpeExtensible {\r\n /** Condiz.: alias a monte; assente quando `runtimeParameterName` e' presente. */\r\n sourceFieldName?: string;\r\n targetFieldName: string;\r\n /** Il valore viene da un parametro, non dalla riga; esclusivo con `sourceFieldName`. */\r\n runtimeParameterName?: string;\r\n /** Default `Value`. */\r\n role?: WritebackFieldRole;\r\n relationshipName?: string;\r\n /** Condiz.: richiesto quando `relationshipName` e' presente. */\r\n parentName?: string;\r\n /** Default `false`; se `true`, `sourceFieldName` non e' richiesto. */\r\n isAutoGenerated?: boolean;\r\n}\r\n\r\n/**\r\n * Opzioni dell'artefatto JSON (`contracts.md` §2, «Opzioni degli artefatti»). Sono **solo**\r\n * scelte di formato, mai di destinazione (ADR 0010).\r\n */\r\nexport interface JsonArtifactOptions extends DpeExtensible {\r\n /** Default `false`: JSON compatto, array di oggetti. */\r\n indented?: boolean;\r\n}\r\n\r\n/**\r\n * Opzioni dell'artefatto CSV. Il quoting **non e' configurabile** di proposito: si quota\r\n * quando serve e si raddoppiano le virgolette, perche' un quoting opzionale produce file che\r\n * qualcuno non riesce a rileggere.\r\n */\r\nexport interface CsvArtifactOptions extends DpeExtensible {\r\n /** Default `Comma`. */\r\n delimiter?: CsvDelimiter;\r\n /** Default `true`. */\r\n includesHeaderRow?: boolean;\r\n}\r\n\r\nexport interface WritebackNode extends DpeNode {\r\n sourceName?: string;\r\n /** **Determina l'artefatto prodotto**. */\r\n target: WritebackTargetKind;\r\n /** >=1, univoco fra tutti i writeback e gli atomic writeback. */\r\n sequence: number;\r\n /** Condiz.: richiesto per `target === 'Database'`. */\r\n tableName?: string;\r\n /** Condiz.: richiesto per `target === 'Database'`; assente per `Json`/`Csv`. */\r\n operation?: WritebackOperation;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n fields?: WritebackFieldMapping[];\r\n /** Espressione SQL nativa applicata al risultato (ADR 0006). */\r\n filterCondition?: string;\r\n /** Condiz.: richiesto per `operation === 'Upsert'`. */\r\n externalIdFieldName?: string;\r\n /** Default `false`. */\r\n onlyChangedRows?: boolean;\r\n /** Solo `target === 'Json'`. */\r\n jsonOptions?: JsonArtifactOptions;\r\n /** Solo `target === 'Csv'`. */\r\n csvOptions?: CsvArtifactOptions;\r\n}\r\n\r\nexport interface AtomicWritebackRelationship extends DpeExtensible {\r\n /** Nome di un `WritebackNode` con `target === 'Database'`. */\r\n parentWritebackName?: string;\r\n parentFieldName?: string;\r\n childWritebackName?: string;\r\n childFieldName?: string;\r\n relationshipName?: string;\r\n /** Ordine dentro il gruppo atomico. */\r\n sequence: number;\r\n}\r\n\r\nexport interface AtomicWritebackNode extends DpeNode {\r\n /** Nello stesso spazio di numerazione dei `WritebackNode`. */\r\n sequence: number;\r\n /** Obbligatorio (>=1) in un nodo valido. */\r\n relationships?: AtomicWritebackRelationship[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Collezioni di nodi: la mappa nome-collezione -> tipo di nodo\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Le collezioni di nodi della radice, con il tipo che ciascuna contiene.\r\n *\r\n * Esiste perche' ogni utility che cammina il documento (derivazione degli archi, rinomina,\r\n * catalogo della palette) deve nominare le collezioni **una volta sola**: una collezione\r\n * dimenticata in uno dei tre posti non produce nessun errore, produce un arco che non\r\n * compare o un riferimento che resta rotto dopo una rinomina.\r\n */\r\nexport interface DpeNodeCollectionMap {\r\n dataSources: DataSourceNode;\r\n filters: FilterNode;\r\n joins: JoinNode;\r\n aggregates: AggregateNode;\r\n transforms: TransformNode;\r\n appends: AppendNode;\r\n hierarchyPaths: HierarchyPathNode;\r\n forecasts: ForecastNode;\r\n customNodes: CustomNode;\r\n writebacks: WritebackNode;\r\n atomicWritebacks: AtomicWritebackNode;\r\n}\r\n\r\nexport type DpeNodeCollectionName = keyof DpeNodeCollectionMap;\r\n\r\n/** Qualunque nodo della definizione. */\r\nexport type DpeAnyNode = DpeNodeCollectionMap[DpeNodeCollectionName];\r\n\r\n/**\r\n * L'elenco dei nomi di collezione in forma di valore, nell'ordine in cui i nodi si leggono\r\n * (sorgenti -> trasformazioni -> sink). `keyof` non produce un array a runtime: questo\r\n * elenco e' l'unico posto in cui vive l'ordine.\r\n */\r\nexport const DPE_NODE_COLLECTIONS: readonly DpeNodeCollectionName[] = [\r\n 'dataSources',\r\n 'filters',\r\n 'joins',\r\n 'aggregates',\r\n 'transforms',\r\n 'appends',\r\n 'hierarchyPaths',\r\n 'forecasts',\r\n 'customNodes',\r\n 'writebacks',\r\n 'atomicWritebacks',\r\n];\r\n","/**\r\n * Diagnostiche — traduzione letterale di `Jace.DPE.Diagnostics` (`docs/contracts.md` §1).\r\n *\r\n * Tipi allineati **a mano** ai record C# (ADR 0007). L'editor **consuma** queste\r\n * diagnostiche e non ne produce: nessuna regola di dominio vive nel frontend, quindi in\r\n * questo file non ci sono ne' codici inventati ne' messaggi ricomposti. Il `message` arriva\r\n * dal backend, che e' l'unico posto in cui un messaggio viene composto.\r\n */\r\n\r\nexport type DiagnosticSeverity = 'Info' | 'Warning' | 'Error';\r\n\r\nexport interface DiagnosticPathSegment {\r\n /** `\"filters\"`, `\"criteria\"`, `\"fields\"`, ... */\r\n collection?: string;\r\n /** Nome del nodo/alias, se applicabile. */\r\n name?: string;\r\n /** Indice nella collezione, se applicabile. */\r\n index?: number;\r\n}\r\n\r\n/**\r\n * Percorso strutturato del rilievo.\r\n *\r\n * **Due forme, entrambe da gestire** (`contracts.md` §1, limite dichiarato): in\r\n * deserializzazione i nomi dei nodi non sono ancora noti e i segmenti portano solo l'indice\r\n * (`filters[0].sourceName`); dalla validazione portano il nome (`filters/OnlyActive`). Chi\r\n * naviga fino al campo deve accettare tutt'e due, altrimenti le diagnostiche del caricamento\r\n * di un file non sono cliccabili.\r\n */\r\nexport interface DiagnosticPath {\r\n segments?: DiagnosticPathSegment[];\r\n /** Nome della proprieta' in causa, camelCase. */\r\n field?: string;\r\n}\r\n\r\n/**\r\n * `arguments` e' un dizionario di stringhe con **chiavi canoniche** (`contracts.md` §1):\r\n * `node`, `field`, `column`, `alias`, `name`, `table`, `parameter`, `dialect`, `construct`,\r\n * `expected`, `actual`, `value`, `sequence`, `condition`, `token`, `truncated`. L'editor le\r\n * legge per costruire etichette, non per riscrivere il messaggio.\r\n */\r\nexport interface Diagnostic {\r\n /** `DiagnosticCodes.*` del backend. Il frontend non ne dichiara l'elenco: e' del backend. */\r\n code: string;\r\n severity: DiagnosticSeverity;\r\n path?: DiagnosticPath;\r\n arguments?: Record<string, string>;\r\n /** Derivato da `code` + `arguments`, cultura invariante. */\r\n message: string;\r\n}\r\n\r\n/**\r\n * L'unico codice che significa \"hai fatto bene, siamo noi\": nodo valido ma non ancora\r\n * compilabile (`Forecast`, `CustomNode`, costrutto non supportato — **I10**). Va distinto\r\n * visivamente dai `DPE_MODEL_*`, che invece l'utente deve correggere.\r\n *\r\n * E' l'unica costante di codice diagnostico che la libreria dichiara, e non e' una\r\n * duplicazione del dominio: e' la sola distinzione che cambia **come si rende** un rilievo.\r\n */\r\nexport const DPE_NODE_NOT_COMPILABLE = 'DPE_NODE_NOT_COMPILABLE';\r\n\r\n/** Rappresentazione testuale del percorso, nella forma usata dai messaggi del backend. */\r\nexport function diagnosticPathToString(path: DiagnosticPath | undefined): string {\r\n if (!path) {\r\n return '';\r\n }\r\n const segments = path.segments ?? [];\r\n let text = '';\r\n for (const segment of segments) {\r\n if (segment.collection) {\r\n text += text.length > 0 ? `/${segment.collection}` : segment.collection;\r\n }\r\n if (segment.name) {\r\n text += `/${segment.name}`;\r\n } else if (segment.index !== undefined) {\r\n text += `[${segment.index}]`;\r\n }\r\n }\r\n if (path.field) {\r\n text += text.length > 0 ? `.${path.field}` : path.field;\r\n }\r\n return text;\r\n}\r\n","/**\r\n * Tipi di richiesta/risposta del service DPE — traduzione letterale di `docs/contracts.md`\r\n * §2 (provider di metadati), §3 (SQL emesso) e §5 (il service).\r\n *\r\n * Allineati **a mano** ai record C# (ADR 0007). Cio' che non e' trasportabile non c'e':\r\n * `DpeContext` porta i provider dell'host (`ITableMetadataProvider`, `IDataQueryProvider`,\r\n * `IArtifactSink`, `ILogger`, `IClock`) e vive **dentro** il backend, quindi non ha un\r\n * corrispettivo TypeScript. Lo stesso vale per `Execute`: l'editor non esegue, non\r\n * materializza artefatti e non ha bisogno di `DpeExecuteResult`.\r\n */\r\n\r\nimport {\r\n ColumnType,\r\n DefinitionRunMode,\r\n DefinitionStatus,\r\n LogicalType,\r\n SqlDialectKind,\r\n WritebackFieldRole,\r\n WritebackOperation,\r\n WritebackTargetKind,\r\n} from './dpe-definition.model';\r\nimport { Diagnostic } from './dpe-diagnostics.model';\r\n\r\n// ---------------------------------------------------------------------------\r\n// §7 La dichiarazione dell'ambiente (ADR 0017)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Cio' che l'ambiente ospite **dichiara** all'editor. Non e' un tipo del backend C#: `IDpeService`\r\n * non cambia (ADR 0017), e l'host lo compone con cio' che gia' sa della propria installazione.\r\n *\r\n * Nasce con un solo campo e si estende **per aggiunta**: e' il posto previsto per i fatti\r\n * dell'ambiente, non un contenitore da riempire in anticipo.\r\n */\r\nexport interface DpeEnvironment {\r\n /** Il dialetto del database di destinazione. Dichiarato, mai scelto dall'utente dell'editor. */\r\n readonly dialect: SqlDialectKind;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §7 Catalogo delle definizioni (ADR 0019)\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Riga di catalogo: identita' e fatti che l'ospite conosce **senza** caricare la definizione.\r\n *\r\n * Distinto da `DpeDefinition` per costruzione, e non per comodita': elencare non deve costare N\r\n * caricamenti completi. Non ha un corrispettivo in `IDpeService` e non deve averlo — il service\r\n * valida, compila ed esegue; dove le definizioni vivano e' dell'ospite (ADR 0007), che non ha\r\n * ne' orologio ne' archiviazione lato libreria.\r\n *\r\n * I quattro campi in coda sono facoltativi in senso pieno: assenti, la riga **non li mostra e\r\n * non li stima**. Contare i nodi lato client vorrebbe dire caricare tutte le definizioni per\r\n * disegnare un elenco, e dedurre `updatedAt` e' impossibile.\r\n */\r\nexport interface DpeDefinitionSummary {\r\n /** La chiave. Non esiste un id distinto dal nome (ADR 0019): rinominare e' cambiare chiave. */\r\n name: string;\r\n label: string;\r\n description?: string;\r\n dialect: SqlDialectKind;\r\n status?: DefinitionStatus;\r\n runMode?: DefinitionRunMode;\r\n isTemplate?: boolean;\r\n /** ISO 8601. Lo scrive l'ospite: la libreria non ha orologio. Assente = non mostrato. */\r\n updatedAt?: string;\r\n updatedBy?: string;\r\n /** Numero di nodi. Lo conta l'ospite, **mai** il client. Assente = non mostrato. */\r\n nodeCount?: number;\r\n /**\r\n * Esito dell'ultima validazione **noto all'ospite**: riportato, non ricalcolato. Puo' essere\r\n * vecchio, quindi la riga lo mostra come stato noto e non come verita' — il frontend non\r\n * valida nulla, e dedurlo qui sarebbe una validazione fatta dal client per interposta persona.\r\n */\r\n hasErrors?: boolean;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §2 Provider di metadati\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Tre esiti, **non due** (ADR 0004): \"dichiarata\", \"dichiarata senza campi\" e\r\n * \"sconosciuta\" sono situazioni diverse e l'editor le mostra diverse. Chi implementa\r\n * l'interfaccia non appiattisce `Unknown` in una lista di campi vuota.\r\n */\r\nexport type TableLookupOutcome = 'Declared' | 'DeclaredWithoutFields' | 'Unknown';\r\n\r\nexport interface TableSummary {\r\n name: string;\r\n description?: string;\r\n}\r\n\r\nexport interface FieldRelationship {\r\n targetTableName: string;\r\n targetFieldName: string;\r\n}\r\n\r\nexport interface FieldDescriptor {\r\n name: string;\r\n description?: string;\r\n type: ColumnType;\r\n isKey: boolean;\r\n isNullable: boolean;\r\n /** Assente quando il campo non e' una relazione. */\r\n relationship?: FieldRelationship;\r\n}\r\n\r\nexport interface TableDescriptor {\r\n name: string;\r\n description?: string;\r\n fields?: FieldDescriptor[];\r\n}\r\n\r\nexport interface TableLookupResult {\r\n outcome: TableLookupOutcome;\r\n /** Presente solo con `outcome === 'Declared'`. */\r\n table?: TableDescriptor;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §3 SQL emesso\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface SqlParameterValue {\r\n /** Senza prefisso di dialetto: `\"p0\"`, `\"param_StartDate\"`. */\r\n name: string;\r\n type: LogicalType;\r\n /** `null` ammesso. Valore opaco per l'editor, che lo mostra e non lo interpreta. */\r\n value: unknown;\r\n}\r\n\r\nexport interface SqlStatement {\r\n /** Porta i marcatori nella forma del dialetto (`@p0`, `:p0`, `$1`). */\r\n text: string;\r\n parameters?: SqlParameterValue[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §5 Il service: Validate\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface DpeColumnInfo {\r\n name: string;\r\n type: ColumnType;\r\n /**\r\n * Informativa (**I4**): serve alla vista dello schema, non blocca la compilazione. Il\r\n * frontend non la calcola — arriva da qui.\r\n */\r\n isNullable: boolean;\r\n}\r\n\r\nexport interface DpeNodeSchemaInfo {\r\n nodeName: string;\r\n columns?: DpeColumnInfo[];\r\n /**\r\n * `false` = nodo **valido ma non compilabile** (**I10**): e' un limite nostro, non un\r\n * errore dell'utente, e va reso diverso da un nodo invalido.\r\n */\r\n isCompilable: boolean;\r\n}\r\n\r\nexport interface DpeWritebackStep {\r\n writebackName: string;\r\n sequence: number;\r\n target: WritebackTargetKind;\r\n /** Assente per i target `Json`/`Csv`. */\r\n operation?: WritebackOperation;\r\n tableName?: string;\r\n /**\r\n * Campo di corrispondenza dell'`Upsert`; assente per ogni altra operazione. E' un\r\n * `targetFieldName`: si ritrova in `targetMapping` per risalire alla colonna del result set\r\n * (ADR 0016).\r\n */\r\n externalIdFieldName?: string;\r\n /** Presente se il writeback appartiene a un gruppo atomico. */\r\n atomicGroupName?: string;\r\n /**\r\n * Dichiarato, **non implementato dalla libreria**: il change tracking e' dell'host\r\n * (ADR 0011) e non influenza l'SQL generato. Va mostrato come una dichiarazione che l'host\r\n * deve onorare, non come una cosa che il motore fa.\r\n */\r\n onlyChangedRows?: boolean;\r\n}\r\n\r\nexport interface DpeValidateResult {\r\n hasErrors: boolean;\r\n /** Esaustive (**I6**): l'elenco completo, non il primo rilievo. */\r\n diagnostics?: Diagnostic[];\r\n /** Ordine topologico. */\r\n schemas?: DpeNodeSchemaInfo[];\r\n executionOrder?: string[];\r\n writebackSequence?: DpeWritebackStep[];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// §5 Il service: Compile\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Valore di un parametro di runtime per una compilazione (`DpeParameterValue`).\r\n *\r\n * `value` e' **opaco**: il tipo dichiarato del parametro lo conosce il backend, che lo\r\n * interpreta secondo `ColumnType` in cultura invariante. L'editor lo trasporta e lo mostra,\r\n * non lo converte.\r\n */\r\nexport interface DpeParameterValue {\r\n name: string;\r\n value: unknown;\r\n}\r\n\r\n/**\r\n * Cio' che serve all'host per **eseguire** la scrittura che la libreria non esegue\r\n * (`contracts.md` §2, «`DpeFieldMappingInfo`»): senza, l'host riceve un result set e non sa\r\n * quale colonna va in quale campo ne' quale sia la chiave.\r\n */\r\nexport interface DpeFieldMappingInfo {\r\n /** Nome della colonna nel result set dello `SqlStatement`. */\r\n resultColumnName?: string;\r\n targetFieldName: string;\r\n role: WritebackFieldRole;\r\n /** Presente: il valore viene da un parametro, non dalla riga. */\r\n runtimeParameterName?: string;\r\n /** La destinazione genera il valore: non e' nel result set. */\r\n isAutoGenerated?: boolean;\r\n relationshipName?: string;\r\n parentName?: string;\r\n}\r\n\r\nexport interface DpeCompiledWriteback {\r\n writebackName: string;\r\n sequence: number;\r\n statement: SqlStatement;\r\n resultColumns?: DpeColumnInfo[];\r\n /** Vedi {@link DpeFieldMappingInfo}: forma provvisoria. */\r\n targetMapping?: DpeFieldMappingInfo[];\r\n}\r\n\r\nexport interface DpeCompileResult {\r\n hasErrors: boolean;\r\n diagnostics?: Diagnostic[];\r\n databaseWritebacks?: DpeCompiledWriteback[];\r\n /** SQL di lettura, non ancora eseguito. */\r\n fileWritebacks?: DpeCompiledWriteback[];\r\n writebackSequence?: DpeWritebackStep[];\r\n}\r\n","/**\r\n * Quali primitive **opzionali** l'ospite implementa davvero — `contracts.md` §7, normativo.\r\n *\r\n * La rilevazione e' per **identita' del metodo**: se il metodo dell'istanza e' ancora quello del\r\n * prototipo di `DpeBuilderApi`, l'ospite non lo ha sovrascritto e la primitiva non c'e'. E'\r\n * esatta, non richiede una primitiva di interrogazione e non aggiunge un giro di rete.\r\n *\r\n * Perche' un solo posto: la disponibilita' va saputa **prima del clic**. Lo schema precedente —\r\n * partire da «disponibile» e scoprire l'assenza dal primo `MissingService` — mostra un comando\r\n * attivo che fallisce alla pressione, cioe' insegna a non fidarsi dei bottoni, e per giunta\r\n * costringe ogni consumatore a ripetere lo stesso trattamento dell'errore.\r\n *\r\n * Regola per chi implementa un host (normativa, `contracts.md` §7): **chi non supporta una\r\n * primitiva non la sovrascrive**. Una sovrascrittura che lancia subito non equivale all'assenza —\r\n * l'editor la considera disponibile e mostra il comando attivo.\r\n *\r\n * **Dichiarazione sottrattiva (ADR 0020).** Da quando la libreria spedisce un client HTTP che\r\n * implementa tutte e dieci le primitive, l'identita' da sola non basta: chi eredita quel client\r\n * non puo' dis-sovrascrivere un metodo. Disponibile diventa quindi «**sovrascritta** e **non\r\n * elencata** in `unsupportedPrimitives`». La seconda meta' e' solo sottrattiva — non rende\r\n * disponibile cio' che non e' implementato — e resta calcolata in questo file e in nessun altro.\r\n */\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\n\r\n/** Le primitive che un ambiente ospite puo' legittimamente non offrire. */\r\nexport type DpeOptionalPrimitive =\r\n | 'compilePreview'\r\n | 'load'\r\n | 'save'\r\n | 'getEnvironment'\r\n | 'listDefinitions'\r\n | 'createDefinition'\r\n | 'deleteDefinition';\r\n\r\ntype MethodBag = Record<string, unknown>;\r\n\r\nexport function dpeIsPrimitiveAvailable(\r\n api: DpeBuilderApi,\r\n primitive: DpeOptionalPrimitive,\r\n): boolean {\r\n // Prima la dichiarazione dell'ospite: se il servizio non c'e', non conta chi ha scritto il\r\n // metodo. E' l'unico modo per un ospite di spegnere una primitiva che ha **ereditato**.\r\n if (api.unsupportedPrimitives?.includes(primitive)) {\r\n return false;\r\n }\r\n const base = DpeBuilderApi.prototype as unknown as MethodBag;\r\n const implementation = (api as unknown as MethodBag)[primitive];\r\n return typeof implementation === 'function' && implementation !== base[primitive];\r\n}\r\n\r\n/** L'insieme delle primitive disponibili: comodo per fotografarlo una volta alla costruzione. */\r\nexport interface DpeCapabilities {\r\n readonly compilePreview: boolean;\r\n readonly load: boolean;\r\n readonly save: boolean;\r\n readonly getEnvironment: boolean;\r\n readonly listDefinitions: boolean;\r\n readonly createDefinition: boolean;\r\n readonly deleteDefinition: boolean;\r\n}\r\n\r\nexport function dpeReadCapabilities(api: DpeBuilderApi): DpeCapabilities {\r\n return {\r\n compilePreview: dpeIsPrimitiveAvailable(api, 'compilePreview'),\r\n load: dpeIsPrimitiveAvailable(api, 'load'),\r\n save: dpeIsPrimitiveAvailable(api, 'save'),\r\n getEnvironment: dpeIsPrimitiveAvailable(api, 'getEnvironment'),\r\n listDefinitions: dpeIsPrimitiveAvailable(api, 'listDefinitions'),\r\n createDefinition: dpeIsPrimitiveAvailable(api, 'createDefinition'),\r\n deleteDefinition: dpeIsPrimitiveAvailable(api, 'deleteDefinition'),\r\n };\r\n}\r\n\r\n/**\r\n * Disponibilita' di un comando, con **il motivo** quando manca: un bottone disabilitato che non\r\n * dice perche' manda a cercare un guasto che non c'e'.\r\n */\r\nexport interface DpeCommandAvailability {\r\n readonly isAvailable: boolean;\r\n /** Presente **solo** quando il comando non e' disponibile. Va nel `title` del bottone. */\r\n readonly reason?: string;\r\n}\r\n\r\n/**\r\n * Il comando di **creazione** e' l'unico che dipende da **due** primitive\r\n * (`contracts.md` §7, normativo): `createDefinition` per scrivere, e `getEnvironment` perche' il\r\n * dialetto della definizione nuova viene dall'ambiente (ADR 0017).\r\n *\r\n * Perche' senza `getEnvironment` si disabilita invece di ripiegare su un dialetto qualsiasi: una\r\n * definizione creata per il dialetto sbagliato porta espressioni SQL native (ADR 0006) da\r\n * riscrivere tutte, e chiederlo all'utente e' proprio la scelta che l'ADR 0017 ha tolto. Un\r\n * comando disabilitato che dice perche' e' meglio di entrambe; il rimedio per l'ospite e' una\r\n * riga, implementare `getEnvironment`.\r\n *\r\n * Sta qui e non dentro un componente per la stessa ragione delle altre: la disponibilita' si sa\r\n * **prima del clic**, e in un solo posto.\r\n */\r\nexport function dpeCreateCommandAvailability(\r\n capabilities: DpeCapabilities,\r\n): DpeCommandAvailability {\r\n const missing: string[] = [];\r\n if (!capabilities.createDefinition) {\r\n missing.push('createDefinition');\r\n }\r\n if (!capabilities.getEnvironment) {\r\n missing.push('getEnvironment');\r\n }\r\n if (missing.length === 0) {\r\n return { isAvailable: true };\r\n }\r\n return {\r\n isAvailable: false,\r\n reason:\r\n missing.length === 2\r\n ? 'Creazione non disponibile: questo ambiente non implementa createDefinition ne’ getEnvironment. ' +\r\n 'Senza la dichiarazione dell’ambiente il dialetto non si sceglie per ripiego (ADR 0017).'\r\n : missing[0] === 'createDefinition'\r\n ? 'Creazione non disponibile: questo ambiente non implementa createDefinition.'\r\n : 'Creazione non disponibile: questo ambiente non dichiara l’ambiente (getEnvironment), ' +\r\n 'quindi il dialetto della definizione nuova non e’ noto e non si sceglie per ripiego (ADR 0017).',\r\n };\r\n}\r\n","/**\r\n * Il grafo della definizione: **un solo posto** costruisce gli id di nodi, porte e archi, e\r\n * **un solo elenco** descrive dove vivono i riferimenti fra nodi.\r\n *\r\n * Perche' sta tutto qui. Un id di porta costruito in due modi diversi (canvas da un lato,\r\n * derivazione degli archi dall'altro) fa sparire un arco **senza nessun errore**: e' il\r\n * difetto piu' difficile da trovare in un editor a canvas. Allo stesso modo, un riferimento\r\n * dimenticato nell'elenco degli slot fa restare incoerente il documento dopo una rinomina,\r\n * anche lì in silenzio.\r\n *\r\n * Cosa **non** sta qui: nessuna regola di dominio. Questo file dice *dove* stanno i nomi dei\r\n * nodi a monte, non se un riferimento e' valido, se il grafo ha cicli (**I2**), se un nodo e'\r\n * a valle (**I3**) o quali colonne produca (**I4**). Quelle risposte arrivano da\r\n * `DpeBuilderApi.validate`.\r\n */\r\n\r\nimport {\r\n AggregateNode,\r\n AppendNode,\r\n AtomicWritebackNode,\r\n CustomNode,\r\n DataSourceNode,\r\n DPE_NODE_COLLECTIONS,\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n FilterNode,\r\n ForecastNode,\r\n HierarchyPathNode,\r\n JoinNode,\r\n TransformNode,\r\n WritebackNode,\r\n} from '../model/dpe-definition.model';\r\n\r\n// ---------------------------------------------------------------------------\r\n// Id — l'unico posto che li costruisce\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Separatore dei componenti di un id. Un nome di nodo non lo contiene mai: i nomi sono\r\n * identificatori del modello e il backend li usa come identificatori SQL.\r\n */\r\nconst SEP = '::';\r\n\r\nexport function dpeNodeId(nodeName: string): string {\r\n return `node${SEP}${nodeName}`;\r\n}\r\n\r\n/**\r\n * Porta di ingresso. Una porta **per slot** (e per indice, sugli slot a lista): un `JoinNode`\r\n * ha due ingressi distinti e attaccare l'arco alla porta sbagliata scambia primaria e\r\n * secondaria, che e' un join diverso.\r\n */\r\nexport function dpeInputPortId(nodeName: string, slot: string, index?: number): string {\r\n const suffix = index === undefined ? '' : `${SEP}${index}`;\r\n return `in${SEP}${nodeName}${SEP}${slot}${suffix}`;\r\n}\r\n\r\n/** Porta di uscita: una sola per nodo, lo schema prodotto e' uno. */\r\nexport function dpeOutputPortId(nodeName: string): string {\r\n return `out${SEP}${nodeName}`;\r\n}\r\n\r\n/**\r\n * Id dell'arco: identifica la **destinazione** (nodo, slot, indice), non la coppia di nodi.\r\n * Due archi possono unire gli stessi due nodi su slot diversi — la primaria e la secondaria\r\n * di un self-join — e con un id per coppia uno dei due sparirebbe.\r\n */\r\nexport function dpeEdgeId(targetNodeName: string, slot: string, index?: number): string {\r\n const suffix = index === undefined ? '' : `${SEP}${index}`;\r\n return `edge${SEP}${targetNodeName}${SEP}${slot}${suffix}`;\r\n}\r\n\r\n/**\r\n * Gli inversi. Stanno **accanto** ai costruttori e non nel canvas: la libreria di canvas\r\n * restituisce gli id nei suoi eventi, e chi li legge deve tornare al nome del nodo con la\r\n * stessa convenzione con cui li ha scritti. Separarli e' il modo con cui un giorno cambierebbe\r\n * uno solo dei due.\r\n */\r\nexport function dpeParseNodeId(id: string): string | undefined {\r\n return id.startsWith(`node${SEP}`) ? id.slice(4 + SEP.length) : undefined;\r\n}\r\n\r\nexport function dpeParseOutputPortId(id: string): string | undefined {\r\n return id.startsWith(`out${SEP}`) ? id.slice(3 + SEP.length) : undefined;\r\n}\r\n\r\nexport function dpeParseInputPortId(\r\n id: string,\r\n): { nodeName: string; slot: string; index?: number } | undefined {\r\n if (!id.startsWith(`in${SEP}`)) {\r\n return undefined;\r\n }\r\n const parts = id.slice(2 + SEP.length).split(SEP);\r\n if (parts.length < 2) {\r\n return undefined;\r\n }\r\n const [nodeName, slot, rawIndex] = parts;\r\n const index = rawIndex === undefined ? undefined : Number(rawIndex);\r\n return {\r\n nodeName,\r\n slot,\r\n index: index === undefined || Number.isNaN(index) ? undefined : index,\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Slot dei riferimenti — l'unico elenco\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Uno slot e' un punto del nodo che contiene il nome di **un altro nodo**.\r\n *\r\n * `read` e `write` sono **posizionali e di lunghezza stabile**: `write(node, read(node))` non\r\n * cambia il nodo. E' la proprieta' che permette di implementare la rinomina come\r\n * `write(node, read(node).map(rinomina))` — cioe' con un solo cammino di codice, invece di\r\n * due elenchi (uno per leggere gli archi, uno per rinominare) che al primo campo aggiunto\r\n * diventano due elenchi diversi.\r\n */\r\nexport interface DpeSourceSlot<TNode> {\r\n readonly slot: string;\r\n /**\r\n * `true` quando lo slot e' un **arco del DAG** (il flusso dei dati). `false` per i\r\n * riferimenti che sono altro: i `sourceName` dei `JoinResultField` ripetono le sorgenti del\r\n * join, e le relazioni di un gruppo atomico dichiarano una transazione dell'host, non un\r\n * flusso di dati (l'ordinamento dei sink e' esplicito e separato dal DAG).\r\n */\r\n readonly isEdge: boolean;\r\n read(node: TNode): readonly (string | undefined)[];\r\n write(node: TNode, names: readonly (string | undefined)[]): TNode;\r\n}\r\n\r\nfunction single<TNode, TKey extends keyof TNode>(\r\n slot: string,\r\n key: TKey,\r\n isEdge = true,\r\n): DpeSourceSlot<TNode> {\r\n return {\r\n slot,\r\n isEdge,\r\n read: (node) => [node[key] as unknown as string | undefined],\r\n // Il cast copre solo la chiave calcolata: TypeScript non sa che `key` di `TNode` porta una\r\n // stringa, e la mappa dei tipi non e' esprimibile senza questo passaggio.\r\n write: (node, names) => ({ ...node, [key]: names[0] }) as unknown as TNode,\r\n };\r\n}\r\n\r\nfunction list<TNode, TKey extends keyof TNode>(\r\n slot: string,\r\n key: TKey,\r\n isEdge = true,\r\n): DpeSourceSlot<TNode> {\r\n return {\r\n slot,\r\n isEdge,\r\n read: (node) => ((node[key] as unknown as string[] | undefined) ?? []).slice(),\r\n // Uno slot a lista non si accorcia in scrittura: `write` riscrive i nomi al loro posto.\r\n // Aggiungere o togliere una sorgente e' una mutazione dello store, non una riscrittura.\r\n write: (node, names) =>\r\n ({ ...node, [key]: names.map((name) => name ?? '') }) as unknown as TNode,\r\n };\r\n}\r\n\r\nconst JOIN_RESULT_FIELDS_SLOT: DpeSourceSlot<JoinNode> = {\r\n slot: 'resultFields',\r\n isEdge: false,\r\n read: (node) => (node.fields ?? []).map((field) => field.sourceName),\r\n write: (node, names) =>\r\n node.fields === undefined\r\n ? node\r\n : {\r\n ...node,\r\n fields: node.fields.map((field, index) => ({ ...field, sourceName: names[index] ?? '' })),\r\n },\r\n};\r\n\r\n/**\r\n * Le relazioni di un gruppo atomico portano **due** nomi di writeback ciascuna, padre e\r\n * figlio. Sono letti e riscritti in coppia e in ordine: se questo slot mancasse, rinominare\r\n * un writeback lascerebbe il gruppo atomico che punta a un nome che non esiste piu' — senza\r\n * nessun errore lato editor, e con un rifiuto del backend che parla di un nodo che l'utente\r\n * non ha toccato.\r\n */\r\nconst ATOMIC_RELATIONSHIPS_SLOT: DpeSourceSlot<AtomicWritebackNode> = {\r\n slot: 'relationships',\r\n isEdge: false,\r\n read: (node) =>\r\n (node.relationships ?? []).flatMap((relationship) => [\r\n relationship.parentWritebackName,\r\n relationship.childWritebackName,\r\n ]),\r\n write: (node, names) =>\r\n node.relationships === undefined\r\n ? node\r\n : {\r\n ...node,\r\n relationships: node.relationships.map((relationship, index) => ({\r\n ...relationship,\r\n parentWritebackName: names[index * 2],\r\n childWritebackName: names[index * 2 + 1],\r\n })),\r\n },\r\n};\r\n\r\n/** Gli slot di ogni collezione. Aggiungere un nodo significa aggiungere una riga qui. */\r\nexport const DPE_SOURCE_SLOTS: {\r\n readonly [K in DpeNodeCollectionName]: readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];\r\n} = {\r\n // Le sorgenti sono i punti d'ingresso del grafo: non riferiscono nessun nodo a monte.\r\n dataSources: [] as readonly DpeSourceSlot<DataSourceNode>[],\r\n filters: [single<FilterNode, 'sourceName'>('source', 'sourceName')],\r\n joins: [\r\n single<JoinNode, 'primarySourceName'>('primary', 'primarySourceName'),\r\n single<JoinNode, 'secondarySourceName'>('secondary', 'secondarySourceName'),\r\n JOIN_RESULT_FIELDS_SLOT,\r\n ],\r\n aggregates: [single<AggregateNode, 'sourceName'>('source', 'sourceName')],\r\n transforms: [single<TransformNode, 'sourceName'>('source', 'sourceName')],\r\n appends: [list<AppendNode, 'sources'>('sources', 'sources')],\r\n hierarchyPaths: [single<HierarchyPathNode, 'sourceName'>('source', 'sourceName')],\r\n forecasts: [single<ForecastNode, 'sourceName'>('source', 'sourceName')],\r\n customNodes: [list<CustomNode, 'sources'>('sources', 'sources')],\r\n writebacks: [single<WritebackNode, 'sourceName'>('source', 'sourceName')],\r\n atomicWritebacks: [ATOMIC_RELATIONSHIPS_SLOT],\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// Lettura del documento\r\n// ---------------------------------------------------------------------------\r\n\r\n/** Un nodo con la collezione da cui viene: senza, non si sa quali slot leggere. */\r\nexport interface DpeLocatedNode<K extends DpeNodeCollectionName = DpeNodeCollectionName> {\r\n collection: K;\r\n index: number;\r\n node: DpeNodeCollectionMap[K];\r\n}\r\n\r\n/** Tutti i nodi, nell'ordine delle collezioni (sorgenti -> trasformazioni -> sink). */\r\nexport function dpeAllNodes(definition: DpeDefinition): DpeLocatedNode[] {\r\n const result: DpeLocatedNode[] = [];\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = (definition[collection] ?? []) as DpeAnyNode[];\r\n nodes.forEach((node, index) => {\r\n result.push({ collection, index, node } as DpeLocatedNode);\r\n });\r\n }\r\n return result;\r\n}\r\n\r\nexport function dpeFindNode(definition: DpeDefinition, nodeName: string): DpeLocatedNode | undefined {\r\n return dpeAllNodes(definition).find((located) => located.node.name === nodeName);\r\n}\r\n\r\nexport interface DpeSourceReference {\r\n /** Nodo che contiene il riferimento (la destinazione dell'arco). */\r\n targetNodeName: string;\r\n collection: DpeNodeCollectionName;\r\n slot: string;\r\n /** Presente solo sugli slot a lista. */\r\n index?: number;\r\n isEdge: boolean;\r\n /** Nome riferito; assente quando lo slot e' vuoto (nodo non collegato). */\r\n sourceName?: string;\r\n}\r\n\r\n/** I riferimenti di un singolo nodo, in ordine di slot. */\r\nexport function dpeNodeSourceReferences(located: DpeLocatedNode): DpeSourceReference[] {\r\n const slots = DPE_SOURCE_SLOTS[located.collection] as readonly DpeSourceSlot<DpeAnyNode>[];\r\n const references: DpeSourceReference[] = [];\r\n for (const slot of slots) {\r\n const names = slot.read(located.node);\r\n const isPositional = names.length > 1 || slotIsPositional(slot);\r\n names.forEach((name, index) => {\r\n references.push({\r\n targetNodeName: located.node.name,\r\n collection: located.collection,\r\n slot: slot.slot,\r\n index: isPositional ? index : undefined,\r\n isEdge: slot.isEdge,\r\n sourceName: name === '' ? undefined : name,\r\n });\r\n });\r\n }\r\n return references;\r\n}\r\n\r\n/**\r\n * Uno slot a lista porta l'indice **anche** quando contiene un solo elemento: l'id della\r\n * porta e dell'arco non deve cambiare forma quando l'utente aggiunge la seconda sorgente a\r\n * un `AppendNode`, altrimenti la selezione dell'arco salta e la posizione della porta cambia\r\n * sotto il puntatore.\r\n */\r\nfunction slotIsPositional(slot: DpeSourceSlot<DpeAnyNode>): boolean {\r\n return slot.slot === 'sources' || slot.slot === 'resultFields' || slot.slot === 'relationships';\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Archi\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface DpeGraphNode {\r\n id: string;\r\n name: string;\r\n collection: DpeNodeCollectionName;\r\n outputPortId: string;\r\n}\r\n\r\nexport interface DpeGraphEdge {\r\n id: string;\r\n /** Nome del nodo a monte, come scritto nel documento. */\r\n fromNodeName: string;\r\n toNodeName: string;\r\n slot: string;\r\n index?: number;\r\n fromPortId: string;\r\n toPortId: string;\r\n /**\r\n * `false` quando il nome a monte non corrisponde a nessun nodo della definizione. L'arco\r\n * **si mostra comunque**: la topologia mostrata e' quella reale, e un riferimento rotto va\r\n * visto, non nascosto. La diagnostica che lo qualifica (`DPE_REF_UNKNOWN_NODE`) arriva dal\r\n * backend.\r\n */\r\n isResolved: boolean;\r\n}\r\n\r\nexport interface DpeGraph {\r\n nodes: DpeGraphNode[];\r\n edges: DpeGraphEdge[];\r\n}\r\n\r\n/**\r\n * Deriva nodi e archi dalla definizione, per riferimento di nome. Funzione pura: nessuna\r\n * lettura di stato, nessuna dipendenza da Angular, testabile senza DOM.\r\n */\r\nexport function dpeBuildGraph(definition: DpeDefinition): DpeGraph {\r\n const located = dpeAllNodes(definition);\r\n const known = new Set(located.map((entry) => entry.node.name));\r\n\r\n const nodes: DpeGraphNode[] = located.map((entry) => ({\r\n id: dpeNodeId(entry.node.name),\r\n name: entry.node.name,\r\n collection: entry.collection,\r\n outputPortId: dpeOutputPortId(entry.node.name),\r\n }));\r\n\r\n const edges: DpeGraphEdge[] = [];\r\n for (const entry of located) {\r\n for (const reference of dpeNodeSourceReferences(entry)) {\r\n if (!reference.isEdge || reference.sourceName === undefined) {\r\n continue;\r\n }\r\n edges.push({\r\n id: dpeEdgeId(reference.targetNodeName, reference.slot, reference.index),\r\n fromNodeName: reference.sourceName,\r\n toNodeName: reference.targetNodeName,\r\n slot: reference.slot,\r\n index: reference.index,\r\n fromPortId: dpeOutputPortId(reference.sourceName),\r\n toPortId: dpeInputPortId(reference.targetNodeName, reference.slot, reference.index),\r\n isResolved: known.has(reference.sourceName),\r\n });\r\n }\r\n }\r\n\r\n return { nodes, edges };\r\n}\r\n\r\n/** Le porte di ingresso di un nodo, nell'ordine in cui vanno disegnate. */\r\nexport interface DpeInputPort {\r\n id: string;\r\n slot: string;\r\n index?: number;\r\n /** Nome collegato, assente se la porta e' libera. */\r\n sourceName?: string;\r\n}\r\n\r\nexport function dpeInputPorts(located: DpeLocatedNode): DpeInputPort[] {\r\n return dpeNodeSourceReferences(located)\r\n .filter((reference) => reference.isEdge)\r\n .map((reference) => ({\r\n id: dpeInputPortId(reference.targetNodeName, reference.slot, reference.index),\r\n slot: reference.slot,\r\n index: reference.index,\r\n sourceName: reference.sourceName,\r\n }));\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Riscrittura dei riferimenti\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * Riscrive un riferimento in **uno** slot di **un** nodo. E' il mattone di `connect` e\r\n * `disconnect` dello store: passando `undefined` la porta torna libera.\r\n */\r\nexport function dpeWriteSourceReference<K extends DpeNodeCollectionName>(\r\n collection: K,\r\n node: DpeNodeCollectionMap[K],\r\n slotName: string,\r\n index: number | undefined,\r\n sourceName: string | undefined,\r\n): DpeNodeCollectionMap[K] {\r\n const slots = DPE_SOURCE_SLOTS[collection] as readonly DpeSourceSlot<DpeNodeCollectionMap[K]>[];\r\n const slot = slots.find((candidate) => candidate.slot === slotName);\r\n if (!slot) {\r\n return node;\r\n }\r\n const names = slot.read(node).slice();\r\n const position = index ?? 0;\r\n // Uno slot a lista puo' non avere ancora la posizione richiesta: la si apre, altrimenti\r\n // collegare la seconda sorgente di un Append non avrebbe nessun effetto e nessun errore.\r\n while (names.length <= position) {\r\n names.push(undefined);\r\n }\r\n names[position] = sourceName;\r\n return slot.write(node, names);\r\n}\r\n\r\n/**\r\n * **Rinominare un nodo e' un refactoring globale, non locale** (**I5**).\r\n *\r\n * Questa e' l'unica funzione che rinomina: aggiorna il `name` del nodo e **ogni** riferimento\r\n * a valle, passando dall'unico elenco di slot — `sourceName`, `sources`,\r\n * `primarySourceName`/`secondarySourceName`, i `sourceName` dei `JoinResultField` e i nomi\r\n * dentro i gruppi atomici. Se una collezione di riferimenti sfuggisse, il documento\r\n * diventerebbe silenziosamente incoerente: e' il difetto che questa funzione esiste per non\r\n * avere.\r\n *\r\n * Cosa **non** fa, di proposito: non rinomina gli **alias di colonna** (sono un altro spazio\r\n * di nomi) e non decide se il nuovo nome sia lecito o già usato — l'unicita' e' **I1**, la\r\n * verifica il backend.\r\n *\r\n * Il confronto e' **esatto**, non case-insensitive: `domain-model.md` dichiara il confronto\r\n * `OrdinalIgnoreCase` per gli **alias di colonna** e non dice nulla sui nomi dei nodi.\r\n * Rinominare anche le occorrenze con capitalizzazione diversa significherebbe, se il backend\r\n * risolvesse i nomi in modo esatto, riscrivere il riferimento a un nodo **diverso**.\r\n */\r\nexport function dpeRenameNode(\r\n definition: DpeDefinition,\r\n oldName: string,\r\n newName: string,\r\n): DpeDefinition {\r\n if (oldName === newName) {\r\n return definition;\r\n }\r\n\r\n const next: DpeDefinition = { ...definition };\r\n\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = definition[collection] as DpeAnyNode[] | undefined;\r\n if (!nodes || nodes.length === 0) {\r\n continue;\r\n }\r\n const slots = DPE_SOURCE_SLOTS[collection] as readonly DpeSourceSlot<DpeAnyNode>[];\r\n const rewritten = nodes.map((node) => {\r\n let result = node;\r\n for (const slot of slots) {\r\n const names = slot.read(result);\r\n if (!names.some((name) => name === oldName)) {\r\n continue;\r\n }\r\n result = slot.write(\r\n result,\r\n names.map((name) => (name === oldName ? newName : name)),\r\n );\r\n }\r\n if (result.name === oldName) {\r\n result = { ...result, name: newName };\r\n }\r\n return result;\r\n });\r\n // L'assegnazione per nome di collezione non e' esprimibile in modo tipato senza un cast:\r\n // la mappa collezione -> tipo di nodo esiste, ma TypeScript non correla la chiave con il\r\n // valore dentro un ciclo. Il cast e' confinato a questa riga.\r\n (next as unknown as Record<string, unknown>)[collection] = rewritten;\r\n }\r\n\r\n return next;\r\n}\r\n\r\n/** Quante occorrenze toccherebbe una rinomina: serve a dirlo prima, non dopo. */\r\nexport function dpeCountReferences(definition: DpeDefinition, nodeName: string): number {\r\n let count = 0;\r\n for (const located of dpeAllNodes(definition)) {\r\n for (const reference of dpeNodeSourceReferences(located)) {\r\n if (reference.sourceName === nodeName) {\r\n count += 1;\r\n }\r\n }\r\n }\r\n return count;\r\n}\r\n","/**\r\n * Utility pure sulle diagnostiche **ricevute** dal backend: raggruppamento per nodo, gravita'\r\n * peggiore, e la distinzione fra \"da correggere\" e \"non ancora compilabile\".\r\n *\r\n * Qui non nasce nessuna diagnostica e non si giudica nessuna definizione: si legge cio' che il\r\n * backend ha detto e si decide **come renderlo**. La sola informazione interpretata e' il\r\n * `DiagnosticPath`, che il contratto pubblica in **due forme** (con nome del nodo dalla\r\n * validazione, con solo indice dalla deserializzazione): chi legge deve accettarle entrambe,\r\n * altrimenti le diagnostiche del caricamento di un file non sono navigabili.\r\n */\r\n\r\nimport { Diagnostic, DiagnosticSeverity, DPE_NODE_NOT_COMPILABLE } from '../model/dpe-diagnostics.model';\r\nimport { DpeDefinition, DpeNodeCollectionName } from '../model/dpe-definition.model';\r\nimport { dpeAllNodes } from './dpe-graph';\r\n\r\n/**\r\n * Il nodo a cui una diagnostica si riferisce, se ricavabile.\r\n *\r\n * Tre strade, nell'ordine: il nome nel primo segmento del percorso; l'argomento canonico\r\n * `node`; l'indice del primo segmento risolto nella collezione corrispondente della\r\n * definizione — che e' il caso della deserializzazione, dove i nomi non sono ancora noti.\r\n * Senza la terza, un `filters[0].sourceName` resterebbe una riga non cliccabile.\r\n */\r\nexport function dpeDiagnosticNodeName(\r\n diagnostic: Diagnostic,\r\n definition?: DpeDefinition,\r\n): string | undefined {\r\n const first = diagnostic.path?.segments?.[0];\r\n if (first?.name) {\r\n return first.name;\r\n }\r\n const fromArguments = diagnostic.arguments?.['node'];\r\n if (fromArguments) {\r\n return fromArguments;\r\n }\r\n if (!definition || !first?.collection || first.index === undefined) {\r\n return undefined;\r\n }\r\n const collection = definition[first.collection as DpeNodeCollectionName];\r\n if (!Array.isArray(collection)) {\r\n return undefined;\r\n }\r\n return collection[first.index]?.name;\r\n}\r\n\r\n/** Il campo in causa, per evidenziarlo nell'ispettore. */\r\nexport function dpeDiagnosticField(diagnostic: Diagnostic): string | undefined {\r\n return diagnostic.path?.field;\r\n}\r\n\r\n/**\r\n * `true` per l'unico codice che significa \"hai fatto bene, siamo noi\" (**I10**, ADR 0005):\r\n * `Forecast`, `CustomNode`, costrutto non supportato dal dialetto scelto. Non va mescolato\r\n * con i `DPE_MODEL_*`, che l'utente deve correggere.\r\n */\r\nexport function dpeIsNotCompilable(diagnostic: Diagnostic): boolean {\r\n return diagnostic.code === DPE_NODE_NOT_COMPILABLE;\r\n}\r\n\r\n/**\r\n * `true` quando la diagnostica riguarda le **capacita' del dialetto** e non la definizione in\r\n * se': l'interfaccia deve dire «questo dialetto non lo supporta», perche' lo stesso documento\r\n * su un altro dialetto sarebbe compilabile.\r\n */\r\nexport function dpeIsDialectDiagnostic(diagnostic: Diagnostic): boolean {\r\n return diagnostic.code.startsWith('DPE_DIALECT_');\r\n}\r\n\r\nexport interface DpeNodeDiagnostics {\r\n /** Diagnostiche ancorate al nodo, nell'ordine ricevuto (**I6**: l'elenco e' esaustivo). */\r\n diagnostics: Diagnostic[];\r\n /** La gravita' peggiore fra quelle presenti. */\r\n severity?: DiagnosticSeverity;\r\n /**\r\n * Il nodo e' **valido ma non compilabile**: stato distinto da \"non valido\", e l'unico per\r\n * cui la UI non deve chiedere all'utente di correggere niente.\r\n */\r\n isNotCompilable: boolean;\r\n}\r\n\r\nconst SEVERITY_RANK: Readonly<Record<DiagnosticSeverity, number>> = {\r\n Info: 1,\r\n Warning: 2,\r\n Error: 3,\r\n};\r\n\r\nexport function dpeWorstSeverity(diagnostics: readonly Diagnostic[]): DiagnosticSeverity | undefined {\r\n let worst: DiagnosticSeverity | undefined;\r\n for (const diagnostic of diagnostics) {\r\n if (!worst || SEVERITY_RANK[diagnostic.severity] > SEVERITY_RANK[worst]) {\r\n worst = diagnostic.severity;\r\n }\r\n }\r\n return worst;\r\n}\r\n\r\n/** Raggruppa per nodo. Le diagnostiche non ancorabili a un nodo non si perdono: vedi sotto. */\r\nexport function dpeGroupDiagnosticsByNode(\r\n diagnostics: readonly Diagnostic[],\r\n definition?: DpeDefinition,\r\n): Map<string, DpeNodeDiagnostics> {\r\n const grouped = new Map<string, DpeNodeDiagnostics>();\r\n for (const diagnostic of diagnostics) {\r\n const nodeName = dpeDiagnosticNodeName(diagnostic, definition);\r\n if (nodeName === undefined) {\r\n continue;\r\n }\r\n const entry = grouped.get(nodeName) ?? { diagnostics: [], isNotCompilable: false };\r\n entry.diagnostics.push(diagnostic);\r\n entry.isNotCompilable = entry.isNotCompilable || dpeIsNotCompilable(diagnostic);\r\n entry.severity = dpeWorstSeverity(entry.diagnostics);\r\n grouped.set(nodeName, entry);\r\n }\r\n return grouped;\r\n}\r\n\r\n/**\r\n * Le diagnostiche che **non** appartengono a nessun nodo (radice, parametri, sequenza dei\r\n * writeback, grafo intero). Esistono come funzione a se' perche' il pannello deve mostrarle:\r\n * un `DPE_GRAPH_NO_WRITEBACK` che scompare perche' non ha un nodo a cui attaccarsi sarebbe la\r\n * diagnostica piu' importante di tutte a non arrivare all'utente.\r\n */\r\nexport function dpeDefinitionLevelDiagnostics(\r\n diagnostics: readonly Diagnostic[],\r\n definition?: DpeDefinition,\r\n): Diagnostic[] {\r\n return diagnostics.filter(\r\n (diagnostic) => dpeDiagnosticNodeName(diagnostic, definition) === undefined,\r\n );\r\n}\r\n\r\n/** Testo leggibile del percorso, per la riga del pannello. */\r\nexport function dpeDiagnosticLocationLabel(\r\n diagnostic: Diagnostic,\r\n definition?: DpeDefinition,\r\n): string {\r\n const node = dpeDiagnosticNodeName(diagnostic, definition);\r\n const segments = diagnostic.path?.segments ?? [];\r\n const tail = segments\r\n .slice(1)\r\n .map((segment) => {\r\n const index = segment.index === undefined ? '' : `[${segment.index}]`;\r\n return `${segment.collection ?? ''}${segment.name ? `/${segment.name}` : index}`;\r\n })\r\n .filter((part) => part.length > 0);\r\n const field = diagnostic.path?.field;\r\n return [node ?? 'definizione', ...tail, field].filter(Boolean).join(' › ');\r\n}\r\n\r\n/** I nomi dei nodi presenti nella definizione: serve a chi naviga dal pannello al canvas. */\r\nexport function dpeKnownNodeNames(definition: DpeDefinition): Set<string> {\r\n return new Set(dpeAllNodes(definition).map((located) => located.node.name));\r\n}\r\n","/**\r\n * Le coordinate di un nodo sul canvas — ADR 0013.\r\n *\r\n * Vivono in `extensionData` sotto la chiave namespaced `dpe:layout`, forma `{x, y}`. Il\r\n * backend le conserva senza interpretarle (**I7**), la validazione non le guarda, il\r\n * compilatore non le vede: l'unico livello che gli da' significato e' l'editor.\r\n *\r\n * Due regole dell'ADR sono implementate qui, e sono le sole che contano:\r\n *\r\n * - le coordinate sono **opzionali**: una definizione scritta a mano non le ha e resta\r\n * valida; in loro assenza si esegue dagre;\r\n * - un `dpe:layout` **malformato o parziale si ignora**. Un documento arrivato da un'altra\r\n * versione non deve poter rompere il canvas, e \"meta' coordinata\" non e' una posizione:\r\n * accettarla metterebbe il nodo a `x` giusta e `y` zero, cioe' in un posto che nessuno ha\r\n * scelto.\r\n */\r\n\r\nimport { DpeAnyNode, DpeExtensionData } from '../model/dpe-definition.model';\r\n\r\n/** La chiave e' namespaced perche' `extensionData` e' anche dove atterrano i campi futuri. */\r\nexport const DPE_LAYOUT_KEY = 'dpe:layout';\r\n\r\nexport interface DpeNodePosition {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/** Legge la posizione, oppure `undefined` se assente o non utilizzabile. */\r\nexport function dpeReadNodePosition(node: DpeAnyNode): DpeNodePosition | undefined {\r\n const raw = node.extensionData?.[DPE_LAYOUT_KEY];\r\n if (raw === null || typeof raw !== 'object') {\r\n return undefined;\r\n }\r\n const candidate = raw as { x?: unknown; y?: unknown };\r\n // `Number.isFinite` e non `typeof === 'number'`: `NaN` e `Infinity` sono numeri per\r\n // TypeScript e coordinate impossibili per il canvas, dove finirebbero in una trasform CSS\r\n // invalida — il nodo semplicemente non si vede, senza nessun errore.\r\n if (!Number.isFinite(candidate.x) || !Number.isFinite(candidate.y)) {\r\n return undefined;\r\n }\r\n return { x: candidate.x as number, y: candidate.y as number };\r\n}\r\n\r\n/** Scrive la posizione producendo un nuovo nodo: il documento resta immutabile. */\r\nexport function dpeWriteNodePosition<TNode extends DpeAnyNode>(\r\n node: TNode,\r\n position: DpeNodePosition,\r\n): TNode {\r\n const extensionData: DpeExtensionData = {\r\n ...(node.extensionData ?? {}),\r\n [DPE_LAYOUT_KEY]: { x: Math.round(position.x), y: Math.round(position.y) },\r\n };\r\n return { ...node, extensionData };\r\n}\r\n\r\n/** Vero quando **tutti** i nodi hanno una posizione: se no, il canvas rifa' il layout. */\r\nexport function dpeHasCompleteLayout(nodes: readonly DpeAnyNode[]): boolean {\r\n return nodes.length > 0 && nodes.every((node) => dpeReadNodePosition(node) !== undefined);\r\n}\r\n","/**\r\n * Catalogo delle categorie di nodo: etichetta italiana, collezione JSON di appartenenza,\r\n * numero di sorgenti ammesse.\r\n *\r\n * **Descrittivo, non normativo.** Serve alla palette e alle etichette dell'interfaccia. Non\r\n * e' validazione: che un `AppendNode` con una sola sorgente sia sbagliato lo dice il backend,\r\n * non questo file, e i due non devono mai diventare due fonti di verita' in disaccordo. I\r\n * conteggi qui sotto servono a decidere **quante porte disegnare**, che e' una domanda di\r\n * rendering.\r\n */\r\n\r\nimport { DpeNodeCollectionName } from '../model/dpe-definition.model';\r\n\r\nexport interface DpeNodeCategory {\r\n /** Collezione JSON della radice: e' anche la chiave con cui si legge il documento. */\r\n collection: DpeNodeCollectionName;\r\n /** Etichetta breve, per la palette e per l'intestazione della card sul canvas. */\r\n label: string;\r\n /** Una riga di spiegazione, per il tooltip della palette. */\r\n description: string;\r\n /** Numero minimo di sorgenti che il nodo dichiara (0 per i punti d'ingresso). */\r\n minSources: number;\r\n /** Numero massimo, `undefined` = illimitato (`Append`, `CustomNode`). */\r\n maxSources?: number;\r\n /** Vero per i punti d'ingresso del grafo. */\r\n isSource: boolean;\r\n /** Vero per i sink: producono l'artefatto, non uno schema. */\r\n isSink: boolean;\r\n /**\r\n * Vero dove il backend rifiuta la compilazione pur accettando il modello (**I10**): la UI\r\n * deve poter avvisare **prima** che l'utente costruisca la pipeline intorno a un nodo che\r\n * non arrivera' all'SQL. Non e' una regola di dominio riprodotta: e' l'informazione che\r\n * `docs/domain-model.md` dichiara esplicitamente per queste due categorie, e la\r\n * diagnostica autorevole resta `DPE_NODE_NOT_COMPILABLE` del backend.\r\n */\r\n isNotCompilableInV1: boolean;\r\n}\r\n\r\nexport const DPE_NODE_CATEGORIES: readonly DpeNodeCategory[] = [\r\n {\r\n collection: 'dataSources',\r\n label: 'Sorgente',\r\n description: 'Punto d’ingresso: tabella del provider di metadati, CSV o dataset esterno.',\r\n minSources: 0,\r\n maxSources: 0,\r\n isSource: true,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'filters',\r\n label: 'Filtro',\r\n description: 'Seleziona le righe con criteri combinati, oppure con un filtro dinamico da parametro.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'joins',\r\n label: 'Join',\r\n description: 'Unisce due sorgenti su una o piu’ chiavi; lo schema di uscita e’ esplicito.',\r\n minSources: 2,\r\n maxSources: 2,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'aggregates',\r\n label: 'Aggregazione',\r\n description: 'Raggruppa e calcola funzioni di aggregazione; senza raggruppamento produce una riga.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'transforms',\r\n label: 'Trasformazione',\r\n description: 'Aggiunge colonne calcolate, ne elimina, oppure calcola valori relativi a una partizione.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'appends',\r\n label: 'Unione',\r\n description: 'Impila N sorgenti; con schemi disgiunti le colonne mancanti diventano nulle.',\r\n minSources: 2,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'hierarchyPaths',\r\n label: 'Percorso gerarchico',\r\n description: 'Risale una gerarchia padre/figlio e produce la colonna di percorso; richiede CTE ricorsive.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'forecasts',\r\n label: 'Previsione',\r\n description: 'Modellata per intero ma non traducibile in SQL nella versione 1.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: true,\r\n },\r\n {\r\n collection: 'customNodes',\r\n label: 'Nodo personalizzato',\r\n description: 'Estensione esterna con schema di uscita dichiarato; non traducibile in SQL nella versione 1.',\r\n minSources: 1,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: true,\r\n },\r\n {\r\n collection: 'writebacks',\r\n label: 'Scrittura',\r\n description: 'Sink: produce l’istruzione SQL per l’host, oppure un file JSON o CSV.',\r\n minSources: 1,\r\n maxSources: 1,\r\n isSource: false,\r\n isSink: true,\r\n isNotCompilableInV1: false,\r\n },\r\n {\r\n collection: 'atomicWritebacks',\r\n label: 'Gruppo atomico',\r\n description: 'Dichiara che alcune scritture vanno applicate dall’host nella stessa transazione.',\r\n minSources: 0,\r\n isSource: false,\r\n isSink: true,\r\n isNotCompilableInV1: false,\r\n },\r\n];\r\n\r\nconst BY_COLLECTION = new Map<DpeNodeCollectionName, DpeNodeCategory>(\r\n DPE_NODE_CATEGORIES.map((category) => [category.collection, category]),\r\n);\r\n\r\nexport function dpeNodeCategory(collection: DpeNodeCollectionName): DpeNodeCategory {\r\n const category = BY_COLLECTION.get(collection);\r\n if (!category) {\r\n // Non raggiungibile: la mappa copre `DpeNodeCollectionName` per costruzione. Il ripiego\r\n // esiste perche' aggiungere una collezione al modello senza aggiungerla qui non deve\r\n // produrre una card senza etichetta e senza spiegazione.\r\n return {\r\n collection,\r\n label: collection,\r\n description: '',\r\n minSources: 0,\r\n isSource: false,\r\n isSink: false,\r\n isNotCompilableInV1: false,\r\n };\r\n }\r\n return category;\r\n}\r\n\r\n/** Nomi dei dialetti per il selettore. La libreria conosce **solo** il nome (ADR 0009). */\r\nexport const DPE_DIALECT_LABELS: Readonly<Record<string, string>> = {\r\n Sqlite: 'SQLite',\r\n SqlServer: 'SQL Server',\r\n PostgreSql: 'PostgreSQL',\r\n Oracle: 'Oracle',\r\n};\r\n","/**\r\n * Creazione di un nodo nuovo: nome candidato e valori iniziali per categoria.\r\n *\r\n * Non e' validazione e non e' dominio. Serve a una cosa sola: un nodo appena rilasciato sul\r\n * canvas deve essere **rappresentabile** e distinguibile, cioe' avere un nome e un'etichetta.\r\n * Tutto il resto lo compila l'utente nell'ispettore, e cosa sia obbligatorio lo dice il\r\n * backend.\r\n *\r\n * Il nome candidato e' unico rispetto ai nomi già presenti con confronto **esatto**\r\n * (`contracts.md` §2: unicita' verificata `OrdinalIgnoreCase`, risoluzione `Ordinal`). Qui il\r\n * confronto e' insensibile al caso di proposito: proporre `Filtro2` accanto a un `filtro2`\r\n * esistente creerebbe un `DPE_MODEL_NAME_DUPLICATE` a nome dell'editor, non dell'utente.\r\n */\r\n\r\nimport {\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n} from '../model/dpe-definition.model';\r\nimport { dpeAllNodes } from './dpe-graph';\r\nimport { dpeNodeCategory } from './dpe-node-catalog';\r\n\r\n/** Radice del nome proposto per categoria: identificatori, quindi senza spazi ne' accenti. */\r\nconst NAME_STEM: Readonly<Record<DpeNodeCollectionName, string>> = {\r\n dataSources: 'Sorgente',\r\n filters: 'Filtro',\r\n joins: 'Join',\r\n aggregates: 'Aggregazione',\r\n transforms: 'Trasformazione',\r\n appends: 'Unione',\r\n hierarchyPaths: 'Gerarchia',\r\n forecasts: 'Previsione',\r\n customNodes: 'NodoCustom',\r\n writebacks: 'Scrittura',\r\n atomicWritebacks: 'GruppoAtomico',\r\n};\r\n\r\n/** Il primo nome libero della forma `<radice><n>`. */\r\nexport function dpeProposeNodeName(\r\n definition: DpeDefinition,\r\n collection: DpeNodeCollectionName,\r\n): string {\r\n const used = new Set(dpeAllNodes(definition).map((located) => located.node.name.toLowerCase()));\r\n const stem = NAME_STEM[collection];\r\n let index = 1;\r\n while (used.has(`${stem}${index}`.toLowerCase())) {\r\n index += 1;\r\n }\r\n return `${stem}${index}`;\r\n}\r\n\r\n/**\r\n * Il nodo iniziale di una categoria. I campi obbligatori senza un valore sensato restano\r\n * **assenti**, non riempiti con un segnaposto: un `tableName` finto passerebbe la forma e\r\n * fallirebbe sul provider di metadati con un errore che l'utente non ha causato.\r\n */\r\nexport function dpeCreateNode<K extends DpeNodeCollectionName>(\r\n definition: DpeDefinition,\r\n collection: K,\r\n): DpeNodeCollectionMap[K] {\r\n const name = dpeProposeNodeName(definition, collection);\r\n const label = `${dpeNodeCategory(collection).label} ${name.replace(/^\\D+/, '')}`;\r\n const base = { name, label };\r\n\r\n switch (collection) {\r\n case 'dataSources':\r\n return { ...base, kind: 'Table', fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'joins':\r\n return { ...base, kind: 'Inner', keys: [], fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'aggregates':\r\n return { ...base, fields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'transforms':\r\n return { ...base, kind: 'Expression', expressionFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'appends':\r\n // Due posizioni vuote: un'unione nasce con due ingressi da collegare, ed e' anche cio'\r\n // che fa comparire due porte sul canvas invece di nessuna.\r\n return { ...base, sources: ['', ''] } as unknown as DpeNodeCollectionMap[K];\r\n case 'customNodes':\r\n return { ...base, sources: [''], extensionName: '', outputFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'forecasts':\r\n return { ...base, aggregationFields: [] } as unknown as DpeNodeCollectionMap[K];\r\n case 'writebacks':\r\n return {\r\n ...base,\r\n target: 'Database',\r\n operation: 'Insert',\r\n sequence: dpeProposeWritebackSequence(definition),\r\n fields: [],\r\n } as unknown as DpeNodeCollectionMap[K];\r\n case 'atomicWritebacks':\r\n return {\r\n ...base,\r\n sequence: dpeProposeWritebackSequence(definition),\r\n relationships: [],\r\n } as unknown as DpeNodeCollectionMap[K];\r\n default:\r\n return base as unknown as DpeNodeCollectionMap[K];\r\n }\r\n}\r\n\r\n/**\r\n * La sequenza dei sink e' univoca fra writeback e gruppi atomici: si propone la prima libera.\r\n * L'unicita' la verifica il backend (`DPE_WRITEBACK_SEQUENCE_DUPLICATE`) — questo e' solo un\r\n * valore iniziale che non collide, non un controllo.\r\n */\r\nexport function dpeProposeWritebackSequence(definition: DpeDefinition): number {\r\n const used = new Set<number>();\r\n for (const node of [...(definition.writebacks ?? []), ...(definition.atomicWritebacks ?? [])]) {\r\n used.add(node.sequence);\r\n }\r\n let sequence = 1;\r\n while (used.has(sequence)) {\r\n sequence += 1;\r\n }\r\n return sequence;\r\n}\r\n\r\n/** Etichetta di sintesi mostrata sulla card del nodo, sotto il nome. */\r\nexport function dpeNodeSubtitle(collection: DpeNodeCollectionName, node: DpeAnyNode): string | null {\r\n const record = node as unknown as Record<string, unknown>;\r\n switch (collection) {\r\n case 'dataSources':\r\n return (record['tableName'] as string) || (record['externalDatasetName'] as string) || null;\r\n case 'joins':\r\n return (record['kind'] as string) || null;\r\n case 'transforms':\r\n return (record['kind'] as string) || null;\r\n case 'aggregates': {\r\n const fields = (record['fields'] as unknown[] | undefined)?.length ?? 0;\r\n return fields ? `${fields} ${fields === 1 ? 'funzione' : 'funzioni'}` : null;\r\n }\r\n case 'filters':\r\n return record['isDynamic'] === true ? 'dinamico' : (record['condition'] as string) || null;\r\n case 'writebacks': {\r\n const target = record['target'] as string | undefined;\r\n const table = record['tableName'] as string | undefined;\r\n return [target, table].filter(Boolean).join(' · ') || null;\r\n }\r\n case 'atomicWritebacks': {\r\n const relationships = (record['relationships'] as unknown[] | undefined)?.length ?? 0;\r\n return relationships ? `${relationships} relazioni` : null;\r\n }\r\n default:\r\n return null;\r\n }\r\n}\r\n","/**\r\n * Lo stato dell'editor: la definizione in memoria e' **la fonte di verita'**.\r\n *\r\n * `@Injectable()` **senza `providedIn`**: e' un provider del componente radice dell'editor,\r\n * non della root. Due editor sulla stessa pagina devono poter editare due definizioni\r\n * indipendenti, e con un servizio in root ne condividerebbero una — compresi undo/redo e\r\n * selezione.\r\n *\r\n * Stato **immutabile e unidirezionale**: ogni mutazione produce un nuovo valore della\r\n * definizione, nessuno muta l'oggetto in luogo. Da lì viene gratis l'undo/redo (istantanee\r\n * JSON), che non e' una funzionalita' aggiunta dopo ma una conseguenza.\r\n *\r\n * Cosa **non** fa questo store, e non e' una dimenticanza: non valida, non calcola schemi,\r\n * non risolve riferimenti, non sa cosa un dialetto supporti. Diagnostiche, schemi, ordine di\r\n * esecuzione e sequenza dei writeback **arrivano dal backend** e qui si depositano\r\n * (`applyValidateResult`). L'unica logica presente e' strutturale: dove vivono i riferimenti\r\n * e come si riscrivono, che sta in `dpe-graph.ts`.\r\n */\r\n\r\nimport { Injectable, computed, signal } from '@angular/core';\r\n\r\nimport {\r\n DPE_NODE_COLLECTIONS,\r\n DpeAnyNode,\r\n DpeDefinition,\r\n DpeNodeCollectionMap,\r\n DpeNodeCollectionName,\r\n SqlDialectKind,\r\n} from '../model/dpe-definition.model';\r\nimport { Diagnostic } from '../model/dpe-diagnostics.model';\r\nimport {\r\n DpeCompileResult,\r\n DpeNodeSchemaInfo,\r\n DpeValidateResult,\r\n DpeWritebackStep,\r\n} from '../model/dpe-api.model';\r\nimport {\r\n DpeGraph,\r\n dpeAllNodes,\r\n dpeBuildGraph,\r\n dpeCountReferences,\r\n dpeFindNode,\r\n dpeRenameNode,\r\n dpeWriteSourceReference,\r\n} from './dpe-graph';\r\nimport {\r\n DpeNodeDiagnostics,\r\n dpeDefinitionLevelDiagnostics,\r\n dpeGroupDiagnosticsByNode,\r\n} from './dpe-diagnostics.util';\r\nimport { DpeNodePosition, dpeReadNodePosition, dpeWriteNodePosition } from './dpe-node-layout';\r\nimport { dpeCreateNode } from './dpe-node-factory';\r\n\r\n/** Profondita' della cronologia: oltre, le istantanee piu' vecchie si buttano. */\r\nconst HISTORY_LIMIT = 100;\r\n\r\n/** Una definizione vuota ma **leggibile**: `formatVersion` e `dialect` non sono opzionali. */\r\nexport function dpeEmptyDefinition(\r\n name: string,\r\n label: string,\r\n dialect: SqlDialectKind,\r\n): DpeDefinition {\r\n return { formatVersion: 1, name, label, dialect };\r\n}\r\n\r\n@Injectable()\r\nexport class DpeDocumentStore {\r\n private readonly _definition = signal<DpeDefinition>(dpeEmptyDefinition('', '', 'Sqlite'));\r\n private readonly _validateResult = signal<DpeValidateResult | undefined>(undefined);\r\n private readonly _compileResult = signal<DpeCompileResult | undefined>(undefined);\r\n /**\r\n * I nodi selezionati, in ordine di gesto. E' una **lista** e non un nome singolo perche' il\r\n * canvas sa selezionare piu' nodi (riquadro, `Ctrl+A`) e trascinarli insieme: tenere qui un solo\r\n * nome costringerebbe la libreria a conservare gli altri, cioe' a essere di nuovo autorevole\r\n * sulla selezione.\r\n */\r\n private readonly _selectedNodeNames = signal<readonly string[]>([]);\r\n private readonly _past = signal<readonly string[]>([]);\r\n private readonly _future = signal<readonly string[]>([]);\r\n /**\r\n * Istantanea di riferimento: l'ultimo stato **salvato**. Non e' un contatore di operazioni.\r\n * Contare le mutazioni sembra equivalente e non lo e': dopo un `undo` il contatore sale, cioe'\r\n * dichiara piu' modifiche di prima proprio quando l'utente ne ha disfatta una. Serve a decidere\r\n * se salvare, quindi deve rispondere alla domanda giusta — \"differisce da cio' che e' salvato?\"\r\n * — e tornare a \"no\" quando si annulla fino allo stato di partenza.\r\n */\r\n private readonly _savedSnapshot = signal<string>(\r\n JSON.stringify(dpeEmptyDefinition('', '', 'Sqlite')),\r\n );\r\n\r\n /** La definizione corrente: unica fonte di verita' per canvas, ispettori e pannelli. */\r\n readonly definition = this._definition.asReadonly();\r\n\r\n /** Nodi e archi derivati dalla definizione. Ricalcolati solo quando la definizione cambia. */\r\n readonly graph = computed<DpeGraph>(() => dpeBuildGraph(this._definition()));\r\n\r\n readonly selectedNodeNames = this._selectedNodeNames.asReadonly();\r\n\r\n /** Insieme dei selezionati: il canvas lo interroga una volta per nodo a ogni render. */\r\n readonly selectedNodeNameSet = computed<ReadonlySet<string>>(\r\n () => new Set(this._selectedNodeNames()),\r\n );\r\n\r\n /**\r\n * Il nodo che l'ispettore mostra: il **primo** della selezione. Un ispettore per piu' nodi\r\n * insieme mostrerebbe campi che appartengono a nodi diversi, che e' peggio di non mostrarne.\r\n */\r\n readonly selectedNodeName = computed<string | undefined>(() => this._selectedNodeNames().at(0));\r\n\r\n readonly selectedNode = computed<DpeAnyNode | undefined>(() => {\r\n const name = this.selectedNodeName();\r\n return name === undefined ? undefined : dpeFindNode(this._definition(), name)?.node;\r\n });\r\n\r\n // --- cio' che arriva dal backend ------------------------------------------\r\n\r\n readonly validateResult = this._validateResult.asReadonly();\r\n readonly compileResult = this._compileResult.asReadonly();\r\n\r\n readonly diagnostics = computed<readonly Diagnostic[]>(\r\n () => this._validateResult()?.diagnostics ?? [],\r\n );\r\n\r\n readonly schemas = computed<readonly DpeNodeSchemaInfo[]>(\r\n () => this._validateResult()?.schemas ?? [],\r\n );\r\n\r\n readonly executionOrder = computed<readonly string[]>(\r\n () => this._validateResult()?.executionOrder ?? [],\r\n );\r\n\r\n readonly writebackSequence = computed<readonly DpeWritebackStep[]>(\r\n () => this._validateResult()?.writebackSequence ?? [],\r\n );\r\n\r\n /** Schema per nome di nodo: la vista dello schema lo cerca per nodo, non per posizione. */\r\n readonly schemaByNode = computed<ReadonlyMap<string, DpeNodeSchemaInfo>>(() => {\r\n const map = new Map<string, DpeNodeSchemaInfo>();\r\n for (const schema of this.schemas()) {\r\n map.set(schema.nodeName, schema);\r\n }\r\n return map;\r\n });\r\n\r\n /**\r\n * Diagnostiche raggruppate per nodo, piu' quelle che **non** appartengono a nessun nodo\r\n * (radice, parametri, grafo intero): tenerle separate e' l'unico modo perche' un\r\n * `DPE_GRAPH_NO_WRITEBACK` non scompaia solo perche' non ha un nodo a cui attaccarsi.\r\n */\r\n readonly diagnosticsByNode = computed<ReadonlyMap<string, DpeNodeDiagnostics>>(() =>\r\n dpeGroupDiagnosticsByNode(this.diagnostics(), this._definition()),\r\n );\r\n\r\n readonly definitionDiagnostics = computed<readonly Diagnostic[]>(() =>\r\n dpeDefinitionLevelDiagnostics(this.diagnostics(), this._definition()),\r\n );\r\n\r\n /** Posizioni lette da `dpe:layout` (ADR 0013): assenti dove il documento non le porta. */\r\n readonly positions = computed<ReadonlyMap<string, DpeNodePosition>>(() => {\r\n const map = new Map<string, DpeNodePosition>();\r\n for (const located of dpeAllNodes(this._definition())) {\r\n const position = dpeReadNodePosition(located.node);\r\n if (position) {\r\n map.set(located.node.name, position);\r\n }\r\n }\r\n return map;\r\n });\r\n\r\n readonly canUndo = computed(() => this._past().length > 0);\r\n readonly canRedo = computed(() => this._future().length > 0);\r\n\r\n /**\r\n * Vero quando il documento differisce dall'ultimo salvataggio. Il confronto e' fra istantanee\r\n * JSON — la stessa moneta dell'undo/redo — e **non** un conteggio di differenze: un elenco di\r\n * differenze costa quanto un diff strutturale, e nessuno lo legge come numero.\r\n *\r\n * Confronto testuale, quindi sensibile all'ordine delle chiavi. Le mutazioni producono nuovi\r\n * valori per spread, che l'ordine lo conserva, e l'undo riparte dalla stessa serializzazione:\r\n * l'unico esito possibile di una divergenza d'ordine sarebbe un falso \"modificata\", cioe' un\r\n * salvataggio in piu' e mai una perdita.\r\n */\r\n readonly isDirty = computed(() => JSON.stringify(this._definition()) !== this._savedSnapshot());\r\n\r\n // -------------------------------------------------------------------------\r\n // Caricamento e risultati del backend\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Sostituisce la definizione. Azzera la cronologia: le istantanee della definizione\r\n * precedente non sono passi di quella nuova, e un undo che riportasse a un altro documento\r\n * sarebbe una perdita di dati che l'utente non ha chiesto.\r\n */\r\n load(definition: DpeDefinition): void {\r\n this._definition.set(definition);\r\n // Cio' che e' appena arrivato **e'** lo stato salvato: aprire un documento non lo sporca.\r\n this._savedSnapshot.set(JSON.stringify(definition));\r\n this._past.set([]);\r\n this._future.set([]);\r\n this._selectedNodeNames.set([]);\r\n this._validateResult.set(undefined);\r\n this._compileResult.set(undefined);\r\n }\r\n\r\n /** Deposita il risultato della validazione. Nessuna interpretazione: si mostra cio' che c'e'. */\r\n applyValidateResult(result: DpeValidateResult | undefined): void {\r\n this._validateResult.set(result);\r\n }\r\n\r\n applyCompileResult(result: DpeCompileResult | undefined): void {\r\n this._compileResult.set(result);\r\n }\r\n\r\n /**\r\n * L'ospite ha salvato: da qui in poi il riferimento e' il documento **effettivamente\r\n * persistito**, che si passa come argomento.\r\n *\r\n * Il parametro non e' un vezzo: un salvataggio e' asincrono, e nel frattempo l'utente puo'\r\n * avere continuato a scrivere. Fissando il riferimento sullo stato *corrente* si dichiarerebbe\r\n * salvato anche cio' che e' stato scritto dopo l'invio, cioe' esattamente il lavoro che si\r\n * perderebbe. Omesso, vale lo stato corrente: e' il caso di chi salva in modo sincrono.\r\n */\r\n markSaved(saved?: DpeDefinition): void {\r\n this._savedSnapshot.set(JSON.stringify(saved ?? this._definition()));\r\n }\r\n\r\n /**\r\n * **L'unico** punto che decide quale nodo e' selezionato. La selezione ha una sola fonte di\r\n * verita', come la definizione: la classe nel DOM e lo stato di selezione della libreria di\r\n * canvas ne **derivano**, non la stabiliscono. Due scritture indipendenti sullo stesso fatto\r\n * producono due nodi selezionati insieme e un utente che non sa su cosa sta agendo.\r\n */\r\n select(nodeName: string | undefined): void {\r\n this._selectedNodeNames.set(nodeName === undefined ? [] : [nodeName]);\r\n }\r\n\r\n /** Selezione multipla (riquadro, `Ctrl+A`): la lista che arriva dal gesto, senza duplicati. */\r\n selectMany(nodeNames: readonly string[]): void {\r\n this._selectedNodeNames.set(Array.from(new Set(nodeNames)));\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Mutazioni — sincrone e granulari\r\n // -------------------------------------------------------------------------\r\n\r\n /** Proprieta' della radice: etichetta, descrizione, dialetto, parametri. */\r\n patchDefinition(patch: Partial<DpeDefinition>): void {\r\n this.commit({ ...this._definition(), ...patch });\r\n }\r\n\r\n addNode<K extends DpeNodeCollectionName>(collection: K, node: DpeNodeCollectionMap[K]): void {\r\n const definition = this._definition();\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n this.commit(this.withCollection(definition, collection, [...existing, node]));\r\n }\r\n\r\n updateNode<K extends DpeNodeCollectionName>(\r\n collection: K,\r\n nodeName: string,\r\n patch: Partial<DpeNodeCollectionMap[K]>,\r\n ): void {\r\n const definition = this._definition();\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n let changed = false;\r\n const next = existing.map((node) => {\r\n if (node.name !== nodeName) {\r\n return node;\r\n }\r\n changed = true;\r\n // `name` non si cambia da qui: rinominare e' un refactoring globale e passa da\r\n // `renameNode`. Lasciarlo passare in un patch produrrebbe un documento con tutti i\r\n // riferimenti a valle rotti e nessun segnale.\r\n const { name: _ignored, ...rest } = patch as Partial<DpeNodeCollectionMap[K]> & { name?: string };\r\n void _ignored;\r\n return { ...node, ...rest };\r\n });\r\n if (!changed) {\r\n return;\r\n }\r\n this.commit(this.withCollection(definition, collection, next));\r\n }\r\n\r\n /**\r\n * Rimuove un nodo. I riferimenti a valle **restano** e diventano riferimenti rotti: e' cio'\r\n * che il documento dice davvero, e il backend li segnala (`DPE_REF_UNKNOWN_NODE`). Pulirli\r\n * qui vorrebbe dire decidere al posto dell'utente che quel filtro non serve piu'.\r\n */\r\n removeNode(nodeName: string): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, nodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.filter((node) => node.name !== nodeName);\r\n this.commit(this.withCollection(definition, located.collection, next));\r\n // Un nome che non esiste piu' non puo' restare selezionato: sarebbe una selezione che punta\r\n // al vuoto. Si riscrive solo se serve, perche' un nuovo array uguale al precedente farebbe\r\n // ripartire per nulla chi osserva la selezione.\r\n const selected = this._selectedNodeNames();\r\n if (selected.includes(nodeName)) {\r\n this._selectedNodeNames.set(selected.filter((name) => name !== nodeName));\r\n }\r\n }\r\n\r\n /**\r\n * L'**unico** punto che rinomina un nodo (**I5**): delega alla funzione pura, che aggiorna\r\n * ogni riferimento a valle passando dall'unico elenco di slot.\r\n */\r\n renameNode(oldName: string, newName: string): void {\r\n if (oldName === newName || newName.length === 0) {\r\n return;\r\n }\r\n this.commit(dpeRenameNode(this._definition(), oldName, newName));\r\n // La selezione segue la rinomina: identifica un nodo per nome, e il nome e' cambiato.\r\n const selected = this._selectedNodeNames();\r\n if (selected.includes(oldName)) {\r\n this._selectedNodeNames.set(selected.map((name) => (name === oldName ? newName : name)));\r\n }\r\n }\r\n\r\n /** Quante occorrenze toccherebbe una rinomina: si dice prima, non dopo. */\r\n countReferences(nodeName: string): number {\r\n return dpeCountReferences(this._definition(), nodeName);\r\n }\r\n\r\n /**\r\n * Crea un nodo della categoria data nella posizione indicata e restituisce il nome\r\n * assegnato, cosi' chi lo ha creato puo' selezionarlo subito.\r\n */\r\n createNodeAt<K extends DpeNodeCollectionName>(collection: K, position: DpeNodePosition): string {\r\n const definition = this._definition();\r\n const node = dpeWriteNodePosition(dpeCreateNode(definition, collection), position);\r\n const existing = (definition[collection] ?? []) as DpeNodeCollectionMap[K][];\r\n this.commit(this.withCollection(definition, collection, [...existing, node]));\r\n return node.name;\r\n }\r\n\r\n /**\r\n * Sposta un nodo scrivendo `dpe:layout`. `silent` non aggiunge un passo di cronologia:\r\n * trascinare cinque nodi insieme e' **un** gesto, e cinque passi di undo per un solo\r\n * trascinamento sono cinque passi che l'utente non ha fatto.\r\n */\r\n moveNode(nodeName: string, position: DpeNodePosition, options?: { silent?: boolean }): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, nodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.map((node) =>\r\n node.name === nodeName ? dpeWriteNodePosition(node, position) : node,\r\n );\r\n const updated = this.withCollection(definition, located.collection, next);\r\n if (options?.silent) {\r\n this._definition.set(updated);\r\n return;\r\n }\r\n this.commit(updated);\r\n }\r\n\r\n /**\r\n * Applica un layout calcolato **su comando dell'utente** («Riordina»): un passo di cronologia\r\n * per l'intero riordino, e il documento risulta modificato, perche' lo e'.\r\n */\r\n applyPositions(positions: ReadonlyMap<string, DpeNodePosition>): void {\r\n this.commit(this.withPositions(this._definition(), positions));\r\n }\r\n\r\n /**\r\n * Layout **iniziale** di un documento che non porta coordinate (ADR 0013: sono opzionali).\r\n *\r\n * Non e' una modifica dell'utente: non entra nella cronologia e **ri-fissa l'istantanea di\r\n * riferimento**, cosi' aprire un documento non produce «modificata». Un indicatore che dice\r\n * «modificata» appena si apre insegna a ignorarlo, e un indicatore ignorato e' peggio di\r\n * nessun indicatore. Il prezzo accettato: chi chiude senza salvare perde le coordinate\r\n * calcolate, che dagre rigenera in modo deterministico.\r\n *\r\n * Il riferimento si sposta **solo** se il documento non era gia' modificato: se l'utente ha\r\n * scritto qualcosa, un layout non puo' dichiarare salvato il suo lavoro.\r\n */\r\n applyInitialPositions(positions: ReadonlyMap<string, DpeNodePosition>): void {\r\n const wasClean = !this.isDirty();\r\n const next = this.withPositions(this._definition(), positions);\r\n this._definition.set(next);\r\n if (wasClean) {\r\n this._savedSnapshot.set(JSON.stringify(next));\r\n }\r\n }\r\n\r\n /**\r\n * Collega una porta di ingresso di `targetNodeName` al nodo `sourceName`. Non verifica che\r\n * il collegamento sia lecito: cicli (**I2**) e riferimenti a valle (**I3**) li rifiuta il\r\n * backend, e l'errore compare subito perche' la validazione parte dopo la mutazione.\r\n */\r\n connect(\r\n targetNodeName: string,\r\n slot: string,\r\n sourceName: string,\r\n index?: number,\r\n ): void {\r\n this.writeReference(targetNodeName, slot, index, sourceName);\r\n }\r\n\r\n /** Scollega una porta: lo slot torna vuoto, non a stringa vuota. */\r\n disconnect(targetNodeName: string, slot: string, index?: number): void {\r\n this.writeReference(targetNodeName, slot, index, undefined);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Cronologia\r\n // -------------------------------------------------------------------------\r\n\r\n undo(): void {\r\n const past = this._past();\r\n if (past.length === 0) {\r\n return;\r\n }\r\n const snapshot = past[past.length - 1];\r\n this._past.set(past.slice(0, -1));\r\n this._future.set([...this._future(), JSON.stringify(this._definition())]);\r\n this._definition.set(JSON.parse(snapshot) as DpeDefinition);\r\n }\r\n\r\n redo(): void {\r\n const future = this._future();\r\n if (future.length === 0) {\r\n return;\r\n }\r\n const snapshot = future[future.length - 1];\r\n this._future.set(future.slice(0, -1));\r\n this._past.set([...this._past(), JSON.stringify(this._definition())]);\r\n this._definition.set(JSON.parse(snapshot) as DpeDefinition);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Interno\r\n // -------------------------------------------------------------------------\r\n\r\n private writeReference(\r\n targetNodeName: string,\r\n slot: string,\r\n index: number | undefined,\r\n sourceName: string | undefined,\r\n ): void {\r\n const definition = this._definition();\r\n const located = dpeFindNode(definition, targetNodeName);\r\n if (!located) {\r\n return;\r\n }\r\n const existing = (definition[located.collection] ?? []) as DpeAnyNode[];\r\n const next = existing.map((node) =>\r\n node.name === targetNodeName\r\n ? dpeWriteSourceReference(located.collection, node, slot, index, sourceName)\r\n : node,\r\n );\r\n this.commit(this.withCollection(definition, located.collection, next));\r\n }\r\n\r\n /** Scrive le posizioni su tutte le collezioni producendo una nuova definizione. */\r\n private withPositions(\r\n definition: DpeDefinition,\r\n positions: ReadonlyMap<string, DpeNodePosition>,\r\n ): DpeDefinition {\r\n let next = definition;\r\n for (const collection of DPE_NODE_COLLECTIONS) {\r\n const nodes = next[collection] as DpeAnyNode[] | undefined;\r\n if (!nodes || nodes.length === 0) {\r\n continue;\r\n }\r\n const updated = nodes.map((node) => {\r\n const position = positions.get(node.name);\r\n return position ? dpeWriteNodePosition(node, position) : node;\r\n });\r\n next = this.withCollection(next, collection, updated);\r\n }\r\n return next;\r\n }\r\n\r\n /**\r\n * Sostituisce una collezione producendo una nuova definizione. Il cast e' confinato qui:\r\n * TypeScript non correla la chiave di collezione con il tipo di nodo dentro un accesso\r\n * dinamico, e la mappa dei tipi serve ai chiamanti, non a questa riga.\r\n */\r\n private withCollection(\r\n definition: DpeDefinition,\r\n collection: DpeNodeCollectionName,\r\n nodes: readonly unknown[],\r\n ): DpeDefinition {\r\n return { ...definition, [collection]: nodes.slice() } as DpeDefinition;\r\n }\r\n\r\n private commit(next: DpeDefinition): void {\r\n const snapshot = JSON.stringify(this._definition());\r\n const past = [...this._past(), snapshot];\r\n this._past.set(past.length > HISTORY_LIMIT ? past.slice(past.length - HISTORY_LIMIT) : past);\r\n // Una nuova mutazione chiude il ramo di redo: tenerlo sarebbe una cronologia ad albero,\r\n // che nessun comando dell'editor sa percorrere.\r\n this._future.set([]);\r\n this._definition.set(next);\r\n }\r\n}\r\n","/**\r\n * Lo stato del **catalogo** delle definizioni (ADR 0019): elenco, esiti delle chiamate, comandi.\r\n *\r\n * `@Injectable()` **senza `providedIn`**, come gli altri store: e' un provider del componente\r\n * radice della schermata di catalogo, non della root dell'applicazione. Due cataloghi in due\r\n * punti dell'ospite sono due elenchi indipendenti.\r\n *\r\n * Sta in `core/` e **non conosce il DOM**: e' il posto in cui un difetto e' silenzioso — una\r\n * chiamata mancata, un `refresh` che non parte dopo una scrittura, un errore assorbito — e quindi\r\n * il posto che ha bisogno di essere testabile senza browser.\r\n *\r\n * Cosa questo store **non** fa, e non e' una dimenticanza:\r\n *\r\n * - **non riordina** i sommari: l'ordine e' quello che l'ospite ha restituito (`contracts.md` §7),\r\n * e riordinarlo lato client combatterebbe una scelta che l'ospite ha gia' fatto;\r\n * - **non filtra**: il filtro di testo e' locale al componente, sui sommari gia' ricevuti;\r\n * - **non calcola** `nodeCount` ne' `hasErrors`: sono fatti riportati dall'ospite, e dedurli qui\r\n * sarebbe una validazione fatta dal client per interposta persona;\r\n * - **non carica documenti**: aprire e' dell'ospite, che potrebbe instradare o controllare\r\n * permessi. Il catalogo emette un nome.\r\n */\r\n\r\nimport { DestroyRef, Injectable, computed, inject, signal } from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EMPTY, Observable, catchError, switchMap, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { DpeApiError } from '../api/dpe-api-error';\r\nimport { DpeDefinitionSummary } from '../model/dpe-api.model';\r\nimport { SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { dpeCreateCommandAvailability, dpeReadCapabilities } from './dpe-capabilities';\r\nimport { dpeEmptyDefinition } from './dpe-document.store';\r\n\r\n@Injectable()\r\nexport class DpeCatalogStore {\r\n private readonly api = inject(DpeBuilderApi);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n /**\r\n * Le primitive disponibili, fotografate **alla costruzione** per identita' del metodo\r\n * (`dpe-capabilities.ts`). La disponibilita' si sa prima del clic: un comando che sembra attivo\r\n * e fallisce alla pressione insegna a non fidarsi dei bottoni.\r\n */\r\n readonly capabilities = dpeReadCapabilities(this.api);\r\n\r\n /** Il comando di creazione dipende da **due** primitive, e il motivo va mostrato. */\r\n readonly createCommand = dpeCreateCommandAvailability(this.capabilities);\r\n\r\n private readonly _summaries = signal<readonly DpeDefinitionSummary[]>([]);\r\n private readonly _isLoading = signal(false);\r\n private readonly _isMutating = signal(false);\r\n private readonly _error = signal<DpeApiError | null>(null);\r\n private readonly _hasLoaded = signal(false);\r\n private readonly _environmentDialect = signal<SqlDialectKind | undefined>(undefined);\r\n\r\n /** Nell'ordine restituito dall'ospite, mai riordinato. */\r\n readonly summaries = this._summaries.asReadonly();\r\n\r\n /**\r\n * Due stati distinti e non uno: **elencare** e **scrivere** si vedono diversi. Un unico\r\n * \"occupato\" farebbe lampeggiare l'elenco a ogni cancellazione, e nasconderebbe il fatto che\r\n * dopo una scrittura l'elenco si ricarica.\r\n */\r\n readonly isLoading = this._isLoading.asReadonly();\r\n readonly isMutating = this._isMutating.asReadonly();\r\n\r\n readonly error = this._error.asReadonly();\r\n\r\n /** Vero dopo la prima risposta: prima, un elenco vuoto non significa «nessuna definizione». */\r\n readonly hasLoaded = this._hasLoaded.asReadonly();\r\n\r\n /**\r\n * Il dialetto **dichiarato dall'ambiente** (ADR 0017), che e' quello con cui nasce una\r\n * definizione creata da qui. Non si chiede all'utente e non si sceglie per ripiego: senza\r\n * dichiarazione il comando di creazione resta spento (`createCommand`).\r\n */\r\n readonly environmentDialect = this._environmentDialect.asReadonly();\r\n\r\n readonly isEmpty = computed(() => this._hasLoaded() && this._summaries().length === 0);\r\n\r\n constructor() {\r\n // L'elenco si chiede all'apertura: un catalogo che mostra righe solo dopo un clic su\r\n // «Aggiorna» e' un catalogo che sembra vuoto.\r\n this.refresh();\r\n\r\n // La dichiarazione dell'ambiente e' un fatto dell'installazione: si chiede una volta. Un\r\n // guasto qui non e' un errore del catalogo — resta il comportamento di `getEnvironment`\r\n // assente, cioe' creazione spenta.\r\n if (this.capabilities.getEnvironment) {\r\n this.api\r\n .getEnvironment()\r\n .pipe(\r\n tap((environment) => this._environmentDialect.set(environment.dialect)),\r\n catchError(() => EMPTY),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n }\r\n\r\n /**\r\n * Ricarica l'elenco. Senza `listDefinitions` non e' un errore: e' un ambiente che non offre il\r\n * catalogo, e chi rende lo dice guardando `capabilities.listDefinitions`.\r\n */\r\n refresh(): void {\r\n if (!this.capabilities.listDefinitions) {\r\n return;\r\n }\r\n this._isLoading.set(true);\r\n this._error.set(null);\r\n this.api\r\n .listDefinitions()\r\n .pipe(\r\n tap((summaries) => {\r\n this._summaries.set(summaries);\r\n this._isLoading.set(false);\r\n this._hasLoaded.set(true);\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isLoading.set(false))),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /**\r\n * Crea una definizione **subito**, non al primo salvataggio: `save` significa «scrivi questa\r\n * definizione» e non distingue inserimento da aggiornamento, quindi solo `createDefinition` da'\r\n * all'ospite il punto in cui rifiutare un nome duplicato. Una definizione che esiste solo nel\r\n * browser e' inoltre uno stato che l'elenco non puo' mostrare.\r\n *\r\n * Il dialetto arriva dall'ambiente e non dall'utente (ADR 0017): lo passa il chiamante, che lo\r\n * legge da `environmentDialect`.\r\n *\r\n * L'osservabile e' **freddo**: chi comanda si iscrive **una volta** e riceve il sommario che\r\n * l'ospite ha restituito — non quello costruito qui, perche' il nome puo' essere stato\r\n * normalizzato.\r\n */\r\n create(name: string, label: string, dialect: SqlDialectKind): Observable<DpeDefinitionSummary> {\r\n return this.mutate(this.api.createDefinition(dpeEmptyDefinition(name, label, dialect)));\r\n }\r\n\r\n /**\r\n * Duplica: `load` **e poi** `createDefinition`. Non esiste una primitiva di duplicazione sul\r\n * contratto, e non deve esistere — si comporrebbe di queste due comunque, e una primitiva\r\n * dedicata dovrebbe ridecidere lato host cosa cambia.\r\n *\r\n * Il dialetto e' quello della **definizione di partenza**, non quello dell'ambiente: le\r\n * espressioni sono SQL nativo (ADR 0006) e cambiare dialetto duplicando sarebbe una migrazione\r\n * silenziosa.\r\n */\r\n duplicate(\r\n sourceName: string,\r\n name: string,\r\n label: string,\r\n ): Observable<DpeDefinitionSummary> {\r\n return this.mutate(\r\n this.api\r\n .load(sourceName)\r\n .pipe(switchMap((source) => this.api.createDefinition({ ...source, name, label }))),\r\n );\r\n }\r\n\r\n /** Cancella per nome e ricarica l'elenco. La conferma e' della schermata, non dello store. */\r\n remove(name: string): void {\r\n if (!this.capabilities.deleteDefinition) {\r\n return;\r\n }\r\n this._isMutating.set(true);\r\n this._error.set(null);\r\n this.api\r\n .deleteDefinition(name)\r\n .pipe(\r\n tap(() => {\r\n this._isMutating.set(false);\r\n this.refresh();\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isMutating.set(false))),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n dismissError(): void {\r\n this._error.set(null);\r\n }\r\n\r\n /**\r\n * Il tratto comune delle due scritture: stato di attesa, **`refresh` dopo il successo** — un\r\n * elenco che omette cio' che l'utente ha appena creato e' un elenco che mente — ed errore nel\r\n * signal invece che propagato. Chi comanda non deve trattare l'errore due volte.\r\n */\r\n private mutate(source: Observable<DpeDefinitionSummary>): Observable<DpeDefinitionSummary> {\r\n this._error.set(null);\r\n return source.pipe(\r\n tap({\r\n subscribe: () => this._isMutating.set(true),\r\n next: () => {\r\n this._isMutating.set(false);\r\n this.refresh();\r\n },\r\n }),\r\n catchError((error: unknown) => this.fail(error, () => this._isMutating.set(false))),\r\n );\r\n }\r\n\r\n /** Un errore del provider finisce in `error()` e **non lancia**: nessuno lo raccoglierebbe. */\r\n private fail(error: unknown, reset: () => void): Observable<never> {\r\n reset();\r\n this._error.set(this.toApiError(error));\r\n return EMPTY;\r\n }\r\n\r\n /** Cio' che l'host non categorizza diventa `Transport`, la categoria \"riprovabile\". */\r\n private toApiError(error: unknown): DpeApiError {\r\n if (DpeApiError.is(error)) {\r\n return error;\r\n }\r\n const message = error instanceof Error ? error.message : 'Errore inatteso dal backend.';\r\n return new DpeApiError('Transport', message, error);\r\n }\r\n}\r\n","/**\r\n * Layout automatico del DAG con dagre.\r\n *\r\n * Due cose non ovvie, ed entrambe sono il motivo per cui esiste questo involucro invece di\r\n * chiamare dagre dai componenti:\r\n *\r\n * 1. **dagre ragiona in centri**, il canvas vuole l'angolo in alto a sinistra. La conversione\r\n * sta qui, una volta: fatta a valle, in ogni chiamante, sbaglia di mezzo nodo e il\r\n * disallineamento si nota solo a occhio;\r\n * 2. **dagre non e' ESM**: sta in `allowedCommonJsDependencies` di `angular.json`, altrimenti\r\n * la build avvisa a ogni compilazione.\r\n *\r\n * Input minimale di proposito: nomi e misure, piu' gli archi. Il servizio non conosce il\r\n * documento e non lo scrive — restituisce le posizioni, e chi lo invoca decide cosa farne.\r\n */\r\n\r\nimport { Injectable } from '@angular/core';\r\nimport dagre from 'dagre';\r\n\r\nexport interface DpeLayoutNodeInput {\r\n name: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface DpeLayoutEdgeInput {\r\n /** Nome del nodo a monte. */\r\n from: string;\r\n /** Nome del nodo a valle. */\r\n to: string;\r\n /** Identificatore dell'arco: dagre ne ha bisogno per ammettere archi paralleli. */\r\n id: string;\r\n}\r\n\r\nexport interface DpeLayoutPosition {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport type DpeLayoutDirection = 'TB' | 'LR';\r\n\r\nexport interface DpeLayoutOptions {\r\n /** Default `TB`: i dati scendono dalle sorgenti ai sink. */\r\n direction?: DpeLayoutDirection;\r\n /** Distanza fra i livelli. */\r\n rankSeparation?: number;\r\n /** Distanza fra i nodi dello stesso livello. */\r\n nodeSeparation?: number;\r\n /** Angolo in alto a sinistra del grafo risultante. */\r\n origin?: DpeLayoutPosition;\r\n}\r\n\r\n@Injectable()\r\nexport class DpeLayoutService {\r\n /**\r\n * Calcola le posizioni. La chiave della mappa e' il **nome** del nodo, non il suo id sul\r\n * canvas: il nome e' cio' che identifica un nodo nel documento, e passare dall'id\r\n * costringerebbe questo servizio a conoscere la costruzione degli id.\r\n */\r\n layout(\r\n nodes: readonly DpeLayoutNodeInput[],\r\n edges: readonly DpeLayoutEdgeInput[],\r\n options?: DpeLayoutOptions,\r\n ): Map<string, DpeLayoutPosition> {\r\n const origin = options?.origin ?? { x: 60, y: 60 };\r\n\r\n const graph = new dagre.graphlib.Graph({ multigraph: true, compound: false });\r\n graph.setGraph({\r\n rankdir: options?.direction ?? 'TB',\r\n ranksep: options?.rankSeparation ?? 90,\r\n nodesep: options?.nodeSeparation ?? 60,\r\n marginx: 0,\r\n marginy: 0,\r\n });\r\n graph.setDefaultEdgeLabel(() => ({}));\r\n\r\n const known = new Set<string>();\r\n for (const node of nodes) {\r\n graph.setNode(node.name, { width: node.width, height: node.height });\r\n known.add(node.name);\r\n }\r\n\r\n for (const edge of edges) {\r\n // Un arco con un capo sconosciuto e' un riferimento rotto: si disegna comunque sul\r\n // canvas, ma non vincola il layout — dagre creerebbe un nodo fantasma con misure zero.\r\n if (!known.has(edge.from) || !known.has(edge.to)) {\r\n continue;\r\n }\r\n graph.setEdge(edge.from, edge.to, {}, edge.id);\r\n }\r\n\r\n dagre.layout(graph);\r\n\r\n const positions = new Map<string, DpeLayoutPosition>();\r\n let minX = Number.POSITIVE_INFINITY;\r\n let minY = Number.POSITIVE_INFINITY;\r\n\r\n for (const node of nodes) {\r\n const laid = graph.node(node.name) as { x?: number; y?: number } | undefined;\r\n if (!laid || laid.x === undefined || laid.y === undefined) {\r\n continue;\r\n }\r\n const x = laid.x - node.width / 2;\r\n const y = laid.y - node.height / 2;\r\n positions.set(node.name, { x, y });\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n }\r\n\r\n // Trasla il grafo sull'origine scelta: dagre puo' produrre coordinate negative, e un nodo\r\n // a coordinate negative finisce fuori dall'area visibile appena il canvas si apre.\r\n if (Number.isFinite(minX) && Number.isFinite(minY)) {\r\n const deltaX = origin.x - minX;\r\n const deltaY = origin.y - minY;\r\n for (const [name, position] of positions) {\r\n positions.set(name, {\r\n x: Math.round(position.x + deltaX),\r\n y: Math.round(position.y + deltaY),\r\n });\r\n }\r\n }\r\n\r\n return positions;\r\n }\r\n}\r\n","/**\r\n * Cache locale del provider di metadati dell'host.\r\n *\r\n * Tabelle e campi arrivano da `DpeBuilderApi`, cioe' dal **provider dell'host** e non dai\r\n * cataloghi del database (ADR 0004). Due cose che questa cache non fa, di proposito:\r\n *\r\n * - **non appiattisce i tre esiti**. `Declared`, `DeclaredWithoutFields` (\"la tabella c'e', i\r\n * campi non li so\") e `Unknown` restano distinti fino alla UI: chi vede una tendina vuota\r\n * deve poter sapere quale dei tre casi sta guardando, perche' nel secondo il nome del campo\r\n * si digita a mano e non c'e' niente da correggere;\r\n * - **non giudica**. Se una tabella non e' nel catalogo, il rilievo autorevole\r\n * (`DPE_REF_UNKNOWN_TABLE`) arriva dalla validazione; qui si sa solo che non si sa.\r\n *\r\n * L'elenco delle tabelle puo' essere grande: si chiede una volta, si tiene, e chi lo mostra\r\n * filtra invece di riversarlo in un `<select>`.\r\n */\r\n\r\nimport { Injectable, inject, signal } from '@angular/core';\r\nimport { catchError, of, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { TableDescriptor, TableLookupOutcome, TableSummary } from '../model/dpe-api.model';\r\n\r\nexport interface DpeTableState {\r\n outcome: TableLookupOutcome;\r\n table?: TableDescriptor;\r\n}\r\n\r\n@Injectable()\r\nexport class DpeMetadataStore {\r\n private readonly api = inject(DpeBuilderApi);\r\n\r\n private readonly _tables = signal<readonly TableSummary[]>([]);\r\n private readonly _isLoadingTables = signal(false);\r\n private readonly _tablesRequested = signal(false);\r\n private readonly _byName = signal<ReadonlyMap<string, DpeTableState>>(new Map());\r\n private readonly pending = new Set<string>();\r\n\r\n readonly tables = this._tables.asReadonly();\r\n readonly isLoadingTables = this._isLoadingTables.asReadonly();\r\n\r\n /** Idempotente: la prima chiamata carica, le successive non fanno nulla. */\r\n loadTables(): void {\r\n if (this._tablesRequested()) {\r\n return;\r\n }\r\n this._tablesRequested.set(true);\r\n this._isLoadingTables.set(true);\r\n this.api\r\n .getTables()\r\n .pipe(\r\n tap((tables) => {\r\n this._tables.set(tables);\r\n this._isLoadingTables.set(false);\r\n }),\r\n catchError(() => {\r\n // Elenco vuoto significa \"non lo so\", non \"nessuna tabella\": la UI lascia digitare\r\n // il nome invece di impedire di scriverlo.\r\n this._isLoadingTables.set(false);\r\n return of([]);\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /** Stato noto di una tabella, se già richiesta. */\r\n stateOf(tableName: string): DpeTableState | undefined {\r\n return this._byName().get(tableName);\r\n }\r\n\r\n /** Chiede la descrizione di una tabella una sola volta per nome. */\r\n describe(tableName: string): void {\r\n if (!tableName || this.pending.has(tableName) || this._byName().has(tableName)) {\r\n return;\r\n }\r\n this.pending.add(tableName);\r\n this.api\r\n .getTable(tableName)\r\n .pipe(\r\n tap((result) => {\r\n this.pending.delete(tableName);\r\n this.put(tableName, { outcome: result.outcome, table: result.table });\r\n }),\r\n catchError(() => {\r\n this.pending.delete(tableName);\r\n // Un guasto di trasporto non e' `Unknown`: `Unknown` e' una risposta del provider.\r\n // Non si registra nulla, cosi' un tentativo successivo riprova.\r\n return of(undefined);\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n private put(tableName: string, state: DpeTableState): void {\r\n const next = new Map(this._byName());\r\n next.set(tableName, state);\r\n this._byName.set(next);\r\n }\r\n}\r\n","/**\r\n * I tracciati SVG delle icone di categoria, uno per collezione di nodi.\r\n *\r\n * **Perche' tracciati e non glifi Unicode** (divergenza motivata dal progetto di riferimento,\r\n * `frontend.md` §3-ter): i glifi non hanno metriche ne' linea di base coerenti fra loro e su\r\n * alcune piattaforme diventano emoji a colori — cioe' proprio la resa sbagliata quando stanno\r\n * in colonna in una palette. Un tracciato disegnato su una griglia 24x24 con `currentColor` si\r\n * colora con una sola regola CSS e vale identico in tema chiaro e scuro.\r\n *\r\n * **Nessun asset e nessuna dipendenza**: sono stringhe, e il componente che le rende le lega con\r\n * `[attr.d]` senza mai toccare `innerHTML` — quindi niente `bypassSecurityTrust*`.\r\n *\r\n * Il disegno e' pensato per la resa a **16px**: pochi tratti, nessun dettaglio sotto i 2 px di\r\n * griglia, e sagome che restano distinguibili l'una dall'altra quando sono incolonnate.\r\n */\r\n\r\nimport { DpeNodeCollectionName } from '../model/dpe-definition.model';\r\nimport { dpeNodeCategory } from './dpe-node-catalog';\r\n\r\n/**\r\n * La famiglia cromatica di una categoria. **Non e' una tassonomia nuova**: si deriva per intero\r\n * da `isSource`/`isSink`/`isNotCompilableInV1` del catalogo, che restano l'unica descrizione dei\r\n * tipi di nodo. Serve solo a scegliere un colore.\r\n */\r\nexport type DpeNodeIconFamily = 'source' | 'transform' | 'sink' | 'uncompilable';\r\n\r\nexport function dpeNodeIconFamily(collection: DpeNodeCollectionName): DpeNodeIconFamily {\r\n const category = dpeNodeCategory(collection);\r\n if (category.isSource) {\r\n return 'source';\r\n }\r\n if (category.isSink) {\r\n return 'sink';\r\n }\r\n // Dopo sorgenti e scritture: un sink non compilabile non esiste, e se un giorno esistesse\r\n // resterebbe piu' utile vederlo come sink.\r\n if (category.isNotCompilableInV1) {\r\n return 'uncompilable';\r\n }\r\n return 'transform';\r\n}\r\n\r\n/** Classe CSS della famiglia: un solo posto la costruisce, cosi' i fogli restano allineati. */\r\nexport function dpeNodeIconFamilyClass(collection: DpeNodeCollectionName): string {\r\n return `dpe-family--${dpeNodeIconFamily(collection)}`;\r\n}\r\n\r\n/**\r\n * I tracciati, per collezione. Ogni voce e' l'elenco degli attributi `d` di un `<path>`; il\r\n * contorno e' `stroke`, mai `fill`, cosi' l'icona pesa uguale su qualunque sfondo.\r\n */\r\nexport const DPE_NODE_ICON_PATHS: Readonly<Record<DpeNodeCollectionName, readonly string[]>> = {\r\n // Cilindro di database: ellisse superiore, fianchi, e la riga di mezzo che lo fa leggere\r\n // come un solido invece che come un ovale con due gambe.\r\n dataSources: [\r\n 'M4 6a8 3 0 1 0 16 0a8 3 0 1 0 -16 0',\r\n 'M4 6v12c0 1.66 3.58 3 8 3s8-1.34 8-3V6',\r\n 'M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3',\r\n ],\r\n // Imbuto.\r\n filters: ['M3 4h18l-7 8.5V20l-4-2v-5.5z'],\r\n // Due cerchi che si intersecano: ogni cerchio e' due archi da 180 gradi. I centri stanno a 7\r\n // unita' e il raggio e' 4.5: con una sovrapposizione maggiore, a 16px, si leggevano come un\r\n // cerchio con un anello dentro invece che come due insiemi che si incrociano.\r\n joins: ['M8.5 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 1 0 0-9', 'M15.5 7.5a4.5 4.5 0 1 0 0 9 4.5 4.5 0 1 0 0-9'],\r\n // Tre barre di altezza diversa. Rettangoli e non segmenti: a 16px un segmento verticale\r\n // spesso 2 non si distingue da una barra sottile, e l'insieme si confonde con l'unione.\r\n aggregates: ['M4 11h4v9H4z', 'M10 5h4v15h-4z', 'M16 14h4v6h-4z'],\r\n // Due frecce affiancate in versi opposti.\r\n transforms: ['M3 8h13', 'M12 4l4 4-4 4', 'M21 16H8', 'M12 12l-4 4 4 4'],\r\n // Due lastre impilate.\r\n appends: ['M4 5h16v5H4z', 'M4 14h16v5H4z'],\r\n // Albero: un nodo in alto, due sotto, collegati.\r\n hierarchyPaths: ['M9 3h6v4H9z', 'M12 7v3', 'M6 10h12', 'M6 10v3', 'M18 10v3', 'M3 13h6v4H3z', 'M15 13h6v4h-6z'],\r\n // Spezzata crescente, con la punta che dichiara la direzione.\r\n forecasts: ['M21 7l-8 8-4-4-6 6', 'M15 7h6v6'],\r\n // Tassello di puzzle: una bozza sopra, un incavo a destra. Due sole sporgenze e non quattro —\r\n // a 16px il tassello \"completo\" diventava un quadrato con quattro tacche indistinguibili.\r\n customNodes: ['M4 4h5.5a2.5 2.5 0 0 1 5 0H20v5.5a2.5 2.5 0 0 0 0 5V20H4z'],\r\n // Freccia che entra in un contenitore.\r\n writebacks: ['M12 3v10', 'M8 9l4 4 4-4', 'M4 14v4a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-4'],\r\n // Lo stesso contenitore, con un lucchetto al posto della freccia.\r\n atomicWritebacks: [\r\n 'M10 7V5.5a2 2 0 0 1 4 0V7',\r\n 'M8.5 7h7v5h-7z',\r\n 'M4 15v3a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-3',\r\n ],\r\n};\r\n\r\n/**\r\n * I tracciati di una collezione. Il ripiego vuoto non e' pigrizia: una collezione aggiunta al\r\n * modello e non ancora disegnata deve produrre una pastiglia vuota, non un errore in console\r\n * ne' un `undefined` dentro `[attr.d]`.\r\n */\r\nexport function dpeNodeIconPaths(collection: DpeNodeCollectionName): readonly string[] {\r\n return DPE_NODE_ICON_PATHS[collection] ?? [];\r\n}\r\n","/**\r\n * Il ponte fra il documento e il backend: valida in modo **debounced**, chiede l'anteprima SQL su\r\n * comando e salva su comando.\r\n *\r\n * Il salvataggio sta qui e non in un componente per la stessa ragione degli altri due: nessun\r\n * componente conosce il trasporto. Che il nome della classe sia piu' stretto della sua\r\n * responsabilita' e' un debito segnalato all'architect, non una svista.\r\n *\r\n * Perche' il debounce non e' un dettaglio: la chiamata al service DPE e' sincrona nel\r\n * backend, cioe' occupa il chiamante finche' non termina. Incatenarne una a ogni battitura\r\n * significa una coda di lavori che nessuno leggera' — e nel frattempo l'editor mostra un\r\n * risultato vecchio. Qui si aspetta la pausa di digitazione, si annulla la richiesta in volo\r\n * quando ne parte una nuova (`switchMap`), e si mostra sempre lo stato di attesa.\r\n *\r\n * L'editing resta **sincrono** mentre una validazione e' in volo: il documento e' la fonte di\r\n * verita', le diagnostiche arrivano dopo e non bloccano niente.\r\n *\r\n * Provider del componente radice come gli store: montare due editor non deve significare due\r\n * servizi che validano lo stesso documento.\r\n */\r\n\r\nimport { DestroyRef, Injectable, computed, inject, signal } from '@angular/core';\r\nimport { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { EMPTY, catchError, debounceTime, of, switchMap, tap } from 'rxjs';\r\n\r\nimport { DpeBuilderApi } from '../api/dpe-builder-api';\r\nimport { DpeApiError } from '../api/dpe-api-error';\r\nimport { DpeParameterValue } from '../model/dpe-api.model';\r\nimport { SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { dpeReadCapabilities } from './dpe-capabilities';\r\nimport { DpeDocumentStore } from './dpe-document.store';\r\n\r\n/** Pausa di digitazione oltre la quale vale la pena chiedere al backend. */\r\nconst VALIDATE_DEBOUNCE_MS = 400;\r\n\r\n/**\r\n * Durata dell'avviso di salvataggio riuscito. Transitorio di proposito: il fatto durevole e'\r\n * «nessuna modifica» nell'indicatore, e un avviso di successo che resta va poi chiuso a mano.\r\n */\r\nconst SAVE_NOTICE_MS = 2600;\r\n\r\n@Injectable()\r\nexport class DpeValidationService {\r\n private readonly api = inject(DpeBuilderApi);\r\n private readonly store = inject(DpeDocumentStore);\r\n private readonly destroyRef = inject(DestroyRef);\r\n\r\n private readonly _isValidating = signal(false);\r\n private readonly _isCompiling = signal(false);\r\n private readonly _error = signal<DpeApiError | undefined>(undefined);\r\n /**\r\n * Le primitive opzionali si sanno **alla costruzione**, per identita' del metodo\r\n * (`dpe-capabilities.ts`, `contracts.md` §7). Prima si partiva da «disponibile» e si scopriva\r\n * l'assenza dal primo `MissingService`: il comando sembrava attivo e falliva alla pressione,\r\n * che e' peggio di un comando disabilitato che ne dice il motivo.\r\n */\r\n private readonly capabilities = dpeReadCapabilities(this.api);\r\n private readonly _isPreviewAvailable = signal(this.capabilities.compilePreview);\r\n private readonly _isSaving = signal(false);\r\n /** Come l'anteprima: un host senza `save` disabilita il comando, non rompe l'editor. */\r\n private readonly _isSaveAvailable = signal(this.capabilities.save);\r\n /** Esito dell'ultimo salvataggio: transitorio al successo, persistente al fallimento. */\r\n private readonly _justSaved = signal(false);\r\n private readonly _saveError = signal<DpeApiError | undefined>(undefined);\r\n /**\r\n * Il dialetto **dichiarato dall'ambiente** (ADR 0017), quando l'host espone `getEnvironment`.\r\n * Non e' il dialetto con cui si compila — quello sta nella definizione — ed e' esattamente per\r\n * questo che i due si tengono separati: il confronto e' l'unica cosa che l'editor puo' dire.\r\n */\r\n private readonly _environmentDialect = signal<SqlDialectKind | undefined>(undefined);\r\n\r\n readonly isValidating = this._isValidating.asReadonly();\r\n readonly isCompiling = this._isCompiling.asReadonly();\r\n readonly error = this._error.asReadonly();\r\n readonly isPreviewAvailable = this._isPreviewAvailable.asReadonly();\r\n readonly isSaving = this._isSaving.asReadonly();\r\n readonly isSaveAvailable = this._isSaveAvailable.asReadonly();\r\n readonly justSaved = this._justSaved.asReadonly();\r\n readonly saveError = this._saveError.asReadonly();\r\n readonly environmentDialect = this._environmentDialect.asReadonly();\r\n\r\n /** Vero finche' non e' arrivata la prima risposta: la UI non deve dire \"nessun problema\". */\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n constructor() {\r\n toObservable(this.store.definition)\r\n .pipe(\r\n debounceTime(VALIDATE_DEBOUNCE_MS),\r\n tap(() => {\r\n this._isValidating.set(true);\r\n this._error.set(undefined);\r\n }),\r\n // `switchMap`: una definizione piu' recente rende inutile la risposta precedente, e\r\n // applicarla dopo mostrerebbe diagnostiche di un documento che non esiste piu'.\r\n switchMap((definition) =>\r\n this.api.validate(definition).pipe(\r\n tap((result) => {\r\n this.store.applyValidateResult(result);\r\n this._isValidating.set(false);\r\n }),\r\n catchError((error: unknown) => {\r\n this._isValidating.set(false);\r\n this._error.set(this.toApiError(error));\r\n // Le diagnostiche precedenti **restano**: cancellarle direbbe \"va tutto bene\"\r\n // proprio quando non lo sappiamo piu'.\r\n return EMPTY;\r\n }),\r\n ),\r\n ),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n\r\n // La dichiarazione dell'ambiente si chiede **una volta**, all'apertura: e' un fatto\r\n // dell'installazione, non cambia mentre si edita. Un guasto qui non si mostra come errore\r\n // dell'editor — senza dichiarazione l'editor si comporta come con `getEnvironment` assente.\r\n if (this.capabilities.getEnvironment) {\r\n this.api\r\n .getEnvironment()\r\n .pipe(\r\n tap((environment) => this._environmentDialect.set(environment.dialect)),\r\n catchError(() => EMPTY),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n // Il timer dell'avviso transitorio non deve sopravvivere all'editor: scriverebbe su un\r\n // signal di un componente distrutto.\r\n this.destroyRef.onDestroy(() => this.clearSaveNotice());\r\n }\r\n\r\n /** Anteprima dell'SQL. Opzionale sull'host: assente, il comando resta disabilitato. */\r\n requestPreview(parameterValues?: DpeParameterValue[]): void {\r\n if (!this._isPreviewAvailable()) {\r\n return;\r\n }\r\n this._isCompiling.set(true);\r\n this.api\r\n .compilePreview(this.store.definition(), parameterValues)\r\n .pipe(\r\n tap((result) => {\r\n this.store.applyCompileResult(result);\r\n this._isCompiling.set(false);\r\n }),\r\n catchError((error: unknown) => {\r\n this._isCompiling.set(false);\r\n const apiError = this.toApiError(error);\r\n if (apiError.category === 'MissingService') {\r\n this._isPreviewAvailable.set(false);\r\n } else {\r\n this._error.set(apiError);\r\n }\r\n return of(undefined);\r\n }),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n /**\r\n * Salvataggio attraverso `DpeBuilderApi.save` (opzionale, `contracts.md` §7). Al successo\r\n * **l'editor dichiara da se'** lo stato salvato: quando l'ospite espone il metodo, e' questo il\r\n * punto che sa se e' andato a buon fine.\r\n *\r\n * Si passa a `markSaved` **il documento inviato**, non quello corrente: se l'utente scrive\r\n * mentre il salvataggio e' in volo, quelle modifiche non sono state salvate e l'indicatore deve\r\n * continuare a dirlo.\r\n */\r\n save(): void {\r\n if (!this._isSaveAvailable() || this._isSaving()) {\r\n return;\r\n }\r\n const sent = this.store.definition();\r\n this._isSaving.set(true);\r\n this._saveError.set(undefined);\r\n this.api\r\n .save(sent)\r\n .pipe(\r\n tap(() => {\r\n this._isSaving.set(false);\r\n // `markSaved` **solo** qui: un salvataggio fallito che azzerasse l'indicatore\r\n // cancellerebbe la traccia di un lavoro che non e' stato scritto da nessuna parte.\r\n this.store.markSaved(sent);\r\n this.showSaveNotice();\r\n }),\r\n catchError((error: unknown) => {\r\n this._isSaving.set(false);\r\n const apiError = this.toApiError(error);\r\n if (apiError.category === 'MissingService') {\r\n // Non dovrebbe accadere: la disponibilita' e' nota prima del clic. Se accade, l'host\r\n // ha sovrascritto la primitiva per rifiutarla — si disabilita il comando invece di\r\n // riproporlo a ogni tentativo.\r\n this._isSaveAvailable.set(false);\r\n }\r\n // L'esito si **vede**: banner persistente con la categoria. Un salvataggio che\r\n // fallisce in silenzio e' peggio di nessun salvataggio.\r\n this._saveError.set(apiError);\r\n return of(undefined);\r\n }),\r\n takeUntilDestroyed(this.destroyRef),\r\n )\r\n .subscribe();\r\n }\r\n\r\n dismissError(): void {\r\n this._error.set(undefined);\r\n }\r\n\r\n dismissSaveError(): void {\r\n this._saveError.set(undefined);\r\n }\r\n\r\n private saveNoticeTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n private showSaveNotice(): void {\r\n this.clearSaveNotice();\r\n this._justSaved.set(true);\r\n this.saveNoticeTimer = setTimeout(() => {\r\n this.saveNoticeTimer = undefined;\r\n this._justSaved.set(false);\r\n }, SAVE_NOTICE_MS);\r\n }\r\n\r\n private clearSaveNotice(): void {\r\n if (this.saveNoticeTimer !== undefined) {\r\n clearTimeout(this.saveNoticeTimer);\r\n this.saveNoticeTimer = undefined;\r\n }\r\n this._justSaved.set(false);\r\n }\r\n\r\n /**\r\n * Un host che non usa `DpeApiError` non deve far esplodere l'editor: cio' che non e'\r\n * categorizzato diventa `Transport`, che e' la categoria \"riprovabile\".\r\n */\r\n private toApiError(error: unknown): DpeApiError {\r\n if (DpeApiError.is(error)) {\r\n return error;\r\n }\r\n const message = error instanceof Error ? error.message : 'Errore inatteso dal backend.';\r\n return new DpeApiError('Transport', message, error);\r\n }\r\n}\r\n","/**\r\n * Geometria della viewport: funzioni pure, nessun DOM.\r\n *\r\n * Serve a una sola domanda, che si pone quando si naviga da una diagnostica al nodo: **il nodo\r\n * e' interamente in vista?** Se lo e', non si sposta niente — una panoramica non richiesta\r\n * disorienta quanto la sua assenza. Se non lo e', si centra la **vista**, non il nodo: le\r\n * coordinate del documento non si toccano.\r\n *\r\n * Sta qui e non nel componente perche' e' esattamente il tipo di logica che si sbaglia in\r\n * silenzio (un `>` al posto di un `>=`, un margine dimenticato) e che si verifica senza browser.\r\n */\r\n\r\n/** Rettangolo in coordinate di schermo, la forma che `getBoundingClientRect` restituisce. */\r\nexport interface DpeRect {\r\n left: number;\r\n top: number;\r\n right: number;\r\n bottom: number;\r\n}\r\n\r\n/**\r\n * Vero quando `target` sta **interamente** dentro `view`, lasciando `margin` pixel di respiro su\r\n * ogni lato. Il margine non e' un vezzo: un nodo tangente al bordo e' tecnicamente visibile e\r\n * praticamente illeggibile, e senza respiro il criterio \"e' visibile\" scatterebbe anche quando\r\n * dell'ombra e del connettore di uscita non si vede nulla.\r\n */\r\nexport function dpeIsRectFullyVisible(target: DpeRect, view: DpeRect, margin = 0): boolean {\r\n return (\r\n target.left >= view.left + margin &&\r\n target.top >= view.top + margin &&\r\n target.right <= view.right - margin &&\r\n target.bottom <= view.bottom - margin\r\n );\r\n}\r\n","/**\r\n * L'icona di una categoria di nodo.\r\n *\r\n * Rende markup SVG **statico** e lega soltanto `[attr.d]` dei tracciati: nessun `innerHTML`,\r\n * quindi nessun bypass del sanitizer e nessuna dipendenza per le icone. `d` non e' un attributo\r\n * sensibile — e' l'unico punto in cui il dato entra nel markup, ed e' un dato nostro, non del\r\n * documento.\r\n *\r\n * `aria-hidden`: l'icona **non e' informazione**, l'etichetta accanto lo e' gia'. Annunciarla\r\n * farebbe leggere due volte la stessa cosa a chi usa uno screen reader.\r\n *\r\n * La stessa icona compare in tre posti — palette, card del canvas, intestazione dell'ispettore —\r\n * perche' cio' che si trascina deve assomigliare a cio' che compare.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\r\n\r\nimport { dpeNodeIconPaths } from '../../core/dpe-node-icons';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n@Component({\r\n selector: 'dpe-node-icon',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n width=\"16\"\r\n height=\"16\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n aria-hidden=\"true\"\r\n >\r\n <!-- track $index: i tracciati sono una lista ricalcolata, e due uguali sono legittimi. -->\r\n @for (path of paths(); track $index) {\r\n <path [attr.d]=\"path\" />\r\n }\r\n </svg>\r\n `,\r\n})\r\nexport class DpeNodeIconComponent {\r\n readonly collection = input.required<DpeNodeCollectionName>();\r\n\r\n protected readonly paths = computed(() => dpeNodeIconPaths(this.collection()));\r\n}\r\n","/**\r\n * View model del canvas.\r\n *\r\n * Gli **id** non si costruiscono qui: vengono da `core/dpe-graph.ts`, che e' l'unico posto che\r\n * li conosce. Qui stanno solo le misure, e stanno qui perche' servono a due consumatori che\r\n * devono concordare: il CSS che disegna la card e dagre che calcola il layout. Se divergono,\r\n * il layout automatico lascia i nodi sovrapposti.\r\n */\r\n\r\nimport { DiagnosticSeverity } from '../../model/dpe-diagnostics.model';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n/** Altezza nominale della card: non cambia con il numero di porte, che stanno in fila sopra. */\r\nexport const DPE_NODE_HEIGHT = 104;\r\n\r\n/**\r\n * Larghezza per numero di porte di ingresso. Le porte stanno in fila sul bordo **superiore**,\r\n * quindi e' la larghezza a dipendere dal loro numero.\r\n *\r\n * E' una tabella a scaglioni e non una formula perche' la larghezza si applica con una\r\n * **classe**: @foblex/flow riscrive l'attributo `style` del nodo a ogni riposizionamento e\r\n * qualunque `[style.width]` di Angular verrebbe cancellato al primo spostamento. I valori qui\r\n * e quelli di `.dpe-node--ports-N` nel CSS del componente devono restare uguali.\r\n */\r\nconst PORT_WIDTHS = [230, 230, 260, 320, 380];\r\n\r\nconst MAX_PORT_BUCKET = PORT_WIDTHS.length - 1;\r\n\r\nfunction portBucket(portCount: number): number {\r\n return Math.min(Math.max(portCount, 0), MAX_PORT_BUCKET);\r\n}\r\n\r\nexport function dpeNodeWidth(portCount: number): number {\r\n return PORT_WIDTHS[portBucket(portCount)];\r\n}\r\n\r\nexport function dpeNodeWidthClass(portCount: number): string {\r\n return `dpe-node--ports-${portBucket(portCount)}`;\r\n}\r\n\r\nexport interface DpeCanvasPort {\r\n id: string;\r\n slot: string;\r\n index?: number;\r\n /** Etichetta della porta: si mostra solo dove le porte sono piu' di una. */\r\n label: string;\r\n /** Nome collegato, assente se la porta e' libera. */\r\n sourceName?: string;\r\n /** Il nome collegato non corrisponde a nessun nodo: si dice sulla porta. */\r\n isBroken: boolean;\r\n}\r\n\r\nexport interface DpeCanvasNode {\r\n /** Nome nel documento: l'identita', anche per la selezione. */\r\n name: string;\r\n /** Id per il canvas, costruito da `dpeNodeId`. */\r\n id: string;\r\n collection: DpeNodeCollectionName;\r\n categoryLabel: string;\r\n label: string;\r\n subtitle: string | null;\r\n position: { x: number; y: number };\r\n ports: DpeCanvasPort[];\r\n showsPortLabels: boolean;\r\n widthClass: string;\r\n /**\r\n * Classe della famiglia cromatica (`dpe-family--*`): la calcola `core/dpe-node-icons.ts` dai\r\n * flag del catalogo. Sta nel view model e non nel template perche' e' la stessa che usa la\r\n * palette, e due modi di derivarla sarebbero due colori diversi per lo stesso tipo di nodo.\r\n */\r\n familyClass: string;\r\n outputPortId: string;\r\n /** I sink non producono uno schema: la porta di uscita non si disegna... */\r\n hasOutput: boolean;\r\n /** Gravita' peggiore fra le diagnostiche del nodo. */\r\n severity: DiagnosticSeverity | null;\r\n diagnosticCount: number;\r\n /**\r\n * Nodo **valido ma non compilabile** (**I10**): stato distinto da \"non valido\", con un\r\n * colore proprio. Sono due situazioni diverse e l'utente deve capire subito quale guarda.\r\n */\r\n isNotCompilable: boolean;\r\n /** Numero di colonne dello schema di uscita, quando il backend lo ha detto. */\r\n columnCount: number | null;\r\n}\r\n\r\nexport interface DpeCanvasEdge {\r\n id: string;\r\n sourceId: string;\r\n targetId: string;\r\n slot: string;\r\n}\r\n","/**\r\n * Il canvas del DAG.\r\n *\r\n * @foblex/flow in *classic mode*: la libreria disegna e riconosce i gesti, **lo stato resta\r\n * nostro**. Nodi e archi sono signal derivati da `DpeDocumentStore` attraverso\r\n * `core/dpe-graph.ts`, e ogni gesto e' una mutazione del documento.\r\n *\r\n * Cosa il canvas **non** fa: non decide se un collegamento sia lecito. Un ciclo (**I2**) o un\r\n * riferimento a valle (**I3**) li rifiuta il backend, e la diagnostica arriva subito perche' la\r\n * validazione parte dopo la mutazione. Disegnare solo cio' che il backend accetterebbe\r\n * richiederebbe di riprodurre qui la sua semantica: e' esattamente cio' che non facciamo.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport {\r\n EFConnectableSide,\r\n EFMarkerType,\r\n FCanvasComponent,\r\n FFlowComponent,\r\n FFlowModule,\r\n provideFFlow,\r\n withA11y,\r\n} from '@foblex/flow';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport {\r\n dpeAllNodes,\r\n dpeInputPorts,\r\n dpeNodeId,\r\n dpeOutputPortId,\r\n dpeParseInputPortId,\r\n dpeParseNodeId,\r\n dpeParseOutputPortId,\r\n} from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport { dpeIsRectFullyVisible } from '../../core/dpe-viewport';\r\nimport { dpeNodeSubtitle } from '../../core/dpe-node-factory';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\nimport {\r\n DPE_NODE_HEIGHT,\r\n DpeCanvasEdge,\r\n DpeCanvasNode,\r\n DpeCanvasPort,\r\n dpeNodeWidth,\r\n dpeNodeWidthClass,\r\n} from './dpe-canvas.model';\r\n\r\n/** Etichette delle porte di ingresso, per slot. Presentazione, non semantica. */\r\nconst PORT_LABELS: Readonly<Record<string, string>> = {\r\n source: 'Ingresso',\r\n primary: 'Primaria',\r\n secondary: 'Secondaria',\r\n sources: 'Sorgente',\r\n};\r\n\r\n/**\r\n * Respiro attorno al grafo inquadrato. Era 100 per lato: su un'area alta 590 px erano 200 px di\r\n * vuoto, cioe' un terzo dello spazio, e bastavano a spingere l'inquadratura sotto la soglia di\r\n * leggibilita' — quindi a farla saltare del tutto.\r\n *\r\n * Il valore verticale e' un filo piu' generoso di quello orizzontale, e non per estetica: la card\r\n * disegna piu' del rettangolo con cui e' misurata (le porte sporgono sopra, il connettore di\r\n * uscita sotto), e con un respiro simmetrico l'ultima card restava tangente al bordo inferiore —\r\n * misurato: un pixel fuori.\r\n */\r\nconst FIT_PADDING = { x: 44, y: 56 };\r\n\r\n/**\r\n * Scala minima con cui il canvas si apre. Sotto questa soglia le etichette della card — nome,\r\n * categoria, conteggio delle colonne — sono disegnate in un corpo che non si legge, e si apre al\r\n * 100% centrato lasciando all'utente lo zoom (rotella, `+`/`-`, minimappa, «Inquadra»).\r\n *\r\n * Il valore non e' arbitrario: il titolo della card e' 13px, quindi a 0,75 resta un corpo effettivo\r\n * di ~10px, il minimo che si legge. Era stato abbassato a 0.35 per soddisfare il criterio «nessun\r\n * nodo fuori dal riquadro all'apertura», criterio poi **ritirato** dal committente\r\n * (`docs/frontend.md` §3-ter): su un grafo grande si soddisfa solo rimpicciolendo fino\r\n * all'illeggibile — misurato sul seed della demo, scala 0,516 e titolo effettivo 6,7px. La\r\n * leggibilita' viene prima della vista d'insieme; la vista d'insieme resta a un clic, tramite\r\n * «Inquadra», che in questo ramo si mostra apposta.\r\n */\r\nconst MIN_INITIAL_SCALE = 0.75;\r\n\r\n/**\r\n * Respiro richiesto attorno al nodo perche' si consideri \"in vista\". Un nodo tangente al bordo\r\n * e' visibile e illeggibile: la panoramica scatta anche in quel caso.\r\n */\r\nconst REVEAL_MARGIN = 24;\r\n\r\n@Component({\r\n selector: 'dpe-canvas',\r\n standalone: true,\r\n imports: [FFlowModule, DpeNodeIconComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n templateUrl: './dpe-canvas.component.html',\r\n /**\r\n * Il layer da tastiera di @foblex/flow e' **opzionale**: senza `withA11y()` la libreria non\r\n * ascolta nessun tasto e `(fDeleteSelected)` — l'unico modo in cui annuncia «l'utente vuole\r\n * cancellare» — non viene mai emesso. Nessun errore: semplicemente `Canc` non fa niente.\r\n * Attiva anche frecce, `Ctrl+A`, `Escape`, zoom da tastiera, cioe' la meta' della\r\n * navigazione senza mouse che un editor a canvas deve avere.\r\n *\r\n * Provider **del componente**: montare il canvas non installa ascoltatori globali nell'app\r\n * ospite.\r\n */\r\n providers: [provideFFlow(withA11y())],\r\n})\r\nexport class DpeCanvasComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n /** Serve per misurare l'area disponibile prima di decidere la scala d'apertura. */\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n /** Marker \"all states\": senza, l'arco selezionato perde la punta. */\r\n readonly markerEnd = EFMarkerType.END_ALL_STATES;\r\n\r\n /**\r\n * Ingressi in alto, uscita in basso, **dichiarati**. Lasciando calcolare il lato, un arco\r\n * che risale (un nodo posizionato sopra la sua sorgente) esce di fianco e il grafo diventa\r\n * illeggibile.\r\n */\r\n readonly sides = EFConnectableSide;\r\n\r\n readonly isEditable = input(true);\r\n\r\n readonly nodeOpened = output<string>();\r\n readonly nodeDropped = output<{ collection: DpeNodeCollectionName; x: number; y: number }>();\r\n\r\n private readonly canvas = viewChild.required(FCanvasComponent);\r\n /**\r\n * Serve solo a **riallineare** la selezione della libreria a quella dello store: e' l'unico\r\n * punto che scrive nello stato di selezione di @foblex/flow.\r\n */\r\n private readonly flow = viewChild(FFlowComponent);\r\n private hasFramedOnce = false;\r\n\r\n /**\r\n * Visibilita' del comando «Inquadra». Non e' piu' «l'utente ha spostato la vista»: lo diventa\r\n * anche all'apertura quando l'editor rinuncia a inquadrare per non scendere sotto\r\n * `MIN_INITIAL_SCALE`. In quel caso la vista d'insieme non e' stata data, quindi il comando che\r\n * la offre deve essere raggiungibile — nasconderlo significherebbe toglierla e basta.\r\n */\r\n private readonly _isFitCommandVisible = signal(false);\r\n readonly isFitCommandVisible = this._isFitCommandVisible.asReadonly();\r\n\r\n readonly nodes = computed<DpeCanvasNode[]>(() => {\r\n const definition = this.store.definition();\r\n const positions = this.store.positions();\r\n const diagnostics = this.store.diagnosticsByNode();\r\n const schemas = this.store.schemaByNode();\r\n const known = new Set(this.store.graph().nodes.map((node) => node.name));\r\n\r\n // Si cammina la definizione, non il grafo: servono i nodi veri (etichetta, sintesi) e le\r\n // porte, che si leggono dagli slot del nodo.\r\n return dpeAllNodes(definition).map((located) => {\r\n const category = dpeNodeCategory(located.collection);\r\n const ports: DpeCanvasPort[] = dpeInputPorts(located).map((port) => ({\r\n id: port.id,\r\n slot: port.slot,\r\n index: port.index,\r\n label:\r\n port.index === undefined\r\n ? (PORT_LABELS[port.slot] ?? port.slot)\r\n : `${PORT_LABELS[port.slot] ?? port.slot} ${port.index + 1}`,\r\n sourceName: port.sourceName,\r\n // Un nome che non corrisponde a nessun nodo non e' disegnabile come arco — non\r\n // esiste il connettore da cui partirebbe — quindi si dice **sulla porta**. Nasconderlo\r\n // sarebbe l'unico modo di non vedere un riferimento rotto.\r\n isBroken: port.sourceName !== undefined && !known.has(port.sourceName),\r\n }));\r\n const name = located.node.name;\r\n const nodeDiagnostics = diagnostics.get(name);\r\n const schema = schemas.get(name);\r\n\r\n return {\r\n name,\r\n id: dpeNodeId(name),\r\n collection: located.collection,\r\n categoryLabel: category.label,\r\n label: located.node.label || name,\r\n subtitle: dpeNodeSubtitle(located.collection, located.node),\r\n position: positions.get(name) ?? { x: 0, y: 0 },\r\n ports,\r\n showsPortLabels: ports.length > 1,\r\n widthClass: dpeNodeWidthClass(ports.length),\r\n familyClass: dpeNodeIconFamilyClass(located.collection),\r\n outputPortId: dpeOutputPortId(name),\r\n hasOutput: !category.isSink,\r\n severity: nodeDiagnostics?.severity ?? null,\r\n diagnosticCount: nodeDiagnostics?.diagnostics.length ?? 0,\r\n // Due fonti concordi: la diagnostica del backend (autorevole) e lo schema, che porta\r\n // `isCompilable`. La categoria «non compilabile in v1» del catalogo e' solo un\r\n // suggerimento della palette e qui non basterebbe.\r\n isNotCompilable:\r\n (nodeDiagnostics?.isNotCompilable ?? false) || schema?.isCompilable === false,\r\n columnCount: schema?.columns?.length ?? null,\r\n };\r\n });\r\n });\r\n\r\n /**\r\n * Solo gli archi con **entrambi** i capi risolti diventano `<f-connection>`: un capo che non\r\n * esiste non ha un connettore, e una connessione verso un id inesistente si attacca a un\r\n * punto arbitrario del canvas. Il riferimento rotto si vede sulla porta del nodo.\r\n */\r\n readonly edges = computed<DpeCanvasEdge[]>(() =>\r\n this.store\r\n .graph()\r\n .edges.filter((edge) => edge.isResolved)\r\n .map((edge) => ({\r\n id: edge.id,\r\n sourceId: edge.fromPortId,\r\n targetId: edge.toPortId,\r\n slot: edge.slot,\r\n })),\r\n );\r\n\r\n constructor() {\r\n /*\r\n * Riallineamento della selezione: **una sola scrittura**, e in questa direzione.\r\n *\r\n * @foblex/flow tiene una sua selezione (classe `f-selected`, elenco interno usato da drag\r\n * multiplo e `Canc`) e la aggiorna da se' sui gesti. Se la si lascia autorevole si finisce\r\n * con due sistemi che non si parlano: il nodo raggiunto da una diagnostica porta la nostra\r\n * classe, quello cliccato prima porta `f-selected`, e l'utente vede due nodi selezionati\r\n * senza sapere su quale sta agendo. La cura non e' azzerare l'altro sistema dove serve — e'\r\n * derivarlo: il gesto entra da `fSelectionChange` e finisce nello store, lo store torna qui e\r\n * scrive nella libreria. La classe `dpe-node--selected` deriva dallo stesso stato.\r\n *\r\n * `isSelectedChanged: false` perche' questa scrittura **non** e' un gesto dell'utente e non\r\n * deve far emettere un cambio di selezione: sarebbe il ciclo.\r\n */\r\n effect(() => {\r\n const selected = this.store.selectedNodeNames();\r\n const flow = this.flow();\r\n if (!flow) {\r\n return;\r\n }\r\n if (selected.length === 0) {\r\n // `clearSelection` agisce subito; `select` no (vedi sotto), quindi il caso vuoto passa da qui.\r\n flow.clearSelection();\r\n return;\r\n }\r\n flow.select(selected.map((name) => dpeNodeId(name)), [], false);\r\n // `select()` della libreria non applica: si iscrive al prossimo cambio delle connessioni e\r\n // agisce **la' dentro**. Senza una notifica, la selezione programmatica resta in attesa\r\n // indefinitamente e nel DOM non compare niente — nessun errore, solo un `f-selected` che\r\n // non arriva. `redraw()` e' cio' che emette quel cambio.\r\n flow.redraw();\r\n });\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Navigazione\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Porta il nodo in vista **muovendo la vista**, non il nodo: le coordinate del documento non si\r\n * toccano (una navigazione non e' una modifica). Se il nodo e' gia' interamente visibile non fa\r\n * nulla, perche' una panoramica non richiesta disorienta quanto la sua assenza.\r\n */\r\n revealNode(name: string): void {\r\n const id = dpeNodeId(name);\r\n const element = this.findNodeElement(id);\r\n if (!element) {\r\n return;\r\n }\r\n const view = this.host.nativeElement.getBoundingClientRect();\r\n if (dpeIsRectFullyVisible(element.getBoundingClientRect(), view, REVEAL_MARGIN)) {\r\n return;\r\n }\r\n // La panoramica e' un movimento della vista fatto da noi, ma resta un movimento: lasciando\r\n // emettere `fCanvasChange` compare «Inquadra», che e' il modo di tornare all'insieme.\r\n this.canvas().centerGroupOrNode(id, true);\r\n }\r\n\r\n /**\r\n * Il nodo nel DOM. Si scorre l'elenco invece di comporre un selettore con il valore\r\n * dell'attributo: il nome del nodo arriva dal documento e puo' contenere qualunque carattere,\r\n * e un selettore costruito per concatenazione su un dato del documento e' un errore in attesa.\r\n */\r\n private findNodeElement(id: string): HTMLElement | undefined {\r\n const elements = this.host.nativeElement.querySelectorAll<HTMLElement>('[data-f-node-id]');\r\n for (const element of Array.from(elements)) {\r\n if (element.getAttribute('data-f-node-id') === id) {\r\n return element;\r\n }\r\n }\r\n return undefined;\r\n }\r\n\r\n /** Misure per il layout automatico: le stesse che il CSS applica con le classi. */\r\n layoutInput(): { name: string; width: number; height: number }[] {\r\n return this.nodes().map((node) => ({\r\n name: node.name,\r\n width: dpeNodeWidth(node.ports.length),\r\n height: DPE_NODE_HEIGHT,\r\n }));\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Viewport\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * `fitToScreen` va chiamato **dopo** il render dei nodi: prima, la libreria non conosce\r\n * ancora le loro dimensioni e inquadra la vista sbagliata. Solo la prima volta: rifarlo\r\n * combatterebbe con l'utente che ha spostato la vista.\r\n */\r\n onNodesRendered(): void {\r\n if (this.hasFramedOnce || this.nodes().length < 2) {\r\n return;\r\n }\r\n /*\r\n * Si inquadra **dopo** che tutti i nodi hanno una posizione. Un documento che non porta\r\n * coordinate (ADR 0013) le riceve da dagre subito dopo il primo render: inquadrare prima\r\n * significava inquadrare un mucchio di card tutte in (0,0), e il risultato era il grafo\r\n * tagliato in alto a sinistra all'apertura — con `hasFramedOnce` già consumato, quindi senza\r\n * una seconda occasione. Qui non si consuma niente: il layout scrive le posizioni, i nodi si\r\n * ridisegnano e questo gestore torna con le misure vere.\r\n */\r\n const positions = this.store.positions();\r\n if (this.nodes().some((node) => !positions.has(node.name))) {\r\n return;\r\n }\r\n this.hasFramedOnce = true;\r\n const canvas = this.canvas();\r\n // La scala si **stima prima**: chiedere `getScale()` dopo `fitToScreen` restituisce la scala\r\n // di configurazione e non quella applicata, quindi il controllo non scattava mai e le card\r\n // restavano illeggibili. La stima usa gli stessi numeri che il CSS applica alle card.\r\n if (this.wouldFitBelowMinimumScale()) {\r\n // 100% centrato sui nodi: si perde la vista d'insieme e si guadagna un'etichetta\r\n // leggibile. `emitCanvasChange: false` perche' l'inquadratura iniziale non e' un gesto\r\n // dell'utente; il comando «Inquadra» si mostra qui in modo esplicito, perche' e' l'unico\r\n // modo di ottenere la panoramica a cui si e' appena rinunciato.\r\n canvas.resetScaleAndCenter(false, false);\r\n this._isFitCommandVisible.set(true);\r\n return;\r\n }\r\n canvas.fitToScreen(FIT_PADDING, false, false);\r\n }\r\n\r\n /** Vero quando inquadrare tutto il grafo richiederebbe una scala sotto la soglia leggibile. */\r\n private wouldFitBelowMinimumScale(): boolean {\r\n const nodes = this.nodes();\r\n if (nodes.length === 0) {\r\n return false;\r\n }\r\n let left = Number.POSITIVE_INFINITY;\r\n let top = Number.POSITIVE_INFINITY;\r\n let right = Number.NEGATIVE_INFINITY;\r\n let bottom = Number.NEGATIVE_INFINITY;\r\n for (const node of nodes) {\r\n const width = dpeNodeWidth(node.ports.length);\r\n left = Math.min(left, node.position.x);\r\n top = Math.min(top, node.position.y);\r\n right = Math.max(right, node.position.x + width);\r\n bottom = Math.max(bottom, node.position.y + DPE_NODE_HEIGHT);\r\n }\r\n const host = this.host.nativeElement;\r\n const availableWidth = host.clientWidth - FIT_PADDING.x * 2;\r\n const availableHeight = host.clientHeight - FIT_PADDING.y * 2;\r\n if (availableWidth <= 0 || availableHeight <= 0) {\r\n return false;\r\n }\r\n const scale = Math.min(\r\n availableWidth / Math.max(right - left, 1),\r\n availableHeight / Math.max(bottom - top, 1),\r\n );\r\n return scale < MIN_INITIAL_SCALE;\r\n }\r\n\r\n onCanvasChange(): void {\r\n this._isFitCommandVisible.set(true);\r\n }\r\n\r\n resetViewport(): void {\r\n this.canvas().fitToScreen(FIT_PADDING, true, false);\r\n // Il grafo e' inquadrato: il comando non ha piu' niente da offrire finche' la vista non si muove.\r\n this._isFitCommandVisible.set(false);\r\n }\r\n\r\n // -------------------------------------------------------------------------\r\n // Gesti\r\n // -------------------------------------------------------------------------\r\n\r\n /**\r\n * Creazione di un arco: si scrive il **riferimento** sulla porta di destinazione. La\r\n * direzione del gesto e' irrilevante — cio' che conta e' quale slot riceve il nome, ed e'\r\n * per questo che le porte di ingresso sono una per slot.\r\n */\r\n onCreateConnection(event: { sourceId: string; targetId?: string }): void {\r\n if (!this.isEditable() || !event.targetId) {\r\n return;\r\n }\r\n const source = dpeParseOutputPortId(event.sourceId);\r\n const target = dpeParseInputPortId(event.targetId);\r\n if (!source || !target || source === target.nodeName) {\r\n // Un nodo che si collega a se stesso e' un ciclo di lunghezza uno: il backend lo\r\n // rifiuterebbe con `DPE_GRAPH_CYCLE`, e disegnarlo non aggiunge informazione.\r\n return;\r\n }\r\n this.store.connect(target.nodeName, target.slot, source, target.index);\r\n }\r\n\r\n /** Riassegnazione di un arco già disegnato, da un capo o dall'altro. */\r\n onReassignConnection(event: {\r\n endpoint: string;\r\n previousSourceId: string;\r\n nextSourceId?: string;\r\n previousTargetId: string;\r\n nextTargetId?: string;\r\n }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n const previousTarget = dpeParseInputPortId(event.previousTargetId);\r\n const previousSource = dpeParseOutputPortId(event.previousSourceId);\r\n if (!previousTarget || !previousSource) {\r\n return;\r\n }\r\n if (event.endpoint === 'target') {\r\n const nextTarget = event.nextTargetId ? dpeParseInputPortId(event.nextTargetId) : undefined;\r\n this.store.disconnect(previousTarget.nodeName, previousTarget.slot, previousTarget.index);\r\n if (nextTarget) {\r\n this.store.connect(nextTarget.nodeName, nextTarget.slot, previousSource, nextTarget.index);\r\n }\r\n return;\r\n }\r\n const nextSource = event.nextSourceId ? dpeParseOutputPortId(event.nextSourceId) : undefined;\r\n if (nextSource) {\r\n this.store.connect(previousTarget.nodeName, previousTarget.slot, nextSource, previousTarget.index);\r\n }\r\n }\r\n\r\n /**\r\n * Spostamento: un solo passo di cronologia per l'intero gesto. Le posizioni intermedie non\r\n * sono modifiche che l'utente vuole annullare una per una.\r\n */\r\n onMoveNodes(event: { nodes: Array<{ id: string; position: { x: number; y: number } }> }): void {\r\n event.nodes.forEach((moved, index) => {\r\n const name = dpeParseNodeId(moved.id);\r\n if (name) {\r\n this.store.moveNode(name, moved.position, { silent: index > 0 });\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Il gesto di selezione della libreria entra **nello store** e non altrove: e' l'unico verso in\r\n * cui la selezione di @foblex/flow conta, come rilevazione del gesto. Cio' che si vede lo decide\r\n * lo store, attraverso l'effect del costruttore.\r\n */\r\n onSelectionChange(event: { nodeIds: string[] }): void {\r\n const names: string[] = [];\r\n for (const id of event.nodeIds) {\r\n const name = dpeParseNodeId(id);\r\n if (name) {\r\n names.push(name);\r\n }\r\n }\r\n this.store.selectMany(names);\r\n }\r\n\r\n onDeleteSelected(event: { nodeIds: string[] }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n for (const id of event.nodeIds) {\r\n const name = dpeParseNodeId(id);\r\n if (name) {\r\n this.store.removeNode(name);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Rilascio di una voce trascinata dalla palette. `externalItemRect` e' già nel sistema di\r\n * coordinate del canvas: convertirlo a mano dal viewport sarebbe rifare la trasformazione\r\n * di zoom e panoramica della libreria.\r\n */\r\n onCreateNode(event: { data: unknown; externalItemRect: { x: number; y: number } }): void {\r\n if (!this.isEditable()) {\r\n return;\r\n }\r\n const collection = event.data as DpeNodeCollectionName | undefined;\r\n if (!collection) {\r\n return;\r\n }\r\n this.nodeDropped.emit({\r\n collection,\r\n x: Math.round(event.externalItemRect.x),\r\n y: Math.round(event.externalItemRect.y),\r\n });\r\n }\r\n\r\n onNodeDoubleClick(name: string): void {\r\n this.nodeOpened.emit(name);\r\n }\r\n\r\n onEditClick(event: Event, name: string): void {\r\n // Senza `stopPropagation` il clic vale anche come selezione dell'area sotto il bottone.\r\n event.stopPropagation();\r\n this.nodeOpened.emit(name);\r\n }\r\n\r\n onRemoveClick(event: Event, name: string): void {\r\n event.stopPropagation();\r\n this.store.removeNode(name);\r\n }\r\n\r\n /** La classe nel DOM **deriva** dallo store: non e' una seconda registrazione della selezione. */\r\n isSelected(node: DpeCanvasNode): boolean {\r\n return this.store.selectedNodeNameSet().has(node.name);\r\n }\r\n}\r\n","<!--\r\n Gerarchia obbligatoria: f-flow > f-canvas > fNode / f-connection. I `@for` stanno\r\n direttamente dentro <f-canvas>: senza wrapper non serve `ngProjectAs`.\r\n-->\r\n<!--\r\n `dpe-flow`: classe nostra sul contenitore della libreria, e serve al **CSS**. Il tema di\r\n @foblex/flow stila la card con `.f-flow .f-node` (due classi): un nostro `.dpe-node` non la\r\n batte, e senza questa classe la card torna larga 120px e col testo centrato. Con `dpe-flow` i\r\n selettori del foglio diventano `dpe-canvas .dpe-flow .dpe-node`, che vince per specificita' e\r\n non per ordine di caricamento.\r\n-->\r\n<f-flow\r\n class=\"dpe-flow\"\r\n fDraggable\r\n (fCreateConnection)=\"onCreateConnection($event)\"\r\n (fReassignConnection)=\"onReassignConnection($event)\"\r\n (fMoveNodes)=\"onMoveNodes($event)\"\r\n (fSelectionChange)=\"onSelectionChange($event)\"\r\n (fDeleteSelected)=\"onDeleteSelected($event)\"\r\n (fCreateNode)=\"onCreateNode($event)\"\r\n (fNodesRendered)=\"onNodesRendered()\"\r\n>\r\n <f-canvas fZoom #canvas (fCanvasChange)=\"onCanvasChange()\">\r\n <f-background>\r\n <f-circle-pattern />\r\n </f-background>\r\n\r\n @for (edge of edges(); track edge.id) {\r\n <!--\r\n La classe porta lo **slot** di destinazione: la primaria e la secondaria di un join\r\n vanno distinte a vista, altrimenti l’unico modo di sapere quale lato e’ quale e’ aprire\r\n l’ispettore. I colori stanno nel CSS globale, non qui: i path SVG sono creati a runtime\r\n e non portano l’attributo di scope.\r\n -->\r\n <f-connection\r\n [fConnectionId]=\"edge.id\"\r\n [fSourceId]=\"edge.sourceId\"\r\n [fTargetId]=\"edge.targetId\"\r\n fBehavior=\"floating\"\r\n fType=\"bezier\"\r\n [class]=\"'dpe-edge dpe-edge--' + edge.slot\"\r\n >\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection>\r\n }\r\n\r\n @for (node of nodes(); track node.id) {\r\n <!--\r\n Nessun `[style.*]` sul nodo: @foblex/flow riscrive l’attributo `style` a ogni\r\n riposizionamento e lo cancellerebbe. La larghezza arriva da `node.widthClass`.\r\n -->\r\n <div\r\n fNode\r\n fDragHandle\r\n [fNodeId]=\"node.id\"\r\n [fNodePosition]=\"node.position\"\r\n [class]=\"\r\n 'dpe-node dpe-node--' + node.collection + ' ' + node.widthClass + ' ' + node.familyClass\r\n \"\r\n [class.dpe-node--selected]=\"isSelected(node)\"\r\n [class.dpe-node--error]=\"node.severity === 'Error'\"\r\n [class.dpe-node--warning]=\"node.severity === 'Warning'\"\r\n [class.dpe-node--not-compilable]=\"node.isNotCompilable\"\r\n [attr.aria-label]=\"node.categoryLabel + ' ' + node.label\"\r\n (dblclick)=\"onNodeDoubleClick(node.name)\"\r\n >\r\n <!--\r\n Le porte di ingresso stanno in fila sul bordo superiore, una per slot. Si renderizzano\r\n **sempre**: un connettore con `display: none` ha geometria 0x0 e l’arco si attacca nel\r\n punto sbagliato. `fConnectorConnectableSide` e’ dichiarato: senza, un arco che risale\r\n entrerebbe di fianco.\r\n -->\r\n @if (node.ports.length > 0) {\r\n <div class=\"dpe-node__ports\" [class.dpe-node__ports--labelled]=\"node.showsPortLabels\">\r\n @for (port of node.ports; track port.id) {\r\n <div class=\"dpe-port\">\r\n <div\r\n fConnector\r\n fConnectorType=\"target\"\r\n [fConnectorId]=\"port.id\"\r\n [fConnectorConnectableSide]=\"sides.TOP\"\r\n fConnectorMultiple=\"false\"\r\n class=\"dpe-connector dpe-connector--in\"\r\n [class.dpe-connector--broken]=\"port.isBroken\"\r\n [title]=\"port.label\"\r\n ></div>\r\n @if (node.showsPortLabels) {\r\n <span class=\"dpe-port__label\" [title]=\"port.label\">{{ port.label }}</span>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-node__head\">\r\n <!--\r\n La stessa pastiglia della palette: cio’ che si trascina deve assomigliare a cio’ che\r\n compare. La classe di famiglia porta i due token di colore.\r\n -->\r\n <span class=\"dpe-node__icon\">\r\n <dpe-node-icon [collection]=\"node.collection\" />\r\n </span>\r\n <div class=\"dpe-node__text\">\r\n <span class=\"dpe-node__title\" [title]=\"node.label\">{{ node.label }}</span>\r\n <span class=\"dpe-node__sub\">\r\n {{ node.categoryLabel }}\r\n @if (node.subtitle) {\r\n <span class=\"dpe-node__dot\">·</span>{{ node.subtitle }}\r\n }\r\n </span>\r\n </div>\r\n <!--\r\n `fDragBlocker` sui bottoni dentro un nodo: senza, il pointerdown diventa un\r\n trascinamento e aprire l’ispettore sposta il nodo di qualche pixel.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-node__btn\"\r\n [attr.aria-label]=\"'Apri l’ispettore di ' + node.label\"\r\n title=\"Apri l’ispettore\"\r\n (click)=\"onEditClick($event, node.name)\"\r\n >\r\n ✎\r\n </button>\r\n @if (isEditable() && isSelected(node)) {\r\n <!--\r\n Solo sul nodo selezionato: un comando distruttivo che compare sotto il puntatore\r\n mentre si attraversa il grafo si preme per sbaglio.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-node__btn dpe-node__btn--remove\"\r\n [attr.aria-label]=\"'Elimina ' + node.label\"\r\n title=\"Elimina (si annulla con ↶)\"\r\n (click)=\"onRemoveClick($event, node.name)\"\r\n >\r\n ×\r\n </button>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-node__meta\">\r\n <span class=\"dpe-node__name\" [title]=\"'Nome tecnico: ' + node.name\">{{ node.name }}</span>\r\n @if (node.columnCount !== null) {\r\n <span class=\"dpe-badge\" [title]=\"'Colonne in uscita secondo il backend'\">\r\n {{ node.columnCount }} col.\r\n </span>\r\n }\r\n @if (node.isNotCompilable) {\r\n <!--\r\n Stato distinto dall’errore: la definizione va bene, il compilatore non ci arriva\r\n (I10). Colore proprio, testo che non chiede di correggere niente.\r\n -->\r\n <span class=\"dpe-badge dpe-badge--not-compilable\" title=\"Valido, ma non compilabile: e’ un limite nostro\">\r\n non compilabile\r\n </span>\r\n }\r\n @if (node.diagnosticCount > 0) {\r\n <span\r\n class=\"dpe-badge\"\r\n [class.dpe-badge--error]=\"node.severity === 'Error'\"\r\n [class.dpe-badge--warning]=\"node.severity === 'Warning'\"\r\n [class.dpe-badge--info]=\"node.severity === 'Info'\"\r\n [title]=\"node.diagnosticCount + ' rilievi dal backend'\"\r\n >\r\n {{ node.diagnosticCount }}\r\n </span>\r\n }\r\n @for (port of node.ports; track $index) {\r\n @if (port.isBroken) {\r\n <span class=\"dpe-badge dpe-badge--error\" [title]=\"'Riferimento non risolto: ' + port.sourceName\">\r\n ⚠ {{ port.sourceName }}\r\n </span>\r\n }\r\n }\r\n </div>\r\n\r\n <!--\r\n L’uscita e’ una sola: lo schema prodotto e’ uno. I sink non ne hanno, e la porta non\r\n si disegna affatto — qui non c’e’ niente da nascondere con `display: none`, il\r\n connettore semplicemente non esiste.\r\n -->\r\n @if (node.hasOutput) {\r\n <div class=\"dpe-node__out\">\r\n <div\r\n fConnector\r\n fConnectorType=\"source\"\r\n [fConnectorId]=\"node.outputPortId\"\r\n [fConnectorConnectableSide]=\"sides.BOTTOM\"\r\n class=\"dpe-connector dpe-connector--out\"\r\n title=\"Uscita\"\r\n ></div>\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <f-connection-for-create fBehavior=\"floating\" fType=\"bezier\" class=\"dpe-edge dpe-edge--creating\">\r\n <f-connection-marker-arrow [type]=\"markerEnd\" />\r\n </f-connection-for-create>\r\n\r\n <f-selection-area />\r\n </f-canvas>\r\n\r\n <!--\r\n Fuori da <f-canvas> come la minimappa: dentro, la trasformazione del canvas se lo\r\n porterebbe via insieme ai nodi.\r\n -->\r\n <button\r\n type=\"button\"\r\n fDragBlocker\r\n class=\"dpe-viewport-reset\"\r\n [class.dpe-viewport-reset--hidden]=\"!isFitCommandVisible()\"\r\n title=\"Rimetti il grafo interamente in vista\"\r\n (click)=\"resetViewport()\"\r\n >\r\n ⤢ Inquadra\r\n </button>\r\n\r\n <f-minimap [fMinSize]=\"1200\" class=\"dpe-minimap\" />\r\n</f-flow>\r\n","/**\r\n * Il pannello delle diagnostiche.\r\n *\r\n * Mostra l'**elenco completo** (la validazione e' esaustiva, **I6**): non si accorpa, non si\r\n * tronca, non si riordina per gravita' — l'ordine del backend segue la struttura del documento e\r\n * perderlo rende impossibile capire quale nodo ha quale problema.\r\n *\r\n * La distinzione che questo pannello esiste per rendere: **nodo non valido** (l'utente deve\r\n * correggere) contro **nodo valido ma non ancora compilabile** (`DPE_NODE_NOT_COMPILABLE`,\r\n * **I10**). Sono situazioni diverse e hanno colore, icona ed etichetta diversi; mescolarle\r\n * significherebbe chiedere all'utente di correggere un limite nostro.\r\n *\r\n * Terza categoria a se': i rilievi **del dialetto** (`DPE_DIALECT_*`). Lo stesso documento su un\r\n * altro dialetto sarebbe compilabile, e l'interfaccia deve dirlo, altrimenti si cerca l'errore\r\n * nella definizione.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject, output } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport {\r\n dpeDiagnosticLocationLabel,\r\n dpeDiagnosticNodeName,\r\n dpeIsDialectDiagnostic,\r\n dpeIsNotCompilable,\r\n} from '../../core/dpe-diagnostics.util';\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { Diagnostic } from '../../model/dpe-diagnostics.model';\r\n\r\ninterface DpeDiagnosticRow {\r\n diagnostic: Diagnostic;\r\n location: string;\r\n /** Nodo a cui navigare, se il percorso permette di ricavarlo. */\r\n nodeName?: string;\r\n field?: string;\r\n isNotCompilable: boolean;\r\n isDialect: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-diagnostics-panel',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-diag__head\">\r\n <strong>Diagnostiche</strong>\r\n <span class=\"dpe-diag__count\">\r\n {{ counts().errors }} errori · {{ counts().warnings }} avvisi · {{ counts().infos }} info\r\n @if (counts().notCompilable > 0) {\r\n · {{ counts().notCompilable }} non compilabili\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (rows().length === 0) {\r\n <p class=\"dpe-diag__empty\">\r\n @if (hasResult()) {\r\n Nessun rilievo dal backend.\r\n } @else {\r\n In attesa della prima validazione…\r\n }\r\n </p>\r\n }\r\n\r\n <!--\r\n track $index: le chiavi composte da codice e percorso si duplicano davvero (lo stesso\r\n codice sullo stesso campo di due righe di una collezione) e Angular lo tratta come errore.\r\n -->\r\n @for (row of rows(); track $index) {\r\n <!-- Una sola sorgente di classi: class statico e [class] si contenderebbero l’attributo. -->\r\n <button\r\n type=\"button\"\r\n [class]=\"'dpe-diag__row dpe-diag__row--' + row.diagnostic.severity\"\r\n [class.dpe-diag__row--not-compilable]=\"row.isNotCompilable\"\r\n [disabled]=\"!row.nodeName\"\r\n (click)=\"navigateTo(row)\"\r\n >\r\n <span class=\"dpe-diag__code\">{{ row.diagnostic.code }}</span>\r\n <span class=\"dpe-diag__text\">\r\n {{ row.diagnostic.message }}\r\n <br />\r\n <span class=\"dpe-diag__where\">{{ row.location }}</span>\r\n </span>\r\n @if (row.isNotCompilable) {\r\n <span\r\n class=\"dpe-diag__tag dpe-diag__tag--not-compilable\"\r\n title=\"Valido, ma il compilatore non lo traduce: non c’e’ nulla da correggere\"\r\n >\r\n limite nostro\r\n </span>\r\n }\r\n @if (row.isDialect) {\r\n <span\r\n class=\"dpe-diag__tag dpe-diag__tag--dialect\"\r\n [title]=\"'Dipende dalle capacita’ del dialetto ' + dialectLabel() + ': su un altro dialetto lo stesso documento potrebbe compilare'\"\r\n >\r\n {{ dialectLabel() }}\r\n </span>\r\n }\r\n </button>\r\n }\r\n `,\r\n})\r\nexport class DpeDiagnosticsPanelComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n /** Emesso quando la riga porta a un nodo: chi ascolta apre l'ispettore e inquadra il nodo. */\r\n readonly navigate = output<{ nodeName: string; field?: string }>();\r\n\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n readonly dialectLabel = computed(() => {\r\n const dialect = this.store.definition().dialect;\r\n return DPE_DIALECT_LABELS[dialect] ?? dialect;\r\n });\r\n\r\n readonly rows = computed<DpeDiagnosticRow[]>(() => {\r\n const definition = this.store.definition();\r\n return this.store.diagnostics().map((diagnostic) => ({\r\n diagnostic,\r\n location: dpeDiagnosticLocationLabel(diagnostic, definition),\r\n nodeName: dpeDiagnosticNodeName(diagnostic, definition),\r\n field: diagnostic.path?.field,\r\n isNotCompilable: dpeIsNotCompilable(diagnostic),\r\n isDialect: dpeIsDialectDiagnostic(diagnostic),\r\n }));\r\n });\r\n\r\n readonly counts = computed(() => {\r\n let errors = 0;\r\n let warnings = 0;\r\n let infos = 0;\r\n let notCompilable = 0;\r\n for (const row of this.rows()) {\r\n if (row.isNotCompilable) {\r\n notCompilable += 1;\r\n }\r\n switch (row.diagnostic.severity) {\r\n case 'Error':\r\n errors += 1;\r\n break;\r\n case 'Warning':\r\n warnings += 1;\r\n break;\r\n default:\r\n infos += 1;\r\n break;\r\n }\r\n }\r\n return { errors, warnings, infos, notCompilable };\r\n });\r\n\r\n /**\r\n * Emette **soltanto** l'intenzione: chi la riceve seleziona e inquadra. Selezionare anche da qui\r\n * significherebbe due scritture della selezione per un solo clic — la strada per due nodi\r\n * selezionati insieme — e un pannello che pilota il canvas invece di chiederglielo.\r\n */\r\n protected navigateTo(row: DpeDiagnosticRow): void {\r\n if (!row.nodeName) {\r\n return;\r\n }\r\n this.navigate.emit({ nodeName: row.nodeName, field: row.field });\r\n }\r\n}\r\n","/**\r\n * `[dpeValue]` su un `<select>`.\r\n *\r\n * Perche' esiste, e non e' un vezzo: un `[value]` viene applicato **prima** che le `<option>`\r\n * generate da un `@for` esistano. Il browser scarta un valore che non corrisponde a nessuna\r\n * opzione, Angular non lo riapplica (il binding non e' cambiato) e la tendina resta sulla prima\r\n * voce — mostrando un valore diverso da quello del documento. Nessun errore, nessun avviso: solo\r\n * una tendina che mente. L'abbiamo visto sul selettore del dialetto e sulle funzioni di\r\n * aggregazione, dove `Sum` compariva come `Count`.\r\n *\r\n * La direttiva riallinea l'elemento al valore dichiarato a ogni giro di change detection, quindi\r\n * quando le opzioni compaiono la selezione si sistema da se'.\r\n */\r\n\r\nimport { AfterViewChecked, Directive, ElementRef, inject, input } from '@angular/core';\r\n\r\n@Directive({\r\n selector: 'select[dpeValue]',\r\n standalone: true,\r\n})\r\nexport class DpeSelectValueDirective implements AfterViewChecked {\r\n private readonly element = inject<ElementRef<HTMLSelectElement>>(ElementRef);\r\n\r\n readonly dpeValue = input<string | number | null | undefined>('');\r\n\r\n ngAfterViewChecked(): void {\r\n const select = this.element.nativeElement;\r\n const value = this.dpeValue();\r\n const normalized = value === null || value === undefined ? '' : String(value);\r\n if (select.value !== normalized) {\r\n select.value = normalized;\r\n }\r\n }\r\n}\r\n","/**\r\n * Base comune degli ispettori.\r\n *\r\n * `@Directive()` **senza selettore**: e' il solo modo in cui Angular riconosce come input\r\n * quelli dichiarati su una classe base ereditata da piu' componenti. Senza il decoratore ogni\r\n * ispettore darebbe NG8002 sul primo binding.\r\n *\r\n * Ogni ispettore riceve il nodo in **sola lettura** e scrive attraverso lo store: la\r\n * definizione e' un valore, le modifiche producono un nuovo valore. Nessun ispettore muta\r\n * l'oggetto che riceve.\r\n *\r\n * Quello che gli ispettori **non** fanno: non validano. Le sole verifiche locali ammesse sono\r\n * di forma del campo (obbligatorio non vuoto, un intero e' un intero) e servono al\r\n * comportamento del controllo, non a dire se la definizione va bene. Le diagnostiche mostrate\r\n * sono quelle del backend, con il loro codice e percorso.\r\n */\r\n\r\nimport { Directive, computed, inject, input } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeFindNode, dpeNodeSourceReferences } from '../../core/dpe-graph';\r\nimport { DpeColumnInfo } from '../../model/dpe-api.model';\r\nimport { Diagnostic } from '../../model/dpe-diagnostics.model';\r\nimport { DpeAnyNode, DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\n\r\n@Directive()\r\nexport abstract class DpeNodeInspectorBase<TNode extends DpeAnyNode = DpeAnyNode> {\r\n protected readonly store = inject(DpeDocumentStore);\r\n\r\n readonly nodeName = input.required<string>();\r\n readonly node = input.required<TNode>();\r\n\r\n /** La collezione di appartenenza: la sa l'ispettore, serve per scrivere nello store. */\r\n abstract readonly collection: DpeNodeCollectionName;\r\n\r\n /** Le diagnostiche ancorate a questo nodo, come le ha date il backend (**I6**). */\r\n readonly diagnostics = computed<readonly Diagnostic[]>(\r\n () => this.store.diagnosticsByNode().get(this.nodeName())?.diagnostics ?? [],\r\n );\r\n\r\n /**\r\n * Il nodo e' valido ma non compilabile (**I10**): l'ispettore lo dice in testa, perche' e'\r\n * l'informazione che spiega perche' non compare nessun SQL — e non c'e' niente da correggere.\r\n */\r\n readonly isNotCompilable = computed(\r\n () =>\r\n (this.store.diagnosticsByNode().get(this.nodeName())?.isNotCompilable ?? false) ||\r\n this.store.schemaByNode().get(this.nodeName())?.isCompilable === false,\r\n );\r\n\r\n /** Colonne prodotte dal nodo, secondo il backend. Mai calcolate qui (**I4**). */\r\n readonly outputColumns = computed<readonly DpeColumnInfo[]>(\r\n () => this.store.schemaByNode().get(this.nodeName())?.columns ?? [],\r\n );\r\n\r\n /**\r\n * Colonne disponibili **in ingresso**: l'unione degli schemi dei nodi a monte, nell'ordine.\r\n * Arrivano dal backend; se la validazione non e' ancora tornata l'elenco e' vuoto e i campi\r\n * si digitano a mano — che e' meglio di un elenco indovinato in locale.\r\n */\r\n readonly inputColumns = computed<readonly DpeColumnInfo[]>(() => {\r\n const located = dpeFindNode(this.store.definition(), this.nodeName());\r\n if (!located) {\r\n return [];\r\n }\r\n const schemas = this.store.schemaByNode();\r\n const result: DpeColumnInfo[] = [];\r\n const seen = new Set<string>();\r\n for (const reference of dpeNodeSourceReferences(located)) {\r\n if (!reference.isEdge || !reference.sourceName) {\r\n continue;\r\n }\r\n for (const column of schemas.get(reference.sourceName)?.columns ?? []) {\r\n // Confronto insensibile al caso: le colonne si confrontano cosi' in tutto il sistema,\r\n // perche' cosi' si comportano i quattro database di destinazione.\r\n const key = column.name.toLowerCase();\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n result.push(column);\r\n }\r\n }\r\n }\r\n return result;\r\n });\r\n\r\n /** I parametri dichiarati sulla radice: servono a filtri e mapping dei writeback. */\r\n readonly parameters = computed(() => this.store.definition().parameters ?? []);\r\n\r\n /** Le diagnostiche su un campo preciso, per mostrarle **accanto** al controllo. */\r\n issuesOn(field: string): Diagnostic[] {\r\n return this.diagnostics().filter((diagnostic) => diagnostic.path?.field === field);\r\n }\r\n\r\n hasIssueOn(field: string): boolean {\r\n return this.issuesOn(field).length > 0;\r\n }\r\n\r\n /** Applica una modifica al nodo. */\r\n protected patch(patch: Partial<TNode>): void {\r\n this.store.updateNode(this.collection, this.nodeName(), patch as never);\r\n }\r\n\r\n /**\r\n * Campo semplice: valore vuoto → chiave **rimossa**, non stringa vuota. Il backend\r\n * distingue assente da vuoto (`DPE_MODEL_REQUIRED_MISSING` contro un valore non valido), e\r\n * su Oracle la stringa vuota **e'** `NULL`: scriverla al posto di un'assenza cambia la\r\n * semantica invece di ripulire il campo.\r\n */\r\n protected setField(field: keyof TNode & string, value: unknown): void {\r\n const patch: Record<string, unknown> = {};\r\n patch[field] = value === '' || value === null ? undefined : value;\r\n this.patch(patch as Partial<TNode>);\r\n }\r\n\r\n /** Numero da un campo di testo: vuoto o non numerico → assente, non `0`. */\r\n protected toNumber(value: string): number | undefined {\r\n if (value.trim() === '') {\r\n return undefined;\r\n }\r\n const parsed = Number(value);\r\n return Number.isFinite(parsed) ? parsed : undefined;\r\n }\r\n\r\n /** Lettura tipizzata di un valore da un evento di input, senza `any` nei template. */\r\n protected valueOf(event: Event): string {\r\n return (event.target as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement).value;\r\n }\r\n\r\n protected checkedOf(event: Event): boolean {\r\n return (event.target as HTMLInputElement).checked;\r\n }\r\n}\r\n","/**\r\n * Ispettore dell'aggregazione.\r\n *\r\n * Lo schema di uscita e' `groupBy` (con i loro nomi) **piu'** gli alias delle funzioni, in\r\n * quest'ordine: l'ispettore mostra le due sezioni in quell'ordine per la stessa ragione.\r\n *\r\n * `sourceFieldName` e' ammesso vuoto **solo** per `Count` (conteggio righe). Il contratto lo\r\n * rappresenta con l'assenza e non con la stringa `\"*\"`, quindi il campo si disabilita invece\r\n * di suggerire un valore magico.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateField,\r\n AggregateFunction,\r\n AggregateNode,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst FUNCTIONS: readonly AggregateFunction[] = [\r\n 'Count',\r\n 'CountDistinct',\r\n 'Sum',\r\n 'Min',\r\n 'Max',\r\n 'Avg',\r\n 'StdDev',\r\n 'StdDevPop',\r\n 'Variance',\r\n 'VariancePop',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-aggregate-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"agg-group\">Raggruppa per</label>\r\n <input\r\n id=\"agg-group\"\r\n type=\"text\"\r\n [value]=\"groupByText()\"\r\n placeholder=\"colonne separate da virgola\"\r\n (change)=\"onGroupBy(valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Vuoto = aggregazione globale, una sola riga in uscita.\r\n @if (inputColumns().length > 0) {\r\n Colonne disponibili: {{ columnHint() }}\r\n }\r\n </p>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Funzioni</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna funzione: il nodo non produce colonne calcolate.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Funzione</th>\r\n <th>Colonna</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"agg-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"field.function === 'Count'\"\r\n [attr.placeholder]=\"field.function === 'Count' ? 'tutte le righe' : ''\"\r\n [attr.aria-label]=\"'Colonna della funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias della funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la funzione\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"agg-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi funzione</button>\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n <code>StdDev</code> e le sue varianti non sono supportate da tutti i dialetti: se il\r\n dialetto scelto non le ha, la validazione lo dice con <code>DPE_DIALECT_UNSUPPORTED</code>.\r\n </p>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAggregateInspectorComponent extends DpeNodeInspectorBase<AggregateNode> {\r\n override readonly collection: DpeNodeCollectionName = 'aggregates';\r\n\r\n protected readonly functions = FUNCTIONS;\r\n\r\n readonly fields = computed<readonly AggregateField[]>(() => this.node().fields ?? []);\r\n\r\n readonly groupByText = computed(() => (this.node().groupBy ?? []).join(', '));\r\n\r\n readonly columnHint = computed(() => {\r\n const names = this.inputColumns().map((column) => column.name);\r\n return names.length > 10 ? `${names.slice(0, 10).join(', ')}, …` : names.join(', ');\r\n });\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected onGroupBy(raw: string): void {\r\n const columns = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n this.patch({ groupBy: columns.length > 0 ? columns : undefined });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { function: 'Count', alias: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<AggregateField>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore dell'unione.\r\n *\r\n * Le sorgenti si collegano sul canvas: qui si aggiunge o si toglie una **posizione**, cioe' una\r\n * porta. Sono due gesti diversi e vanno in due posti diversi — togliere una porta con l'arco\r\n * attaccato sul canvas non si capirebbe.\r\n *\r\n * `allowsDisjointSchema` cambia il significato dell'unione (schema comune obbligatorio contro\r\n * unione con colonne nulle): l'etichetta lo dice, perche' il nome del campo da solo no.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport { AppendNode, DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-append-inspector',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().allowsDisjointSchema ?? false\"\r\n (change)=\"setField('allowsDisjointSchema', checkedOf($event))\"\r\n />\r\n Ammetti schemi diversi\r\n </label>\r\n <p class=\"dpe-field__hint\">\r\n @if (node().allowsDisjointSchema) {\r\n Lo schema in uscita e’ l’unione degli alias: le colonne assenti in una sorgente\r\n diventano nulle.\r\n } @else {\r\n Gli schemi delle sorgenti devono coincidere per nome e tipo compatibile; se non\r\n coincidono, la validazione lo dice con <code>DPE_SCHEMA_INCOMPATIBLE_UNION</code>.\r\n }\r\n </p>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Sorgenti ({{ sources().length }})</h4>\r\n <ol class=\"dpe-form\">\r\n @for (source of sources(); track $index) {\r\n <li class=\"dpe-row\">\r\n <span>{{ $index + 1 }}. {{ source || 'non collegata' }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la posizione ' + ($index + 1)\"\r\n (click)=\"removeSource($index)\"\r\n >\r\n ×\r\n </button>\r\n </li>\r\n }\r\n </ol>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addSource()\">Aggiungi posizione</button>\r\n </div>\r\n <p class=\"dpe-field__hint\">Le sorgenti si collegano trascinando un arco sulle porte in alto.</p>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAppendInspectorComponent extends DpeNodeInspectorBase<AppendNode> {\r\n override readonly collection: DpeNodeCollectionName = 'appends';\r\n\r\n readonly sources = computed<readonly string[]>(() => this.node().sources ?? []);\r\n\r\n protected addSource(): void {\r\n // Stringa vuota e non `undefined`: una posizione vuota **esiste** come porta, e serve un\r\n // elemento nell'array perche' il canvas la disegni.\r\n this.patch({ sources: [...this.sources(), ''] });\r\n }\r\n\r\n protected removeSource(index: number): void {\r\n this.patch({ sources: this.sources().filter((_, position) => position !== index) });\r\n }\r\n}\r\n","/**\r\n * Ispettore del gruppo atomico.\r\n *\r\n * Non e' un nodo del DAG: dichiara che alcune scritture vanno applicate dall'host **nella stessa\r\n * transazione**, nell'ordine dato. La libreria non apre transazioni — lo dice nel risultato e\r\n * l'host obbedisce — e l'avviso serve a non far credere che qui ci sia un `BEGIN`.\r\n *\r\n * I riferimenti sono a `WritebackNode` con destinazione `Database`: l'elenco e' chiuso a quelli,\r\n * perche' un gruppo atomico su un file non significherebbe niente.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AtomicWritebackNode,\r\n AtomicWritebackRelationship,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-atomic-writeback-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note\">\r\n La libreria non apre transazioni: questo gruppo <strong>dichiara</strong> che le scritture\r\n elencate vanno applicate insieme, e l’host lo esegue.\r\n </p>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"aw-sequence\">Sequenza</label>\r\n <input\r\n id=\"aw-sequence\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"node().sequence\"\r\n [attr.aria-invalid]=\"hasIssueOn('sequence')\"\r\n (change)=\"setField('sequence', toNumber(valueOf($event)) ?? 1)\"\r\n />\r\n <p class=\"dpe-field__hint\">Nello stesso spazio di numerazione delle scritture.</p>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Relazioni</h4>\r\n @if (relationships().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna relazione.</p>\r\n }\r\n @for (relationship of relationships(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-parent-' + $index\">Scrittura padre</label>\r\n <select\r\n [id]=\"'aw-parent-' + $index\"\r\n [dpeValue]=\"relationship.parentWritebackName ?? ''\"\r\n (change)=\"patchRelationship($index, { parentWritebackName: valueOf($event) || undefined })\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (writeback of databaseWritebacks(); track $index) {\r\n <option [value]=\"writeback.name\">{{ writeback.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-child-' + $index\">Scrittura figlia</label>\r\n <select\r\n [id]=\"'aw-child-' + $index\"\r\n [dpeValue]=\"relationship.childWritebackName ?? ''\"\r\n (change)=\"patchRelationship($index, { childWritebackName: valueOf($event) || undefined })\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (writeback of databaseWritebacks(); track $index) {\r\n <option [value]=\"writeback.name\">{{ writeback.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-seq-' + $index\">Ordine</label>\r\n <input\r\n [id]=\"'aw-seq-' + $index\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"relationship.sequence\"\r\n (change)=\"patchRelationship($index, { sequence: toNumber(valueOf($event)) ?? 1 })\"\r\n />\r\n </div>\r\n </div>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-pfield-' + $index\">Campo padre</label>\r\n <input\r\n [id]=\"'aw-pfield-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.parentFieldName ?? ''\"\r\n (change)=\"patchRelationship($index, { parentFieldName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-cfield-' + $index\">Campo figlio</label>\r\n <input\r\n [id]=\"'aw-cfield-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.childFieldName ?? ''\"\r\n (change)=\"patchRelationship($index, { childFieldName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'aw-rel-' + $index\">Relazione</label>\r\n <input\r\n [id]=\"'aw-rel-' + $index\"\r\n type=\"text\"\r\n [value]=\"relationship.relationshipName ?? ''\"\r\n (change)=\"patchRelationship($index, { relationshipName: valueOf($event) || undefined })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la relazione ' + ($index + 1)\"\r\n (click)=\"removeRelationship($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addRelationship()\">Aggiungi relazione</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeAtomicWritebackInspectorComponent extends DpeNodeInspectorBase<AtomicWritebackNode> {\r\n override readonly collection: DpeNodeCollectionName = 'atomicWritebacks';\r\n\r\n readonly relationships = computed<readonly AtomicWritebackRelationship[]>(\r\n () => this.node().relationships ?? [],\r\n );\r\n\r\n readonly databaseWritebacks = computed(() =>\r\n (this.store.definition().writebacks ?? []).filter((writeback) => writeback.target === 'Database'),\r\n );\r\n\r\n protected addRelationship(): void {\r\n const nextSequence =\r\n this.relationships().reduce((max, relationship) => Math.max(max, relationship.sequence), 0) + 1;\r\n this.patch({ relationships: [...this.relationships(), { sequence: nextSequence }] });\r\n }\r\n\r\n protected removeRelationship(index: number): void {\r\n this.patch({\r\n relationships: this.relationships().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchRelationship(index: number, patch: Partial<AtomicWritebackRelationship>): void {\r\n this.patch({\r\n relationships: this.relationships().map((relationship, position) =>\r\n position === index ? { ...relationship, ...patch } : relationship,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Editor di un `ColumnType`: i sei tipi logici e i loro attributi condizionali.\r\n *\r\n * I campi che compaiono dipendono dal `kind`, e la dipendenza e' quella del contratto:\r\n * `length` per `String`, `precision`/`scale` per `Number`, `allowedValues` per `Enum`. Mostrare\r\n * sempre tutto renderebbe rappresentabile un tipo che il backend rifiuta; mostrare solo cio'\r\n * che serve rende quello stato non rappresentabile.\r\n *\r\n * Cosa **non** fa: non decide se `length` sia obbligatorio in questo punto della definizione —\r\n * lo e' nei campi *dichiarati* e non altrove, e a dirlo e' la validazione\r\n * (`DPE_MODEL_CONDITIONAL_REQUIRED`).\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\r\n\r\nimport { ColumnType, LogicalType } from '../../model/dpe-definition.model';\r\n\r\nconst LOGICAL_TYPES: readonly LogicalType[] = [\r\n 'String',\r\n 'Number',\r\n 'Integer',\r\n 'DateTime',\r\n 'Boolean',\r\n 'Enum',\r\n];\r\n\r\nimport { DpeSelectValueDirective } from './dpe-select-value.directive';\r\n\r\n@Component({\r\n selector: 'dpe-column-type-editor',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-kind'\">Tipo</label>\r\n <select [id]=\"controlId() + '-kind'\" [dpeValue]=\"kind()\" (change)=\"onKind(text($event))\">\r\n @for (option of types; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (kind() === 'String') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-length'\">Lunghezza</label>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [id]=\"controlId() + '-length'\"\r\n [value]=\"value()?.length ?? ''\"\r\n (change)=\"onNumber('length', text($event))\"\r\n />\r\n </div>\r\n }\r\n\r\n @if (kind() === 'Number') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-precision'\">Precisione</label>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [id]=\"controlId() + '-precision'\"\r\n [value]=\"value()?.precision ?? ''\"\r\n (change)=\"onNumber('precision', text($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-scale'\">Decimali</label>\r\n <input\r\n type=\"number\"\r\n min=\"0\"\r\n [id]=\"controlId() + '-scale'\"\r\n [value]=\"value()?.scale ?? ''\"\r\n (change)=\"onNumber('scale', text($event))\"\r\n />\r\n </div>\r\n }\r\n </div>\r\n\r\n @if (kind() === 'Enum') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId() + '-values'\">Valori ammessi</label>\r\n <input\r\n type=\"text\"\r\n [id]=\"controlId() + '-values'\"\r\n [value]=\"allowedValues()\"\r\n placeholder=\"separati da virgola\"\r\n (change)=\"onAllowedValues(text($event))\"\r\n />\r\n </div>\r\n }\r\n `,\r\n})\r\nexport class DpeColumnTypeEditorComponent {\r\n readonly value = input<ColumnType | undefined>(undefined);\r\n readonly controlId = input('dpe-type');\r\n readonly valueChange = output<ColumnType>();\r\n\r\n protected readonly types = LOGICAL_TYPES;\r\n\r\n readonly kind = computed<LogicalType>(() => this.value()?.kind ?? 'String');\r\n\r\n readonly allowedValues = computed(() => (this.value()?.allowedValues ?? []).join(', '));\r\n\r\n protected onKind(kind: string): void {\r\n // Cambiare tipo **azzera** gli attributi dell'altro: una `length` rimasta su un `Number`\r\n // sarebbe un campo che il backend ignora oggi e rifiuta domani.\r\n this.valueChange.emit({ kind: kind as LogicalType });\r\n }\r\n\r\n protected onNumber(field: 'length' | 'precision' | 'scale', raw: string): void {\r\n const parsed = raw.trim() === '' ? undefined : Number(raw);\r\n this.valueChange.emit({\r\n ...(this.value() ?? { kind: this.kind() }),\r\n [field]: Number.isFinite(parsed) ? parsed : undefined,\r\n });\r\n }\r\n\r\n protected onAllowedValues(raw: string): void {\r\n const values = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n this.valueChange.emit({\r\n ...(this.value() ?? { kind: 'Enum' }),\r\n allowedValues: values.length > 0 ? values : undefined,\r\n });\r\n }\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLInputElement | HTMLSelectElement).value;\r\n }\r\n}\r\n","/**\r\n * Ispettore del nodo personalizzato.\r\n *\r\n * `outputFields` non e' un campo come gli altri: **e' l'unica cosa che tiene in piedi lo schema\r\n * a valle** (**I4**). Senza uno schema dichiarato la propagazione si interrompe e tutto cio' che\r\n * sta dopo diventa invalidabile — quindi l'avviso non e' generico, dice esattamente questo.\r\n *\r\n * Come il `Forecast`, e' modellato e non compilabile in v1.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n ColumnType,\r\n CustomNode,\r\n CustomNodeParameter,\r\n DeclaredField,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\n@Component({\r\n selector: 'dpe-custom-node-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note dpe-note--not-compilable\">\r\n Nodo modellato per intero ma <strong>non traducibile in SQL</strong> nella versione 1.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"cn-extension\">Estensione</label>\r\n <input\r\n id=\"cn-extension\"\r\n type=\"text\"\r\n [value]=\"node().extensionName ?? ''\"\r\n (change)=\"setField('extensionName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"cn-namespace\">Namespace</label>\r\n <input\r\n id=\"cn-namespace\"\r\n type=\"text\"\r\n [value]=\"node().extensionNamespace ?? ''\"\r\n (change)=\"setField('extensionNamespace', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Sorgenti ({{ sources().length }})</h4>\r\n @for (source of sources(); track $index) {\r\n <div class=\"dpe-row\">\r\n <span>{{ $index + 1 }}. {{ source || 'non collegata' }}</span>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la posizione ' + ($index + 1)\"\r\n (click)=\"removeSource($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addSource()\">Aggiungi posizione</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Parametri dell’estensione</h4>\r\n @for (parameter of nodeParameters(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n [value]=\"parameter.name\"\r\n [attr.aria-label]=\"'Nome del parametro ' + ($index + 1)\"\r\n (change)=\"patchParameter($index, { name: valueOf($event) })\"\r\n />\r\n <input\r\n type=\"text\"\r\n [value]=\"parameter.value\"\r\n [attr.aria-label]=\"'Valore del parametro ' + ($index + 1)\"\r\n (change)=\"patchParameter($index, { value: valueOf($event) })\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il parametro\"\r\n (click)=\"removeParameter($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addParameter()\">Aggiungi parametro</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Schema in uscita</h4>\r\n <p class=\"dpe-note dpe-note--warning\">\r\n Va dichiarato qui: non esiste un registro delle estensioni da cui ricavarlo. Se manca,\r\n la propagazione dello schema si interrompe e <strong>tutto cio’ che sta a valle</strong>\r\n diventa invalidabile.\r\n </p>\r\n @for (field of outputFields(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'cn-field-' + $index\">Nome</label>\r\n <input\r\n [id]=\"'cn-field-' + $index\"\r\n type=\"text\"\r\n [value]=\"field.name\"\r\n (change)=\"patchOutput($index, { name: valueOf($event) })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la colonna ' + field.name\"\r\n (click)=\"removeOutput($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n <dpe-column-type-editor\r\n [value]=\"field.type\"\r\n [controlId]=\"'cn-type-' + $index\"\r\n (valueChange)=\"patchOutput($index, { type: $event })\"\r\n />\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addOutput()\">Aggiungi colonna</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeCustomNodeInspectorComponent extends DpeNodeInspectorBase<CustomNode> {\r\n override readonly collection: DpeNodeCollectionName = 'customNodes';\r\n\r\n readonly sources = computed<readonly string[]>(() => this.node().sources ?? []);\r\n readonly nodeParameters = computed<readonly CustomNodeParameter[]>(\r\n () => this.node().parameters ?? [],\r\n );\r\n readonly outputFields = computed<readonly DeclaredField[]>(() => this.node().outputFields ?? []);\r\n\r\n protected addSource(): void {\r\n this.patch({ sources: [...this.sources(), ''] });\r\n }\r\n\r\n protected removeSource(index: number): void {\r\n this.patch({ sources: this.sources().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected addParameter(): void {\r\n this.patch({ parameters: [...this.nodeParameters(), { name: '', value: '' }] });\r\n }\r\n\r\n protected removeParameter(index: number): void {\r\n this.patch({\r\n parameters: this.nodeParameters().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchParameter(index: number, patch: Partial<CustomNodeParameter>): void {\r\n this.patch({\r\n parameters: this.nodeParameters().map((parameter, position) =>\r\n position === index ? { ...parameter, ...patch } : parameter,\r\n ),\r\n });\r\n }\r\n\r\n protected addOutput(): void {\r\n this.patch({\r\n outputFields: [...this.outputFields(), { name: '', type: { kind: 'String' } }],\r\n });\r\n }\r\n\r\n protected removeOutput(index: number): void {\r\n this.patch({ outputFields: this.outputFields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchOutput(index: number, patch: Partial<DeclaredField> & { type?: ColumnType }): void {\r\n this.patch({\r\n outputFields: this.outputFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore della sorgente.\r\n *\r\n * I campi che compaiono dipendono dal `kind`: `tableName` per `Table`, le opzioni CSV per\r\n * `Csv`, il nome del dataset per `ExternalDataset`. Il `declaredType` di un campo si mostra\r\n * **solo** dove serve — per `Table` il tipo lo da' il provider di metadati e quello dichiarato\r\n * viene ignorato: mostrarlo farebbe credere di poterlo decidere.\r\n *\r\n * I tre esiti del provider (ADR 0004) restano distinti: tabella dichiarata, dichiarata **senza\r\n * campi**, sconosciuta. Nel secondo caso i nomi dei campi si digitano a mano e non c'e' niente\r\n * da correggere; nel terzo la diagnostica autorevole e' `DPE_REF_UNKNOWN_TABLE` del backend.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, effect, inject } from '@angular/core';\r\n\r\nimport { DpeMetadataStore } from '../../core/dpe-metadata.store';\r\nimport {\r\n ColumnType,\r\n CsvDelimiter,\r\n DataSourceField,\r\n DataSourceKind,\r\n DataSourceNode,\r\n DpeNodeCollectionName,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly DataSourceKind[] = ['Table', 'Csv', 'ExternalDataset'];\r\nconst DELIMITERS: readonly CsvDelimiter[] = ['Comma', 'Semicolon', 'Tab', 'Pipe', 'Caret', 'Backquote'];\r\n\r\n@Component({\r\n selector: 'dpe-data-source-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-kind\">Tipo di sorgente</label>\r\n <select id=\"ds-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @switch (node().kind) {\r\n @case ('Table') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-table\">Tabella</label>\r\n <input\r\n id=\"ds-table\"\r\n type=\"text\"\r\n list=\"ds-table-options\"\r\n [value]=\"node().tableName ?? ''\"\r\n [attr.aria-invalid]=\"hasIssueOn('tableName')\"\r\n (change)=\"setField('tableName', valueOf($event))\"\r\n />\r\n <!--\r\n Elenco proposto (datalist) e non tendina chiusa: le tabelle possono essere molte e\r\n il nome resta digitabile — un catalogo incompleto non deve impedire di scrivere.\r\n -->\r\n <datalist id=\"ds-table-options\">\r\n @for (table of tables(); track $index) {\r\n <option [value]=\"table.name\">{{ table.description || table.name }}</option>\r\n }\r\n </datalist>\r\n <p class=\"dpe-field__hint\">{{ tableHint() }}</p>\r\n @for (issue of issuesOn('tableName'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n }\r\n @case ('Csv') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-location\">Posizione del file</label>\r\n <input\r\n id=\"ds-location\"\r\n type=\"text\"\r\n [value]=\"node().csvOptions?.location ?? ''\"\r\n (change)=\"patchCsv({ location: valueOf($event) })\"\r\n />\r\n <p class=\"dpe-field__hint\">Identificatore opaco: lo risolve l’host, non la libreria.</p>\r\n </div>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-delimiter\">Separatore</label>\r\n <select\r\n id=\"ds-delimiter\"\r\n [dpeValue]=\"node().csvOptions?.delimiter ?? 'Comma'\"\r\n (change)=\"patchCsv({ delimiter: valueOf($event) })\"\r\n >\r\n @for (delimiter of delimiters; track $index) {\r\n <option [value]=\"delimiter\">{{ delimiter }}</option>\r\n }\r\n </select>\r\n </div>\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().csvOptions?.hasHeaderRow ?? true\"\r\n (change)=\"patchCsv({ hasHeaderRow: checkedOf($event) })\"\r\n />\r\n Prima riga di intestazione\r\n </label>\r\n </div>\r\n }\r\n @case ('ExternalDataset') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"ds-dataset\">Dataset esterno</label>\r\n <input\r\n id=\"ds-dataset\"\r\n type=\"text\"\r\n [value]=\"node().externalDatasetName ?? ''\"\r\n (change)=\"setField('externalDatasetName', valueOf($event))\"\r\n />\r\n </div>\r\n }\r\n }\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo: la sorgente non produce colonne.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Nome</th>\r\n <th>Alias</th>\r\n @if (declaresTypes()) {\r\n <th>Tipo</th>\r\n }\r\n <th>PK</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"ds-field-options\"\r\n [value]=\"field.name\"\r\n [attr.aria-label]=\"'Nome del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { name: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias ?? ''\"\r\n [attr.aria-label]=\"'Alias del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n @if (declaresTypes()) {\r\n <td>\r\n <dpe-column-type-editor\r\n [value]=\"field.declaredType\"\r\n [controlId]=\"'ds-field-' + $index\"\r\n (valueChange)=\"patchField($index, { declaredType: $event })\"\r\n />\r\n </td>\r\n }\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"field.isPrimaryKey ?? false\"\r\n [attr.aria-label]=\"'Chiave primaria del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { isPrimaryKey: checkedOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi il campo ' + field.name\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"ds-field-options\">\r\n @for (candidate of providerFields(); track $index) {\r\n <option [value]=\"candidate.name\">{{ candidate.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeDataSourceInspectorComponent extends DpeNodeInspectorBase<DataSourceNode> {\r\n private readonly metadata = inject(DpeMetadataStore);\r\n\r\n override readonly collection: DpeNodeCollectionName = 'dataSources';\r\n\r\n protected readonly kinds = KINDS;\r\n protected readonly delimiters = DELIMITERS;\r\n\r\n readonly tables = computed(() => this.metadata.tables());\r\n\r\n readonly fields = computed<readonly DataSourceField[]>(() => this.node().fields ?? []);\r\n\r\n /** Il tipo si dichiara solo dove non c'e' un catalogo da interrogare. */\r\n readonly declaresTypes = computed(() => this.node().kind !== 'Table');\r\n\r\n readonly providerFields = computed(() => {\r\n const tableName = this.node().tableName;\r\n if (!tableName) {\r\n return [];\r\n }\r\n return this.metadata.stateOf(tableName)?.table?.fields ?? [];\r\n });\r\n\r\n /** I tre esiti in una frase: sono situazioni diverse e vanno dette diverse. */\r\n readonly tableHint = computed(() => {\r\n const tableName = this.node().tableName;\r\n if (!tableName) {\r\n return 'Nome noto al provider di metadati dell’host, non al catalogo del database.';\r\n }\r\n const state = this.metadata.stateOf(tableName);\r\n if (!state) {\r\n return 'Lettura dei metadati in corso…';\r\n }\r\n switch (state.outcome) {\r\n case 'Declared':\r\n return `Tabella dichiarata: ${state.table?.fields?.length ?? 0} campi noti.`;\r\n case 'DeclaredWithoutFields':\r\n return 'Tabella dichiarata senza campi: i nomi si scrivono a mano, non c’e’ nulla da correggere.';\r\n case 'Unknown':\r\n return 'Tabella sconosciuta al provider: la validazione lo segnalera’.';\r\n default:\r\n return '';\r\n }\r\n });\r\n\r\n constructor() {\r\n super();\r\n this.metadata.loadTables();\r\n // Si chiede la descrizione della tabella riferita, una volta per nome. La cache e' dello\r\n // store: cambiare nodo e tornare indietro non rifa' la chiamata.\r\n effect(() => {\r\n const tableName = this.node().tableName;\r\n if (tableName) {\r\n this.metadata.describe(tableName);\r\n }\r\n });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { name: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(\r\n index: number,\r\n patch: Partial<DataSourceField> & { declaredType?: ColumnType },\r\n ): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected patchCsv(patch: Partial<{ location: string; delimiter: string; hasHeaderRow: boolean }>): void {\r\n const current = this.node().csvOptions ?? { location: '' };\r\n this.patch({\r\n csvOptions: { ...current, ...(patch as Partial<typeof current>) },\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del filtro.\r\n *\r\n * Il vincolo condizionale del contratto governa cosa si vede: con `isDynamic` falso servono i\r\n * criteri e la `condition`; con `isDynamic` vero serve il nome del parametro di filtro, e i\r\n * criteri **non** si mostrano affatto. Mostrarli entrambi renderebbe rappresentabile uno stato\r\n * che il backend rifiuta (`DPE_MODEL_CONDITIONAL_FORBIDDEN`).\r\n *\r\n * `condition` non e' SQL: e' una combinazione booleana dei numeri di sequenza dei criteri\r\n * (`1 AND (2 OR 3)`), ed e' l'unico linguaggio che il backend parsifica davvero. L'etichetta lo\r\n * dice, perche' una casella accanto a \"SQL nativo\" altrove invita a scriverci dentro SQL.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n FilterCriterion,\r\n FilterNode,\r\n FilterOperator,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst OPERATORS: readonly FilterOperator[] = [\r\n 'Equals',\r\n 'NotEquals',\r\n 'GreaterThan',\r\n 'GreaterThanOrEqual',\r\n 'LessThan',\r\n 'LessThanOrEqual',\r\n 'StartsWith',\r\n 'EndsWith',\r\n 'Contains',\r\n 'DoesNotContain',\r\n 'IsNull',\r\n 'IsNotNull',\r\n 'In',\r\n 'NotIn',\r\n];\r\n\r\n/** Gli unici operatori che non prendono un valore: e' forma del controllo, non validazione. */\r\nconst UNARY: readonly FilterOperator[] = ['IsNull', 'IsNotNull'];\r\n\r\n@Component({\r\n selector: 'dpe-filter-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().isDynamic ?? false\"\r\n (change)=\"setField('isDynamic', checkedOf($event))\"\r\n />\r\n Filtro dinamico (i criteri arrivano da un parametro)\r\n </label>\r\n\r\n @if (node().isDynamic) {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"filter-parameter\">Parametro di filtro</label>\r\n <select\r\n id=\"filter-parameter\"\r\n [dpeValue]=\"node().filterParameterName ?? ''\"\r\n (change)=\"setField('filterParameterName', valueOf($event))\"\r\n >\r\n <option value=\"\">— non impostato —</option>\r\n @for (parameter of filterParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.label }} ({{ parameter.name }})</option>\r\n }\r\n </select>\r\n @if (filterParameters().length === 0) {\r\n <p class=\"dpe-field__hint\">\r\n Nessun parametro con ruolo <code>Filter</code> dichiarato sulla definizione.\r\n </p>\r\n }\r\n </div>\r\n } @else {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Criteri</h4>\r\n @if (criteria().length === 0) {\r\n <p class=\"dpe-empty\">Nessun criterio.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Seq.</th>\r\n <th>Colonna</th>\r\n <th>Operatore</th>\r\n <th>Valore</th>\r\n <th>Parametro</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (criterion of criteria(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"criterion.sequence\"\r\n [attr.aria-label]=\"'Sequenza del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { sequence: number(valueOf($event)) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"filter-columns\"\r\n [value]=\"criterion.sourceFieldName\"\r\n [attr.aria-label]=\"'Colonna del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { sourceFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"criterion.operator\"\r\n [attr.aria-label]=\"'Operatore del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { operator: operator(valueOf($event)) })\"\r\n >\r\n @for (option of operators; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n @if (!isUnary(criterion.operator)) {\r\n <input\r\n type=\"text\"\r\n [value]=\"criterion.value ?? ''\"\r\n [disabled]=\"!!criterion.inputVariable\"\r\n [attr.aria-label]=\"'Valore del criterio ' + ($index + 1)\"\r\n (change)=\"patchCriterion($index, { value: valueOf($event) || undefined })\"\r\n />\r\n }\r\n </td>\r\n <td>\r\n @if (!isUnary(criterion.operator)) {\r\n <!--\r\n Valore e parametro sono mutuamente esclusivi: sceglierne uno disabilita\r\n l’altro, così lo stato \"entrambi\" non e’ rappresentabile.\r\n -->\r\n <select\r\n [dpeValue]=\"criterion.inputVariable ?? ''\"\r\n [attr.aria-label]=\"'Parametro del criterio ' + ($index + 1)\"\r\n (change)=\"onInputVariable($index, valueOf($event))\"\r\n >\r\n <option value=\"\">— nessuno —</option>\r\n @for (parameter of valueParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }}</option>\r\n }\r\n </select>\r\n }\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi il criterio ' + criterion.sequence\"\r\n (click)=\"removeCriterion($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"filter-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addCriterion()\">Aggiungi criterio</button>\r\n </div>\r\n </section>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"filter-condition\">Condizione sui numeri di sequenza</label>\r\n <input\r\n id=\"filter-condition\"\r\n type=\"text\"\r\n [value]=\"node().condition ?? ''\"\r\n placeholder=\"1 AND (2 OR 3)\"\r\n [attr.aria-invalid]=\"hasIssueOn('condition')\"\r\n (change)=\"setField('condition', valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Non e’ SQL: solo numeri di sequenza, <code>AND</code>, <code>OR</code>,\r\n <code>NOT</code> e parentesi.\r\n </p>\r\n @for (issue of issuesOn('condition'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n }\r\n </div>\r\n `,\r\n})\r\nexport class DpeFilterInspectorComponent extends DpeNodeInspectorBase<FilterNode> {\r\n override readonly collection: DpeNodeCollectionName = 'filters';\r\n\r\n protected readonly operators = OPERATORS;\r\n\r\n readonly criteria = computed<readonly FilterCriterion[]>(() => this.node().criteria ?? []);\r\n\r\n readonly filterParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Filter'),\r\n );\r\n\r\n readonly valueParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Value'),\r\n );\r\n\r\n protected isUnary(operator: FilterOperator): boolean {\r\n return UNARY.includes(operator);\r\n }\r\n\r\n protected operator(value: string): FilterOperator {\r\n return value as FilterOperator;\r\n }\r\n\r\n protected number(value: string): number {\r\n // Forma del campo: un numero di sequenza non numerico non e' rappresentabile, e 1 e' il\r\n // minimo dichiarato. Non e' validazione: l'unicita' la verifica il backend.\r\n const parsed = Number(value);\r\n return Number.isFinite(parsed) && parsed >= 1 ? Math.trunc(parsed) : 1;\r\n }\r\n\r\n protected addCriterion(): void {\r\n const nextSequence =\r\n this.criteria().reduce((max, criterion) => Math.max(max, criterion.sequence), 0) + 1;\r\n this.patch({\r\n criteria: [\r\n ...this.criteria(),\r\n { sequence: nextSequence, sourceFieldName: '', operator: 'Equals' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeCriterion(index: number): void {\r\n this.patch({ criteria: this.criteria().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchCriterion(index: number, patch: Partial<FilterCriterion>): void {\r\n this.patch({\r\n criteria: this.criteria().map((criterion, position) =>\r\n position === index ? { ...criterion, ...patch } : criterion,\r\n ),\r\n });\r\n }\r\n\r\n /** Scegliere un parametro **toglie** il valore letterale: sono esclusivi per contratto. */\r\n protected onInputVariable(index: number, name: string): void {\r\n this.patchCriterion(index, {\r\n inputVariable: name === '' ? undefined : name,\r\n value: name === '' ? this.criteria()[index]?.value : undefined,\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore della previsione.\r\n *\r\n * Il nodo e' **modellato per intero e non compilabile in v1**: l'avviso sta in testa e non a\r\n * pie' di pagina, perche' e' la prima cosa da sapere prima di costruirci una pipeline intorno.\r\n * Non e' un errore dell'utente — e' `DPE_NODE_NOT_COMPILABLE`, l'unico codice che significa\r\n * \"hai fatto bene, siamo noi\" — quindi il colore non e' quello dell'errore.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateFunction,\r\n DatePart,\r\n DpeNodeCollectionName,\r\n ForecastAccuracy,\r\n ForecastAggregationField,\r\n ForecastGroupField,\r\n ForecastModelType,\r\n ForecastNode,\r\n ForecastPeriodType,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst PERIOD_TYPES: readonly ForecastPeriodType[] = [\r\n 'Year',\r\n 'YearQuarter',\r\n 'YearMonth',\r\n 'YearWeek',\r\n 'YearMonthDay',\r\n 'FiscalYear',\r\n 'FiscalYearQuarter',\r\n 'FiscalYearMonth',\r\n 'FiscalYearWeek',\r\n];\r\n\r\nconst MODELS: readonly ForecastModelType[] = ['Auto', 'Additive', 'Multiplicative'];\r\nconst ACCURACIES: readonly ForecastAccuracy[] = ['None', 'Eighty', 'NinetyFive'];\r\nconst FUNCTIONS: readonly AggregateFunction[] = ['Sum', 'Avg', 'Min', 'Max', 'Count'];\r\nconst DATE_PARTS: readonly DatePart[] = [\r\n 'Second',\r\n 'Minute',\r\n 'Hour',\r\n 'Day',\r\n 'Week',\r\n 'Month',\r\n 'Quarter',\r\n 'Year',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-forecast-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note dpe-note--not-compilable\">\r\n Nodo modellato per intero ma <strong>non traducibile in SQL</strong> nella versione 1:\r\n puoi descriverlo e salvarlo, la compilazione lo rifiuta con\r\n <code>DPE_NODE_NOT_COMPILABLE</code>. Non c’e’ niente da correggere.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-date\">Campo data</label>\r\n <input\r\n id=\"fc-date\"\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"node().dateFieldName ?? ''\"\r\n (change)=\"setField('dateFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-period\">Periodo</label>\r\n <select\r\n id=\"fc-period\"\r\n [dpeValue]=\"node().periodType ?? 'YearMonth'\"\r\n (change)=\"setField('periodType', valueOf($event))\"\r\n >\r\n @for (period of periodTypes; track $index) {\r\n <option [value]=\"period\">{{ period }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-count\">Numero di periodi</label>\r\n <input\r\n id=\"fc-count\"\r\n type=\"number\"\r\n min=\"1\"\r\n max=\"100\"\r\n [value]=\"node().periodCount ?? 1\"\r\n (change)=\"setField('periodCount', toNumber(valueOf($event)))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-start\">Alias inizio periodo</label>\r\n <input\r\n id=\"fc-start\"\r\n type=\"text\"\r\n [value]=\"node().periodStartFieldName ?? ''\"\r\n (change)=\"setField('periodStartFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-model\">Modello</label>\r\n <select\r\n id=\"fc-model\"\r\n [dpeValue]=\"node().modelType ?? 'Auto'\"\r\n (change)=\"setField('modelType', valueOf($event))\"\r\n >\r\n @for (model of models; track $index) {\r\n <option [value]=\"model\">{{ model }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-seasonality\">Stagionalita’</label>\r\n <input\r\n id=\"fc-seasonality\"\r\n type=\"number\"\r\n min=\"2\"\r\n max=\"24\"\r\n [value]=\"node().seasonality ?? ''\"\r\n placeholder=\"automatica\"\r\n (change)=\"setField('seasonality', toNumber(valueOf($event)))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"fc-accuracy\">Intervallo di confidenza</label>\r\n <select\r\n id=\"fc-accuracy\"\r\n [dpeValue]=\"node().accuracyPercent ?? 'None'\"\r\n (change)=\"setField('accuracyPercent', valueOf($event))\"\r\n >\r\n @for (accuracy of accuracies; track $index) {\r\n <option [value]=\"accuracy\">{{ accuracy }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().excludesLastPeriod ?? false\"\r\n (change)=\"setField('excludesLastPeriod', checkedOf($event))\"\r\n />\r\n Escludi l’ultimo periodo (spesso incompleto)\r\n </label>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi da prevedere</h4>\r\n @for (field of aggregationFields(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"field.fieldName\"\r\n [attr.aria-label]=\"'Campo ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { fieldName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.resultAlias\"\r\n [attr.aria-label]=\"'Alias ' + ($index + 1)\"\r\n (change)=\"patchAggregation($index, { resultAlias: valueOf($event) })\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeAggregation($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addAggregation()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Raggruppamenti</h4>\r\n @for (group of groupFields(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"fc-columns\"\r\n [value]=\"group.fieldName\"\r\n [attr.aria-label]=\"'Campo di raggruppamento ' + ($index + 1)\"\r\n (change)=\"patchGroup($index, { fieldName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"group.datePart ?? ''\"\r\n [attr.aria-label]=\"'Parte di data ' + ($index + 1)\"\r\n (change)=\"patchGroup($index, { datePart: asDatePart(valueOf($event)) })\"\r\n >\r\n <option value=\"\">— nessuna —</option>\r\n @for (part of dateParts; track $index) {\r\n <option [value]=\"part\">{{ part }}</option>\r\n }\r\n </select>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il raggruppamento\"\r\n (click)=\"removeGroup($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <p class=\"dpe-field__hint\">\r\n La parte di data e’ richiesta quando il campo e’ di tipo <code>DateTime</code>.\r\n </p>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addGroup()\">Aggiungi raggruppamento</button>\r\n </div>\r\n </section>\r\n\r\n <datalist id=\"fc-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeForecastInspectorComponent extends DpeNodeInspectorBase<ForecastNode> {\r\n override readonly collection: DpeNodeCollectionName = 'forecasts';\r\n\r\n protected readonly periodTypes = PERIOD_TYPES;\r\n protected readonly models = MODELS;\r\n protected readonly accuracies = ACCURACIES;\r\n protected readonly functions = FUNCTIONS;\r\n protected readonly dateParts = DATE_PARTS;\r\n\r\n readonly aggregationFields = computed<readonly ForecastAggregationField[]>(\r\n () => this.node().aggregationFields ?? [],\r\n );\r\n\r\n readonly groupFields = computed<readonly ForecastGroupField[]>(() => this.node().groupFields ?? []);\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected asDatePart(value: string): DatePart | undefined {\r\n return value === '' ? undefined : (value as DatePart);\r\n }\r\n\r\n protected addAggregation(): void {\r\n this.patch({\r\n aggregationFields: [\r\n ...this.aggregationFields(),\r\n { fieldName: '', function: 'Sum', resultAlias: '' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeAggregation(index: number): void {\r\n this.patch({\r\n aggregationFields: this.aggregationFields().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchAggregation(index: number, patch: Partial<ForecastAggregationField>): void {\r\n this.patch({\r\n aggregationFields: this.aggregationFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected addGroup(): void {\r\n this.patch({ groupFields: [...this.groupFields(), { fieldName: '' }] });\r\n }\r\n\r\n protected removeGroup(index: number): void {\r\n this.patch({ groupFields: this.groupFields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchGroup(index: number, patch: Partial<ForecastGroupField>): void {\r\n this.patch({\r\n groupFields: this.groupFields().map((group, position) =>\r\n position === index ? { ...group, ...patch } : group,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del percorso gerarchico.\r\n *\r\n * E' il nodo che pone il vincolo di capacita' sul dialetto: richiede CTE ricorsive. Non lo\r\n * verifichiamo qui — `DPE_DIALECT_UNSUPPORTED` arriva dalla validazione — ma lo diciamo, perche'\r\n * un utente che non sa che questo nodo dipende dal dialetto non capirebbe la diagnostica.\r\n *\r\n * I campi di aggregazione compaiono solo con `isAggregationRequired`: e' il vincolo condizionale\r\n * del contratto, e senza il flag sono campi che il backend rifiuta.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n AggregateField,\r\n AggregateFunction,\r\n DpeNodeCollectionName,\r\n HierarchyPathNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst FUNCTIONS: readonly AggregateFunction[] = [\r\n 'Count',\r\n 'CountDistinct',\r\n 'Sum',\r\n 'Min',\r\n 'Max',\r\n 'Avg',\r\n];\r\n\r\n@Component({\r\n selector: 'dpe-hierarchy-path-inspector',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <p class=\"dpe-note\">\r\n Richiede le CTE ricorsive del dialetto di destinazione: se il dialetto scelto non le\r\n supporta, la validazione lo segnala come limite del <strong>dialetto</strong>, non della\r\n definizione.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-self\">Campo chiave</label>\r\n <input\r\n id=\"hp-self\"\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"node().selfFieldName ?? ''\"\r\n (change)=\"setField('selfFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-parent\">Campo padre</label>\r\n <input\r\n id=\"hp-parent\"\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"node().parentFieldName ?? ''\"\r\n (change)=\"setField('parentFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-path\">Alias della colonna di percorso</label>\r\n <input\r\n id=\"hp-path\"\r\n type=\"text\"\r\n [value]=\"node().pathFieldName ?? ''\"\r\n (change)=\"setField('pathFieldName', valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">La produce il backend: e’ di tipo <code>String</code> e non nulla.</p>\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().includesSelfValue ?? true\"\r\n (change)=\"setField('includesSelfValue', checkedOf($event))\"\r\n />\r\n Includi il valore del nodo corrente nel percorso\r\n </label>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"hp-rollup\">Alias della percentuale di rollup</label>\r\n <input\r\n id=\"hp-rollup\"\r\n type=\"text\"\r\n [value]=\"node().rollupPercentageFieldName ?? ''\"\r\n (change)=\"setField('rollupPercentageFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().isAggregationRequired ?? false\"\r\n (change)=\"setField('isAggregationRequired', checkedOf($event))\"\r\n />\r\n Aggrega lungo la gerarchia\r\n </label>\r\n\r\n @if (node().isAggregationRequired) {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi aggregati</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo: con l’aggregazione attiva ne serve almeno uno.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Funzione</th>\r\n <th>Colonna</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <select\r\n [value]=\"field.function\"\r\n [attr.aria-label]=\"'Funzione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { function: asFunction(valueOf($event)) })\"\r\n >\r\n @for (option of functions; track $index) {\r\n <option [value]=\"option\">{{ option }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"hp-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"field.function === 'Count'\"\r\n [attr.aria-label]=\"'Colonna ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n }\r\n\r\n <datalist id=\"hp-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeHierarchyPathInspectorComponent extends DpeNodeInspectorBase<HierarchyPathNode> {\r\n override readonly collection: DpeNodeCollectionName = 'hierarchyPaths';\r\n\r\n protected readonly functions = FUNCTIONS;\r\n\r\n readonly fields = computed<readonly AggregateField[]>(() => this.node().aggregateFields ?? []);\r\n\r\n protected asFunction(value: string): AggregateFunction {\r\n return value as AggregateFunction;\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ aggregateFields: [...this.fields(), { function: 'Sum', alias: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ aggregateFields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<AggregateField>): void {\r\n this.patch({\r\n aggregateFields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * Ispettore del join.\r\n *\r\n * Due cose che il canvas non puo' dire e che quindi stanno qui: quale sorgente e' la\r\n * **primaria** (il lato che sopravvive in un `LeftOuter`) e lo **schema di uscita esplicito** —\r\n * un join produce solo i campi dichiarati in `fields`, non l'unione dei due lati.\r\n *\r\n * `allowsMultipleLookupValues` compare solo con `kind === 'Lookup'`: altrove il contratto lo\r\n * dichiara non significativo, e un interruttore che non fa niente e' peggio di un interruttore\r\n * assente.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n JoinKey,\r\n JoinKind,\r\n JoinNode,\r\n JoinResultField,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly JoinKind[] = ['Inner', 'LeftOuter', 'RightOuter', 'FullOuter', 'Lookup'];\r\n\r\n@Component({\r\n selector: 'dpe-join-inspector',\r\n standalone: true,\r\n imports: [DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"join-kind\">Tipo di join</label>\r\n <select id=\"join-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n @for (issue of issuesOn('kind'); track $index) {\r\n <!--\r\n Un FullOuter su SQLite e’ DPE_DIALECT_UNSUPPORTED: il messaggio arriva da qui e non\r\n da un controllo locale, perche’ le capacita’ del dialetto le conosce il backend.\r\n -->\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Sorgente primaria</span>\r\n <p class=\"dpe-field__hint\">{{ node().primarySourceName || 'non collegata' }}</p>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Sorgente secondaria</span>\r\n <p class=\"dpe-field__hint\">{{ node().secondarySourceName || 'non collegata' }}</p>\r\n </div>\r\n </div>\r\n <p class=\"dpe-field__hint\">Le sorgenti si collegano sul canvas, sulle due porte in alto.</p>\r\n\r\n @if (node().kind === 'Lookup') {\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().allowsMultipleLookupValues ?? false\"\r\n (change)=\"setField('allowsMultipleLookupValues', checkedOf($event))\"\r\n />\r\n Ammetti piu’ corrispondenze sul lato secondario\r\n </label>\r\n }\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Chiavi</h4>\r\n @if (keys().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna chiave.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Campo primario</th>\r\n <th>Campo secondario</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (key of keys(); track $index) {\r\n <tr>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"join-primary-columns\"\r\n [value]=\"key.primaryFieldName\"\r\n [attr.aria-label]=\"'Campo primario della chiave ' + ($index + 1)\"\r\n (change)=\"patchKey($index, { primaryFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n list=\"join-secondary-columns\"\r\n [value]=\"key.secondaryFieldName\"\r\n [attr.aria-label]=\"'Campo secondario della chiave ' + ($index + 1)\"\r\n (change)=\"patchKey($index, { secondaryFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la chiave\"\r\n (click)=\"removeKey($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addKey()\">Aggiungi chiave</button>\r\n </div>\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Campi in uscita</h4>\r\n <p class=\"dpe-field__hint\">\r\n Lo schema del join e’ <strong>solo</strong> questo elenco: cio’ che non e’ dichiarato\r\n qui non arriva a valle.\r\n </p>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo dichiarato.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Da</th>\r\n <th>Campo</th>\r\n <th>Alias</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <!--\r\n Un elenco chiuso alle due sorgenti del nodo: il contratto dice che\r\n la sorgente del campo deve essere una delle due, e con una casella di testo\r\n digitarne una terza sarebbe possibile.\r\n -->\r\n <select\r\n [dpeValue]=\"field.sourceName\"\r\n [attr.aria-label]=\"'Sorgente del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceName: valueOf($event) })\"\r\n >\r\n <option value=\"\">—</option>\r\n @if (node().primarySourceName) {\r\n <option [value]=\"node().primarySourceName!\">\r\n {{ node().primarySourceName }} (primaria)\r\n </option>\r\n }\r\n @if (node().secondarySourceName) {\r\n <option [value]=\"node().secondarySourceName!\">\r\n {{ node().secondarySourceName }} (secondaria)\r\n </option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [attr.list]=\"columnListIdFor(field)\"\r\n [value]=\"field.sourceFieldName\"\r\n [attr.aria-label]=\"'Campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n [attr.aria-label]=\"'Alias del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { alias: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi il campo\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi campo</button>\r\n </div>\r\n </section>\r\n\r\n <datalist id=\"join-primary-columns\">\r\n @for (column of primaryColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <datalist id=\"join-secondary-columns\">\r\n @for (column of secondaryColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeJoinInspectorComponent extends DpeNodeInspectorBase<JoinNode> {\r\n override readonly collection: DpeNodeCollectionName = 'joins';\r\n\r\n protected readonly kinds = KINDS;\r\n\r\n readonly keys = computed<readonly JoinKey[]>(() => this.node().keys ?? []);\r\n readonly fields = computed<readonly JoinResultField[]>(() => this.node().fields ?? []);\r\n\r\n /** Gli schemi dei due lati, separati: qui `inputColumns` fusi non basterebbero. */\r\n readonly primaryColumns = computed(\r\n () => this.store.schemaByNode().get(this.node().primarySourceName ?? '')?.columns ?? [],\r\n );\r\n\r\n readonly secondaryColumns = computed(\r\n () => this.store.schemaByNode().get(this.node().secondarySourceName ?? '')?.columns ?? [],\r\n );\r\n\r\n /** L'elenco dei campi proposti segue il lato scelto sulla riga. */\r\n protected columnListIdFor(field: JoinResultField): string {\r\n return field.sourceName === this.node().secondarySourceName\r\n ? 'join-secondary-columns'\r\n : 'join-primary-columns';\r\n }\r\n\r\n protected addKey(): void {\r\n this.patch({ keys: [...this.keys(), { primaryFieldName: '', secondaryFieldName: '' }] });\r\n }\r\n\r\n protected removeKey(index: number): void {\r\n this.patch({ keys: this.keys().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchKey(index: number, patch: Partial<JoinKey>): void {\r\n this.patch({\r\n keys: this.keys().map((key, position) => (position === index ? { ...key, ...patch } : key)),\r\n });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({\r\n fields: [\r\n ...this.fields(),\r\n { sourceName: this.node().primarySourceName ?? '', sourceFieldName: '', alias: '' },\r\n ],\r\n });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<JoinResultField>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n}\r\n","/**\r\n * L'editor di un'espressione.\r\n *\r\n * Per la v1 le espressioni sono **SQL nativo del dialetto della definizione** (ADR 0006): non\r\n * c'e' nessun parser, il testo passa verbatim nell'SQL generato. Tre conseguenze che\r\n * l'interfaccia deve rendere visibili, perche' nessuna di esse si vede scrivendo:\r\n *\r\n * 1. i **riferimenti dentro l'espressione non sono validati**: un nome di colonna sbagliato\r\n * non produce nessuna diagnostica e fallisce al momento dell'esecuzione, sul database;\r\n * 2. il **tipo dichiarato e' autorevole e non verificato**: se l'espressione produce altro,\r\n * nessuno lo dira';\r\n * 3. cio' che si scrive **verra' eseguito** sul database di destinazione: authoring di\r\n * un'espressione equivale a eseguire SQL arbitrario.\r\n *\r\n * Per questo l'avviso non e' un tooltip: e' testo accanto al campo. Un'interfaccia che facesse\r\n * sembrare questa casella un editor di formule verificate mentirebbe.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\r\n\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { SqlDialectKind } from '../../model/dpe-definition.model';\r\n\r\n@Component({\r\n selector: 'dpe-expression-editor',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"controlId()\">{{ label() }}</label>\r\n <textarea\r\n [id]=\"controlId()\"\r\n [value]=\"value() ?? ''\"\r\n [attr.placeholder]=\"placeholder()\"\r\n [attr.aria-describedby]=\"controlId() + '-warn'\"\r\n spellcheck=\"false\"\r\n (change)=\"valueChange.emit(text($event))\"\r\n ></textarea>\r\n <p class=\"dpe-note dpe-note--danger\" [id]=\"controlId() + '-warn'\">\r\n <span class=\"dpe-expr__dialect\">SQL {{ dialectLabel() }}</span> — il testo entra\r\n nell’istruzione generata così com’è: i riferimenti non vengono verificati e il tipo\r\n dichiarato non viene controllato. Quello che scrivi qui verrà <strong>eseguito</strong>\r\n sul database di destinazione.\r\n </p>\r\n @if (columnHint().length > 0) {\r\n <p class=\"dpe-field__hint\">Colonne in ingresso: {{ columnHint() }}</p>\r\n }\r\n </div>\r\n `,\r\n})\r\nexport class DpeExpressionEditorComponent {\r\n readonly label = input('Espressione');\r\n readonly value = input<string | undefined>(undefined);\r\n readonly placeholder = input('');\r\n readonly dialect = input.required<SqlDialectKind>();\r\n /**\r\n * I nomi delle colonne a monte, **come suggerimento** e non come elenco chiuso: sono cio'\r\n * che il backend ha propagato, ma dentro l'espressione si puo' scrivere qualunque SQL.\r\n */\r\n readonly columns = input<readonly string[]>([]);\r\n readonly controlId = input('dpe-expression');\r\n\r\n readonly valueChange = output<string>();\r\n\r\n readonly dialectLabel = computed(() => DPE_DIALECT_LABELS[this.dialect()] ?? this.dialect());\r\n\r\n /** Elenco troncato: dieci nomi sono un aiuto, cinquanta sono un muro di testo. */\r\n readonly columnHint = computed(() => {\r\n const columns = this.columns();\r\n const shown = columns.slice(0, 10).join(', ');\r\n return columns.length > 10 ? `${shown}, …` : shown;\r\n });\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLTextAreaElement).value;\r\n }\r\n}\r\n","/**\r\n * Ispettore della trasformazione.\r\n *\r\n * `kind` governa i campi, e la corrispondenza e' quella del contratto: `expressionFields` per\r\n * `Expression` e `ComputeRelative`, `droppedFields` per `Slice`, `partitionBy`/`orderBy` solo\r\n * per `ComputeRelative`. Il vincolo e' **esclusivo** in entrambi i sensi (per `Slice` le\r\n * espressioni devono essere vuote), quindi cambiare `kind` non lascia in giro i campi dell'altro\r\n * ramo: restano nel documento solo se l'utente li ha scritti in quel ramo.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n DpeNodeCollectionName,\r\n ExpressionField,\r\n OrderByField,\r\n TransformKind,\r\n TransformNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeColumnTypeEditorComponent } from '../shared/dpe-column-type-editor.component';\r\nimport { DpeExpressionEditorComponent } from '../shared/dpe-expression-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst KINDS: readonly TransformKind[] = ['Expression', 'Slice', 'ComputeRelative'];\r\n\r\n@Component({\r\n selector: 'dpe-transform-inspector',\r\n standalone: true,\r\n imports: [DpeColumnTypeEditorComponent, DpeExpressionEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-kind\">Tipo di trasformazione</label>\r\n <select id=\"tr-kind\" [dpeValue]=\"node().kind\" (change)=\"setField('kind', valueOf($event))\">\r\n @for (kind of kinds; track $index) {\r\n <option [value]=\"kind\">{{ kind }}</option>\r\n }\r\n </select>\r\n </div>\r\n\r\n @if (node().kind === 'Slice') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-dropped\">Colonne da eliminare</label>\r\n <input\r\n id=\"tr-dropped\"\r\n type=\"text\"\r\n [value]=\"droppedText()\"\r\n placeholder=\"separate da virgola\"\r\n (change)=\"onDropped(valueOf($event))\"\r\n />\r\n <p class=\"dpe-field__hint\">In ingresso: {{ columnHint() }}</p>\r\n </div>\r\n } @else {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Colonne calcolate</h4>\r\n @if (expressionFields().length === 0) {\r\n <p class=\"dpe-empty\">Nessuna colonna calcolata.</p>\r\n }\r\n @for (field of expressionFields(); track $index) {\r\n <div class=\"dpe-section\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" [attr.for]=\"'tr-alias-' + $index\">Alias</label>\r\n <input\r\n [id]=\"'tr-alias-' + $index\"\r\n type=\"text\"\r\n [value]=\"field.alias\"\r\n (change)=\"patchExpression($index, { alias: valueOf($event) })\"\r\n />\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--danger\"\r\n [attr.aria-label]=\"'Rimuovi la colonna ' + field.alias\"\r\n (click)=\"removeExpression($index)\"\r\n >\r\n Rimuovi\r\n </button>\r\n </div>\r\n\r\n <dpe-expression-editor\r\n [value]=\"field.expression\"\r\n [dialect]=\"dialect()\"\r\n [columns]=\"columnNames()\"\r\n [controlId]=\"'tr-expr-' + $index\"\r\n (valueChange)=\"patchExpression($index, { expression: $event })\"\r\n />\r\n\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Tipo dichiarato</span>\r\n <dpe-column-type-editor\r\n [value]=\"field.declaredType\"\r\n [controlId]=\"'tr-type-' + $index\"\r\n (valueChange)=\"patchExpression($index, { declaredType: $event })\"\r\n />\r\n <p class=\"dpe-field__hint\">\r\n Autorevole e <strong>non verificato</strong>: il backend si fida di questa\r\n dichiarazione e non controlla cosa l’espressione produca davvero.\r\n </p>\r\n </div>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addExpression()\">Aggiungi colonna</button>\r\n </div>\r\n </section>\r\n }\r\n\r\n @if (node().kind === 'ComputeRelative') {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Finestra</h4>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"tr-partition\">Partiziona per</label>\r\n <input\r\n id=\"tr-partition\"\r\n type=\"text\"\r\n [value]=\"partitionText()\"\r\n placeholder=\"colonne separate da virgola\"\r\n (change)=\"onPartition(valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <span class=\"dpe-field__label\">Ordina per</span>\r\n @for (order of orderBy(); track $index) {\r\n <div class=\"dpe-row\">\r\n <input\r\n type=\"text\"\r\n list=\"tr-columns\"\r\n [value]=\"order.columnName\"\r\n [attr.aria-label]=\"'Colonna di ordinamento ' + ($index + 1)\"\r\n (change)=\"patchOrder($index, { columnName: valueOf($event) })\"\r\n />\r\n <select\r\n [dpeValue]=\"order.direction ?? 'Ascending'\"\r\n [attr.aria-label]=\"'Direzione ' + ($index + 1)\"\r\n (change)=\"patchOrder($index, { direction: valueOf($event) === 'Descending' ? 'Descending' : 'Ascending' })\"\r\n >\r\n <option value=\"Ascending\">Ascendente</option>\r\n <option value=\"Descending\">Discendente</option>\r\n </select>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi l’ordinamento\"\r\n (click)=\"removeOrder($index)\"\r\n >\r\n ×\r\n </button>\r\n </div>\r\n }\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addOrder()\">Aggiungi ordinamento</button>\r\n </div>\r\n </div>\r\n </section>\r\n }\r\n\r\n <datalist id=\"tr-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n </div>\r\n `,\r\n})\r\nexport class DpeTransformInspectorComponent extends DpeNodeInspectorBase<TransformNode> {\r\n override readonly collection: DpeNodeCollectionName = 'transforms';\r\n\r\n protected readonly kinds = KINDS;\r\n\r\n readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n readonly expressionFields = computed<readonly ExpressionField[]>(\r\n () => this.node().expressionFields ?? [],\r\n );\r\n\r\n readonly orderBy = computed<readonly OrderByField[]>(() => this.node().orderBy ?? []);\r\n\r\n readonly droppedText = computed(() => (this.node().droppedFields ?? []).join(', '));\r\n readonly partitionText = computed(() => (this.node().partitionBy ?? []).join(', '));\r\n\r\n readonly columnNames = computed(() => this.inputColumns().map((column) => column.name));\r\n\r\n readonly columnHint = computed(() => {\r\n const names = this.columnNames();\r\n return names.length > 10 ? `${names.slice(0, 10).join(', ')}, …` : names.join(', ') || '—';\r\n });\r\n\r\n protected addExpression(): void {\r\n this.patch({\r\n expressionFields: [\r\n ...this.expressionFields(),\r\n { alias: '', expression: '', declaredType: { kind: 'String' } },\r\n ],\r\n });\r\n }\r\n\r\n protected removeExpression(index: number): void {\r\n this.patch({\r\n expressionFields: this.expressionFields().filter((_, position) => position !== index),\r\n });\r\n }\r\n\r\n protected patchExpression(index: number, patch: Partial<ExpressionField>): void {\r\n this.patch({\r\n expressionFields: this.expressionFields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected onDropped(raw: string): void {\r\n this.patch({ droppedFields: this.split(raw) });\r\n }\r\n\r\n protected onPartition(raw: string): void {\r\n this.patch({ partitionBy: this.split(raw) });\r\n }\r\n\r\n protected addOrder(): void {\r\n this.patch({ orderBy: [...this.orderBy(), { columnName: '' }] });\r\n }\r\n\r\n protected removeOrder(index: number): void {\r\n this.patch({ orderBy: this.orderBy().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchOrder(index: number, patch: Partial<OrderByField>): void {\r\n this.patch({\r\n orderBy: this.orderBy().map((order, position) =>\r\n position === index ? { ...order, ...patch } : order,\r\n ),\r\n });\r\n }\r\n\r\n private split(raw: string): string[] | undefined {\r\n const values = raw\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => value.length > 0);\r\n return values.length > 0 ? values : undefined;\r\n }\r\n}\r\n","/**\r\n * Ispettore della scrittura.\r\n *\r\n * `target` decide **cosa produce la libreria**: un'istruzione SQL per l'host (`Database`) oppure\r\n * un file (`Json`, `Csv`). E' la cosa piu' importante di questo nodo, quindi sta in cima, e i\r\n * campi che seguono cambiano di conseguenza: tabella e operazione solo per `Database`, opzioni di\r\n * formato solo per il file corrispondente.\r\n *\r\n * Due avvisi che non sono decorazione:\r\n *\r\n * - `Insert`/`Update`/`Upsert`/`Delete` **non vengono eseguiti** dalla libreria: determinano la\r\n * forma dell'SQL di lettura consegnato all'host. Un'interfaccia che li presentasse come azioni\r\n * farebbe credere che la pipeline scriva sul database;\r\n * - `onlyChangedRows` e' **dichiarato e non implementato** da noi: il change tracking e' dell'host\r\n * (ADR 0011) e non influenza l'SQL generato.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed } from '@angular/core';\r\n\r\nimport {\r\n CsvDelimiter,\r\n DpeNodeCollectionName,\r\n WritebackFieldMapping,\r\n WritebackFieldRole,\r\n WritebackNode,\r\n WritebackOperation,\r\n WritebackTargetKind,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeExpressionEditorComponent } from '../shared/dpe-expression-editor.component';\r\nimport { DpeSelectValueDirective } from '../shared/dpe-select-value.directive';\r\nimport { DpeNodeInspectorBase } from './dpe-node-inspector-base';\r\n\r\nconst TARGETS: readonly WritebackTargetKind[] = ['Database', 'Json', 'Csv'];\r\nconst OPERATIONS: readonly WritebackOperation[] = ['Insert', 'Update', 'Upsert', 'Delete'];\r\nconst ROLES: readonly WritebackFieldRole[] = ['Value', 'PrimaryKey', 'QualifierKey'];\r\nconst DELIMITERS: readonly CsvDelimiter[] = ['Comma', 'Semicolon', 'Tab', 'Pipe', 'Caret', 'Backquote'];\r\n\r\n@Component({\r\n selector: 'dpe-writeback-inspector',\r\n standalone: true,\r\n imports: [DpeExpressionEditorComponent, DpeSelectValueDirective],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-target\">Destinazione</label>\r\n <select id=\"wb-target\" [dpeValue]=\"node().target\" (change)=\"onTarget(valueOf($event))\">\r\n @for (target of targets; track $index) {\r\n <option [value]=\"target\">{{ target }}</option>\r\n }\r\n </select>\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-sequence\">Sequenza</label>\r\n <input\r\n id=\"wb-sequence\"\r\n type=\"number\"\r\n min=\"1\"\r\n [value]=\"node().sequence\"\r\n [attr.aria-invalid]=\"hasIssueOn('sequence')\"\r\n (change)=\"setField('sequence', toNumber(valueOf($event)) ?? 1)\"\r\n />\r\n @for (issue of issuesOn('sequence'); track $index) {\r\n <p class=\"dpe-field__issue\">{{ issue.code }} — {{ issue.message }}</p>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (node().target === 'Database') {\r\n <p class=\"dpe-note\">\r\n La libreria <strong>non scrive</strong> sul database: produce un’istruzione SQL di\r\n lettura e la consegna all’host, che la esegue. L’operazione scelta determina la forma di\r\n quell’istruzione (quali colonne, quale chiave di correlazione).\r\n </p>\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-table\">Tabella di destinazione</label>\r\n <input\r\n id=\"wb-table\"\r\n type=\"text\"\r\n [value]=\"node().tableName ?? ''\"\r\n [attr.aria-invalid]=\"hasIssueOn('tableName')\"\r\n (change)=\"setField('tableName', valueOf($event))\"\r\n />\r\n </div>\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-operation\">Operazione</label>\r\n <select\r\n id=\"wb-operation\"\r\n [dpeValue]=\"node().operation ?? 'Insert'\"\r\n (change)=\"setField('operation', valueOf($event))\"\r\n >\r\n @for (operation of operations; track $index) {\r\n <option [value]=\"operation\">{{ operation }}</option>\r\n }\r\n </select>\r\n </div>\r\n </div>\r\n\r\n @if (node().operation === 'Upsert') {\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-external-id\">Campo di identificazione esterna</label>\r\n <input\r\n id=\"wb-external-id\"\r\n type=\"text\"\r\n [value]=\"node().externalIdFieldName ?? ''\"\r\n (change)=\"setField('externalIdFieldName', valueOf($event))\"\r\n />\r\n </div>\r\n }\r\n\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().onlyChangedRows ?? false\"\r\n (change)=\"setField('onlyChangedRows', checkedOf($event))\"\r\n />\r\n Solo le righe cambiate\r\n </label>\r\n <p class=\"dpe-field__hint\">\r\n Dichiarazione per l’host: il confronto con lo stato precedente non lo fa la libreria e\r\n non cambia l’SQL generato.\r\n </p>\r\n }\r\n\r\n @if (node().target === 'Csv') {\r\n <div class=\"dpe-row\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"wb-delimiter\">Separatore</label>\r\n <select\r\n id=\"wb-delimiter\"\r\n [dpeValue]=\"node().csvOptions?.delimiter ?? 'Comma'\"\r\n (change)=\"patchCsv({ delimiter: asDelimiter(valueOf($event)) })\"\r\n >\r\n @for (delimiter of delimiters; track $index) {\r\n <option [value]=\"delimiter\">{{ delimiter }}</option>\r\n }\r\n </select>\r\n </div>\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().csvOptions?.includesHeaderRow ?? true\"\r\n (change)=\"patchCsv({ includesHeaderRow: checkedOf($event) })\"\r\n />\r\n Riga di intestazione\r\n </label>\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n Il quoting non e’ configurabile: si quota quando serve, con le virgolette raddoppiate.\r\n </p>\r\n }\r\n\r\n @if (node().target === 'Json') {\r\n <label class=\"dpe-check\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"node().jsonOptions?.indented ?? false\"\r\n (change)=\"patchJson(checkedOf($event))\"\r\n />\r\n JSON indentato\r\n </label>\r\n }\r\n\r\n <dpe-expression-editor\r\n label=\"Filtro sul risultato (facoltativo)\"\r\n [value]=\"node().filterCondition\"\r\n [dialect]=\"dialect()\"\r\n [columns]=\"columnNames()\"\r\n controlId=\"wb-filter\"\r\n (valueChange)=\"setField('filterCondition', $event)\"\r\n />\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Mappatura dei campi</h4>\r\n @if (fields().length === 0) {\r\n <p class=\"dpe-empty\">Nessun campo mappato.</p>\r\n } @else {\r\n <table class=\"dpe-table\">\r\n <thead>\r\n <tr>\r\n <th>Colonna a monte</th>\r\n <th>Parametro</th>\r\n <th>Campo di destinazione</th>\r\n <th>Ruolo</th>\r\n <th>Auto</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (field of fields(); track $index) {\r\n <tr>\r\n <td>\r\n <!-- Colonna e parametro sono esclusivi: scegliere l’uno svuota l’altro. -->\r\n <input\r\n type=\"text\"\r\n list=\"wb-columns\"\r\n [value]=\"field.sourceFieldName ?? ''\"\r\n [disabled]=\"!!field.runtimeParameterName || (field.isAutoGenerated ?? false)\"\r\n [attr.aria-label]=\"'Colonna del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { sourceFieldName: valueOf($event) || undefined })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.runtimeParameterName ?? ''\"\r\n [attr.aria-label]=\"'Parametro del campo ' + ($index + 1)\"\r\n (change)=\"onRuntimeParameter($index, valueOf($event))\"\r\n >\r\n <option value=\"\">—</option>\r\n @for (parameter of valueParameters(); track $index) {\r\n <option [value]=\"parameter.name\">{{ parameter.name }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"text\"\r\n [value]=\"field.targetFieldName\"\r\n [attr.aria-label]=\"'Campo di destinazione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { targetFieldName: valueOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <select\r\n [dpeValue]=\"field.role ?? 'Value'\"\r\n [attr.aria-label]=\"'Ruolo del campo ' + ($index + 1)\"\r\n (change)=\"patchField($index, { role: asRole(valueOf($event)) })\"\r\n >\r\n @for (role of roles; track $index) {\r\n <option [value]=\"role\">{{ role }}</option>\r\n }\r\n </select>\r\n </td>\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"field.isAutoGenerated ?? false\"\r\n [attr.aria-label]=\"'Generato dalla destinazione ' + ($index + 1)\"\r\n (change)=\"patchField($index, { isAutoGenerated: checkedOf($event) })\"\r\n />\r\n </td>\r\n <td>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn dpe-btn--icon dpe-btn--danger\"\r\n aria-label=\"Rimuovi la mappatura\"\r\n (click)=\"removeField($index)\"\r\n >\r\n ×\r\n </button>\r\n </td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n <datalist id=\"wb-columns\">\r\n @for (column of inputColumns(); track $index) {\r\n <option [value]=\"column.name\">{{ column.type.kind }}</option>\r\n }\r\n </datalist>\r\n <div>\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"addField()\">Aggiungi mappatura</button>\r\n </div>\r\n </section>\r\n </div>\r\n `,\r\n})\r\nexport class DpeWritebackInspectorComponent extends DpeNodeInspectorBase<WritebackNode> {\r\n override readonly collection: DpeNodeCollectionName = 'writebacks';\r\n\r\n protected readonly targets = TARGETS;\r\n protected readonly operations = OPERATIONS;\r\n protected readonly roles = ROLES;\r\n protected readonly delimiters = DELIMITERS;\r\n\r\n readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n readonly fields = computed<readonly WritebackFieldMapping[]>(() => this.node().fields ?? []);\r\n\r\n readonly columnNames = computed(() => this.inputColumns().map((column) => column.name));\r\n\r\n readonly valueParameters = computed(() =>\r\n this.parameters().filter((parameter) => parameter.role === 'Value'),\r\n );\r\n\r\n protected asRole(value: string): WritebackFieldRole {\r\n return value as WritebackFieldRole;\r\n }\r\n\r\n protected asDelimiter(value: string): CsvDelimiter {\r\n return value as CsvDelimiter;\r\n }\r\n\r\n /**\r\n * Cambiare destinazione **toglie** i campi dell'altra: `operation` e' richiesta per\r\n * `Database` e deve essere assente per `Json`/`Csv`, quindi lasciarla scritta produrrebbe\r\n * `DPE_MODEL_CONDITIONAL_FORBIDDEN` su un campo che l'utente non vede piu'.\r\n */\r\n protected onTarget(value: string): void {\r\n const target = value as WritebackTargetKind;\r\n this.patch({\r\n target,\r\n operation: target === 'Database' ? (this.node().operation ?? 'Insert') : undefined,\r\n tableName: target === 'Database' ? this.node().tableName : undefined,\r\n externalIdFieldName: target === 'Database' ? this.node().externalIdFieldName : undefined,\r\n csvOptions: target === 'Csv' ? this.node().csvOptions : undefined,\r\n jsonOptions: target === 'Json' ? this.node().jsonOptions : undefined,\r\n });\r\n }\r\n\r\n // Lo spread non esiste nelle espressioni dei template Angular: la fusione sta qui.\r\n protected patchJson(indented: boolean): void {\r\n this.patch({ jsonOptions: { ...(this.node().jsonOptions ?? {}), indented } });\r\n }\r\n\r\n protected patchCsv(patch: Partial<{ delimiter: CsvDelimiter; includesHeaderRow: boolean }>): void {\r\n this.patch({ csvOptions: { ...(this.node().csvOptions ?? {}), ...patch } });\r\n }\r\n\r\n protected addField(): void {\r\n this.patch({ fields: [...this.fields(), { targetFieldName: '' }] });\r\n }\r\n\r\n protected removeField(index: number): void {\r\n this.patch({ fields: this.fields().filter((_, position) => position !== index) });\r\n }\r\n\r\n protected patchField(index: number, patch: Partial<WritebackFieldMapping>): void {\r\n this.patch({\r\n fields: this.fields().map((field, position) =>\r\n position === index ? { ...field, ...patch } : field,\r\n ),\r\n });\r\n }\r\n\r\n protected onRuntimeParameter(index: number, name: string): void {\r\n this.patchField(index, {\r\n runtimeParameterName: name === '' ? undefined : name,\r\n sourceFieldName: name === '' ? this.fields()[index]?.sourceFieldName : undefined,\r\n });\r\n }\r\n}\r\n","/**\r\n * Il contenitore degli ispettori: campi comuni, poi l'ispettore della categoria.\r\n *\r\n * La **rinomina** sta qui e non nei singoli ispettori, per due ragioni. E' identica per tutte le\r\n * categorie, e soprattutto e' un refactoring globale (**I5**): passa dall'unico punto che\r\n * riscrive i riferimenti a valle, e prima di applicarla **dice quante occorrenze tocchera'**.\r\n * Rinominare non e' modificare un campo, e non deve sembrarlo.\r\n *\r\n * Con **piu' di un nodo selezionato** non si mostra l'editor del primo: si dichiara quanti sono e\r\n * si offrono solo le operazioni valide su molti. Mostrare i campi di uno mentre N sono evidenziati\r\n * e' la stessa bugia della doppia evidenziazione, detta piu' piano — l'utente crede di stare\r\n * agendo su cio' che vede selezionato.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n computed,\r\n effect,\r\n inject,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeFindNode } from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport {\r\n AggregateNode,\r\n AppendNode,\r\n AtomicWritebackNode,\r\n CustomNode,\r\n DataSourceNode,\r\n FilterNode,\r\n ForecastNode,\r\n HierarchyPathNode,\r\n JoinNode,\r\n TransformNode,\r\n WritebackNode,\r\n} from '../../model/dpe-definition.model';\r\nimport { DpeAggregateInspectorComponent } from './dpe-aggregate-inspector.component';\r\nimport { DpeAppendInspectorComponent } from './dpe-append-inspector.component';\r\nimport { DpeAtomicWritebackInspectorComponent } from './dpe-atomic-writeback-inspector.component';\r\nimport { DpeCustomNodeInspectorComponent } from './dpe-custom-node-inspector.component';\r\nimport { DpeDataSourceInspectorComponent } from './dpe-data-source-inspector.component';\r\nimport { DpeFilterInspectorComponent } from './dpe-filter-inspector.component';\r\nimport { DpeForecastInspectorComponent } from './dpe-forecast-inspector.component';\r\nimport { DpeHierarchyPathInspectorComponent } from './dpe-hierarchy-path-inspector.component';\r\nimport { DpeJoinInspectorComponent } from './dpe-join-inspector.component';\r\nimport { DpeTransformInspectorComponent } from './dpe-transform-inspector.component';\r\nimport { DpeWritebackInspectorComponent } from './dpe-writeback-inspector.component';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\n\r\n@Component({\r\n selector: 'dpe-node-inspector',\r\n standalone: true,\r\n imports: [\r\n DpeAggregateInspectorComponent,\r\n DpeAppendInspectorComponent,\r\n DpeAtomicWritebackInspectorComponent,\r\n DpeCustomNodeInspectorComponent,\r\n DpeDataSourceInspectorComponent,\r\n DpeFilterInspectorComponent,\r\n DpeForecastInspectorComponent,\r\n DpeHierarchyPathInspectorComponent,\r\n DpeJoinInspectorComponent,\r\n DpeTransformInspectorComponent,\r\n DpeWritebackInspectorComponent,\r\n DpeNodeIconComponent,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (selectedNames().length > 1) {\r\n <!--\r\n Selezione multipla: si dice quanti sono e si offre solo cio' che ha senso su molti. Nessun\r\n campo del primo nodo, perche' non e' su quello che l’utente sta agendo.\r\n -->\r\n <div class=\"dpe-inspector__head\">\r\n <strong>{{ selectedNames().length }} nodi selezionati</strong>\r\n <span class=\"dpe-inspector__category\">selezione</span>\r\n </div>\r\n\r\n <ul class=\"dpe-multi__names\">\r\n @for (name of selectedNames(); track $index) {\r\n <li class=\"dpe-multi__name\">{{ name }}</li>\r\n }\r\n </ul>\r\n\r\n <p class=\"dpe-note\">\r\n I campi di un singolo nodo si modificano con un nodo solo selezionato: mostrarli qui\r\n farebbe credere di agire su tutti.\r\n </p>\r\n\r\n <div class=\"dpe-row\">\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"removeSelected()\">\r\n Elimina i {{ selectedNames().length }} nodi\r\n </button>\r\n <!--\r\n Il riordino e’ dichiaratamente **dell’intero grafo**: dagre su un sottografo sarebbe una\r\n funzione nuova, e chiamarla «riordina i selezionati» mentre riordina tutto sarebbe una\r\n bugia — la stessa classe di difetto che questo pannello esiste per evitare.\r\n -->\r\n <button type=\"button\" class=\"dpe-btn\" (click)=\"layoutRequested.emit()\">\r\n Riordina il grafo\r\n </button>\r\n </div>\r\n\r\n <p class=\"dpe-note dpe-note--warning\">\r\n L’eliminazione lascia i riferimenti a valle così come sono: diventano riferimenti rotti, e\r\n il backend li segnala. Si annulla con ↶.\r\n </p>\r\n } @else if (located(); as entry) {\r\n <div class=\"dpe-inspector__head\">\r\n <!--\r\n La stessa icona della palette e della card: il terzo posto in cui compare il tipo, e\r\n deve avere lo stesso aspetto degli altri due.\r\n -->\r\n <span class=\"dpe-inspector__icon\" [class]=\"'dpe-inspector__icon ' + familyClass()\">\r\n <dpe-node-icon [collection]=\"entry.collection\" />\r\n </span>\r\n <strong class=\"dpe-inspector__name\">{{ entry.node.label || entry.node.name }}</strong>\r\n <span class=\"dpe-inspector__category\">{{ categoryLabel() }}</span>\r\n </div>\r\n\r\n <div class=\"dpe-form\">\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-name\">Nome tecnico</label>\r\n <div class=\"dpe-row\">\r\n <input\r\n id=\"node-name\"\r\n type=\"text\"\r\n [value]=\"nameDraft()\"\r\n [attr.aria-invalid]=\"nameDraft().trim().length === 0\"\r\n (input)=\"nameDraft.set(valueOf($event))\"\r\n />\r\n <button\r\n type=\"button\"\r\n class=\"dpe-btn\"\r\n [disabled]=\"!canRename()\"\r\n (click)=\"rename(entry.node.name)\"\r\n >\r\n Rinomina\r\n </button>\r\n </div>\r\n @if (canRename()) {\r\n <p class=\"dpe-note dpe-note--warning\">\r\n La rinomina aggiorna <strong>{{ referenceCount() }}</strong> riferimenti a valle.\r\n I nomi si confrontano in modo esatto: un riferimento che sbaglia le maiuscole non\r\n verrebbe risolto dal backend.\r\n </p>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-label\">Etichetta</label>\r\n <input\r\n id=\"node-label\"\r\n type=\"text\"\r\n [value]=\"entry.node.label ?? ''\"\r\n (change)=\"setCommon('label', valueOf($event))\"\r\n />\r\n </div>\r\n\r\n <div class=\"dpe-field\">\r\n <label class=\"dpe-field__label\" for=\"node-description\">Descrizione</label>\r\n <input\r\n id=\"node-description\"\r\n type=\"text\"\r\n [value]=\"entry.node.description ?? ''\"\r\n (change)=\"setCommon('description', valueOf($event))\"\r\n />\r\n </div>\r\n </div>\r\n\r\n <section class=\"dpe-section\">\r\n @switch (entry.collection) {\r\n @case ('dataSources') {\r\n <dpe-data-source-inspector [nodeName]=\"entry.node.name\" [node]=\"asDataSource(entry.node)\" />\r\n }\r\n @case ('filters') {\r\n <dpe-filter-inspector [nodeName]=\"entry.node.name\" [node]=\"asFilter(entry.node)\" />\r\n }\r\n @case ('joins') {\r\n <dpe-join-inspector [nodeName]=\"entry.node.name\" [node]=\"asJoin(entry.node)\" />\r\n }\r\n @case ('aggregates') {\r\n <dpe-aggregate-inspector [nodeName]=\"entry.node.name\" [node]=\"asAggregate(entry.node)\" />\r\n }\r\n @case ('transforms') {\r\n <dpe-transform-inspector [nodeName]=\"entry.node.name\" [node]=\"asTransform(entry.node)\" />\r\n }\r\n @case ('appends') {\r\n <dpe-append-inspector [nodeName]=\"entry.node.name\" [node]=\"asAppend(entry.node)\" />\r\n }\r\n @case ('hierarchyPaths') {\r\n <dpe-hierarchy-path-inspector [nodeName]=\"entry.node.name\" [node]=\"asHierarchy(entry.node)\" />\r\n }\r\n @case ('forecasts') {\r\n <dpe-forecast-inspector [nodeName]=\"entry.node.name\" [node]=\"asForecast(entry.node)\" />\r\n }\r\n @case ('customNodes') {\r\n <dpe-custom-node-inspector [nodeName]=\"entry.node.name\" [node]=\"asCustom(entry.node)\" />\r\n }\r\n @case ('writebacks') {\r\n <dpe-writeback-inspector [nodeName]=\"entry.node.name\" [node]=\"asWriteback(entry.node)\" />\r\n }\r\n @case ('atomicWritebacks') {\r\n <dpe-atomic-writeback-inspector [nodeName]=\"entry.node.name\" [node]=\"asAtomic(entry.node)\" />\r\n }\r\n }\r\n </section>\r\n\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Schema in uscita</h4>\r\n @if (columns().length === 0) {\r\n <p class=\"dpe-empty\">\r\n Nessuna colonna: il backend non ha (ancora) propagato uno schema per questo nodo.\r\n </p>\r\n } @else {\r\n <div class=\"dpe-columns\">\r\n @for (column of columns(); track $index) {\r\n <span\r\n class=\"dpe-column\"\r\n [class.dpe-column--nullable]=\"column.isNullable\"\r\n [title]=\"column.type.kind + (column.isNullable ? ' · nullabile' : ' · non nulla')\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n <p class=\"dpe-field__hint\">\r\n Tratteggiate le colonne nullabili. Lo schema arriva da <code>validate</code>: non lo\r\n calcoliamo qui.\r\n </p>\r\n }\r\n </section>\r\n\r\n @if (diagnostics().length > 0) {\r\n <section class=\"dpe-section\">\r\n <h4 class=\"dpe-section__title\">Rilievi su questo nodo</h4>\r\n @for (diagnostic of diagnostics(); track $index) {\r\n <p\r\n class=\"dpe-field__issue\"\r\n [class.dpe-field__issue--warning]=\"diagnostic.severity === 'Warning'\"\r\n [class.dpe-field__issue--info]=\"diagnostic.severity === 'Info'\"\r\n >\r\n <code>{{ diagnostic.code }}</code> — {{ diagnostic.message }}\r\n </p>\r\n }\r\n </section>\r\n }\r\n } @else {\r\n <p class=\"dpe-empty\">Nessun nodo selezionato.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeNodeInspectorComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n /**\r\n * Il riordino richiede le misure delle card, che le conosce il canvas: l'ispettore **chiede**,\r\n * non calcola. Componente stupido, orchestrazione fuori.\r\n */\r\n readonly layoutRequested = output<void>();\r\n\r\n readonly selectedNames = computed(() => this.store.selectedNodeNames());\r\n\r\n readonly located = computed(() => {\r\n const name = this.store.selectedNodeName();\r\n return name === undefined ? undefined : dpeFindNode(this.store.definition(), name);\r\n });\r\n\r\n readonly nameDraft = signal('');\r\n\r\n readonly categoryLabel = computed(() => {\r\n const entry = this.located();\r\n return entry ? dpeNodeCategory(entry.collection).label : '';\r\n });\r\n\r\n /** La classe di famiglia dell'icona: la stessa funzione che usano palette e canvas. */\r\n readonly familyClass = computed(() => {\r\n const entry = this.located();\r\n return entry ? dpeNodeIconFamilyClass(entry.collection) : '';\r\n });\r\n\r\n readonly columns = computed(() => {\r\n const entry = this.located();\r\n return entry ? (this.store.schemaByNode().get(entry.node.name)?.columns ?? []) : [];\r\n });\r\n\r\n readonly diagnostics = computed(() => {\r\n const entry = this.located();\r\n return entry ? (this.store.diagnosticsByNode().get(entry.node.name)?.diagnostics ?? []) : [];\r\n });\r\n\r\n readonly referenceCount = computed(() => {\r\n const entry = this.located();\r\n return entry ? this.store.countReferences(entry.node.name) : 0;\r\n });\r\n\r\n readonly canRename = computed(() => {\r\n const entry = this.located();\r\n const draft = this.nameDraft().trim();\r\n return !!entry && draft.length > 0 && draft !== entry.node.name;\r\n });\r\n\r\n constructor() {\r\n // La bozza del nome segue la selezione: senza, cambiando nodo si resterebbe con il nome\r\n // del precedente in una casella che rinomina.\r\n effect(() => {\r\n const entry = this.located();\r\n this.nameDraft.set(entry?.node.name ?? '');\r\n });\r\n }\r\n\r\n /**\r\n * Elimina i nodi selezionati. Si itera su una **copia** dei nomi: `removeNode` pota la selezione\r\n * a ogni giro, e scorrere il signal mentre lo si svuota salterebbe la meta' dei nodi.\r\n */\r\n protected removeSelected(): void {\r\n for (const name of [...this.selectedNames()]) {\r\n this.store.removeNode(name);\r\n }\r\n }\r\n\r\n protected rename(currentName: string): void {\r\n this.store.renameNode(currentName, this.nameDraft().trim());\r\n }\r\n\r\n protected setCommon(field: 'label' | 'description', value: string): void {\r\n const entry = this.located();\r\n if (!entry) {\r\n return;\r\n }\r\n this.store.updateNode(entry.collection, entry.node.name, {\r\n [field]: value === '' ? undefined : value,\r\n } as never);\r\n }\r\n\r\n protected valueOf(event: Event): string {\r\n return (event.target as HTMLInputElement).value;\r\n }\r\n\r\n // I cast sono confinati qui: `@switch` restringe la collezione ma non il tipo del nodo, che\r\n // nel modello e' un'unione. Un cast per ramo e' il prezzo, e sbagliarne uno e' un errore di\r\n // compilazione nel template dell'ispettore, non un difetto silenzioso.\r\n protected asDataSource(node: unknown): DataSourceNode {\r\n return node as DataSourceNode;\r\n }\r\n\r\n protected asFilter(node: unknown): FilterNode {\r\n return node as FilterNode;\r\n }\r\n\r\n protected asJoin(node: unknown): JoinNode {\r\n return node as JoinNode;\r\n }\r\n\r\n protected asAggregate(node: unknown): AggregateNode {\r\n return node as AggregateNode;\r\n }\r\n\r\n protected asTransform(node: unknown): TransformNode {\r\n return node as TransformNode;\r\n }\r\n\r\n protected asAppend(node: unknown): AppendNode {\r\n return node as AppendNode;\r\n }\r\n\r\n protected asHierarchy(node: unknown): HierarchyPathNode {\r\n return node as HierarchyPathNode;\r\n }\r\n\r\n protected asForecast(node: unknown): ForecastNode {\r\n return node as ForecastNode;\r\n }\r\n\r\n protected asCustom(node: unknown): CustomNode {\r\n return node as CustomNode;\r\n }\r\n\r\n protected asWriteback(node: unknown): WritebackNode {\r\n return node as WritebackNode;\r\n }\r\n\r\n protected asAtomic(node: unknown): AtomicWritebackNode {\r\n return node as AtomicWritebackNode;\r\n }\r\n}\r\n","/**\r\n * La palette dei nodi.\r\n *\r\n * Il trascinamento verso il canvas usa `fExternalItem` di @foblex/flow: il rilascio emette\r\n * `fCreateNode` con il `fData` e la posizione **già nel sistema di coordinate del canvas**.\r\n * Convertirla a mano — che e' cio' che servirebbe con un drag generico — vorrebbe dire rifare la\r\n * trasformazione di zoom e panoramica della libreria, cioe' riscrivere la parte piu' facile da\r\n * sbagliare senza guadagnarci niente. Il **clic** resta la via da tastiera: la palette e'\r\n * navigabile con Tab e Invio, e chi non usa il mouse crea comunque un nodo.\r\n *\r\n * Il catalogo e' **descrittivo**: etichette e numero di sorgenti servono a rendere, non a\r\n * validare. Che un'unione con una sola sorgente sia sbagliata lo dice il backend.\r\n *\r\n * La voce sta su **una riga** — pastiglia con l'icona, etichetta — e la descrizione resta nel\r\n * `title`. La versione precedente ne faceva un paragrafo di tre righe: undici categorie non\r\n * entravano nel riquadro e sette si vedevano senza scorrere, cioe' l'elenco non era un elenco.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, output, signal } from '@angular/core';\r\nimport { FFlowModule } from '@foblex/flow';\r\n\r\nimport { DPE_NODE_CATEGORIES, DpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { dpeNodeIconFamilyClass } from '../../core/dpe-node-icons';\r\nimport { DpeNodeCollectionName } from '../../model/dpe-definition.model';\r\nimport { DpeNodeIconComponent } from '../shared/dpe-node-icon.component';\r\n\r\n/** Un gruppo dell'elenco: intestazione e voci. Presentazione, non semantica. */\r\nexport interface DpeNodePaletteGroup {\r\n key: 'sources' | 'transforms' | 'sinks';\r\n label: string;\r\n categories: readonly DpeNodeCategory[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-node-palette',\r\n standalone: true,\r\n imports: [FFlowModule, DpeNodeIconComponent],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <h3>Nodi</h3>\r\n <input\r\n type=\"search\"\r\n placeholder=\"Cerca un nodo\"\r\n aria-label=\"Cerca un nodo\"\r\n (input)=\"filter.set(text($event))\"\r\n />\r\n\r\n @for (group of groups(); track group.key) {\r\n <p class=\"dpe-palette__group\">{{ group.label }}</p>\r\n @for (category of group.categories; track category.collection) {\r\n <!--\r\n fExternalItem rende la voce trascinabile sul canvas; fData porta il nome della\r\n collezione, che e’ l’unica cosa che serve per creare il nodo.\r\n -->\r\n <button\r\n type=\"button\"\r\n class=\"dpe-palette__item\"\r\n fExternalItem\r\n [fExternalItemId]=\"category.collection\"\r\n [fData]=\"category.collection\"\r\n [title]=\"titleOf(category)\"\r\n (click)=\"nodeRequested.emit(category.collection)\"\r\n >\r\n <!--\r\n Un solo figlio dentro l’elemento che la libreria tocca: e’ qui che sta il layout della\r\n riga, e non dipende dal display che @foblex/flow riscrive dopo un trascinamento.\r\n -->\r\n <span class=\"dpe-palette__body\">\r\n <span class=\"dpe-palette__icon\" [class]=\"'dpe-palette__icon ' + familyClass(category)\">\r\n <dpe-node-icon [collection]=\"category.collection\" />\r\n </span>\r\n <span class=\"dpe-palette__label\">{{ category.label }}</span>\r\n @if (category.isNotCompilableInV1) {\r\n <span class=\"dpe-palette__flag\">v1</span>\r\n }\r\n </span>\r\n </button>\r\n }\r\n }\r\n\r\n @if (visible().length === 0) {\r\n <p class=\"dpe-palette__empty\">Nessun nodo corrisponde alla ricerca.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeNodePaletteComponent {\r\n /** Clic sulla voce: il nodo si crea al centro dell'area, non dove stava il puntatore. */\r\n readonly nodeRequested = output<DpeNodeCollectionName>();\r\n\r\n protected readonly filter = signal('');\r\n\r\n readonly visible = computed<readonly DpeNodeCategory[]>(() => {\r\n const needle = this.filter().trim().toLowerCase();\r\n if (needle.length === 0) {\r\n return DPE_NODE_CATEGORIES;\r\n }\r\n return DPE_NODE_CATEGORIES.filter(\r\n (category) =>\r\n category.label.toLowerCase().includes(needle) ||\r\n category.description.toLowerCase().includes(needle),\r\n );\r\n });\r\n\r\n /**\r\n * Tre gruppi, nell'ordine in cui si costruisce una pipeline: da dove entrano i dati, cosa ci\r\n * si fa, dove finiscono. I gruppi vuoti non compaiono, altrimenti una ricerca lascerebbe sullo\r\n * schermo intestazioni senza voci.\r\n */\r\n readonly groups = computed<readonly DpeNodePaletteGroup[]>(() => {\r\n const visible = this.visible();\r\n const groups: DpeNodePaletteGroup[] = [\r\n {\r\n key: 'sources',\r\n label: 'Sorgenti',\r\n categories: visible.filter((category) => category.isSource),\r\n },\r\n {\r\n key: 'transforms',\r\n label: 'Trasformazioni',\r\n categories: visible.filter((category) => !category.isSource && !category.isSink),\r\n },\r\n {\r\n key: 'sinks',\r\n label: 'Scritture',\r\n categories: visible.filter((category) => category.isSink),\r\n },\r\n ];\r\n return groups.filter((group) => group.categories.length > 0);\r\n });\r\n\r\n protected familyClass(category: DpeNodeCategory): string {\r\n return dpeNodeIconFamilyClass(category.collection);\r\n }\r\n\r\n /** Il testo che la descrizione non mostra piu' nel corpo della voce. */\r\n protected titleOf(category: DpeNodeCategory): string {\r\n return category.isNotCompilableInV1\r\n ? `${category.description}\\nModellato ma non compilabile nella versione 1.`\r\n : category.description;\r\n }\r\n\r\n protected text(event: Event): string {\r\n return (event.target as HTMLInputElement).value;\r\n }\r\n}\r\n","/**\r\n * Anteprima dell'SQL generato, in **sola lettura**.\r\n *\r\n * E' lo strumento diagnostico principale per chi costruisce una pipeline: e' l'unico posto in\r\n * cui si vede cosa diventera' il grafo. Tre cose che l'interfaccia dice esplicitamente, perche'\r\n * nessuna e' ovvia guardando il testo:\r\n *\r\n * - i writeback `Database` producono un'istruzione **per l'host**, che la libreria non esegue;\r\n * - i writeback `Json`/`Csv` portano l'SQL di **lettura** con cui l'artefatto viene materializzato;\r\n * - i parametri restano **parametri**: il testo mostra i marcatori del dialetto e i valori stanno\r\n * accanto. Non si interpolano nel testo nemmeno per mostrarlo — un'anteprima che mostra SQL\r\n * concatenato insegna a scriverlo.\r\n *\r\n * Se l'host non implementa `compilePreview` il comando e' disabilitato e questo pannello lo dice:\r\n * degrada l'anteprima, non l'editor.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { DpeValidationService } from '../../core/dpe-validation.service';\r\nimport { DpeCompiledWriteback } from '../../model/dpe-api.model';\r\n\r\ninterface DpeSqlSection {\r\n title: string;\r\n hint: string;\r\n writebacks: readonly DpeCompiledWriteback[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-sql-preview',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n <div class=\"dpe-sql__bar\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-sql__btn\"\r\n [disabled]=\"!validation.isPreviewAvailable() || validation.isCompiling()\"\r\n (click)=\"validation.requestPreview()\"\r\n >\r\n @if (validation.isCompiling()) {\r\n Compilazione in corso…\r\n } @else {\r\n Genera anteprima\r\n }\r\n </button>\r\n @if (!validation.isPreviewAvailable()) {\r\n <span class=\"dpe-sql__note\">\r\n Anteprima non disponibile su questo ambiente: l’host non espone la compilazione.\r\n </span>\r\n } @else {\r\n <span class=\"dpe-sql__note\">Sola lettura: la libreria non esegue nulla.</span>\r\n }\r\n </div>\r\n\r\n @if (result(); as compiled) {\r\n @if (compiled.hasErrors) {\r\n <p class=\"dpe-sql__empty\">\r\n La compilazione si e’ fermata: ci sono errori di validazione, e nessun artefatto parziale\r\n viene prodotto. Guarda il pannello delle diagnostiche.\r\n </p>\r\n }\r\n\r\n @for (section of sections(); track $index) {\r\n @if (section.writebacks.length > 0) {\r\n <div class=\"dpe-sql__section\">\r\n <h4 class=\"dpe-sql__title\">{{ section.title }}</h4>\r\n <p class=\"dpe-sql__note\">{{ section.hint }}</p>\r\n @for (writeback of section.writebacks; track $index) {\r\n <div>\r\n <p class=\"dpe-sql__note\">\r\n <strong>{{ writeback.writebackName }}</strong> · sequenza {{ writeback.sequence }}\r\n </p>\r\n <pre>{{ writeback.statement.text }}</pre>\r\n @if (writeback.statement.parameters?.length) {\r\n <table>\r\n <thead>\r\n <tr>\r\n <th>Parametro</th>\r\n <th>Tipo</th>\r\n <th>Valore</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n @for (parameter of writeback.statement.parameters ?? []; track $index) {\r\n <tr>\r\n <td>{{ parameter.name }}</td>\r\n <td>{{ parameter.type }}</td>\r\n <td>{{ display(parameter.value) }}</td>\r\n </tr>\r\n }\r\n </tbody>\r\n </table>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n }\r\n\r\n @if (isEmpty()) {\r\n <p class=\"dpe-sql__empty\">Nessuna istruzione prodotta.</p>\r\n }\r\n } @else {\r\n <p class=\"dpe-sql__empty\">Nessuna anteprima richiesta.</p>\r\n }\r\n `,\r\n})\r\nexport class DpeSqlPreviewComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n protected readonly validation = inject(DpeValidationService);\r\n\r\n readonly result = computed(() => this.store.compileResult());\r\n\r\n readonly sections = computed<DpeSqlSection[]>(() => {\r\n const compiled = this.result();\r\n return [\r\n {\r\n title: 'Scritture su database',\r\n hint: 'Istruzione consegnata all’host, che la esegue: la libreria non scrive.',\r\n writebacks: compiled?.databaseWritebacks ?? [],\r\n },\r\n {\r\n title: 'Artefatti (JSON / CSV)',\r\n hint: 'SQL di lettura con cui il file viene materializzato, non ancora eseguito.',\r\n writebacks: compiled?.fileWritebacks ?? [],\r\n },\r\n ];\r\n });\r\n\r\n readonly isEmpty = computed(() =>\r\n this.sections().every((section) => section.writebacks.length === 0),\r\n );\r\n\r\n /** Il valore di un parametro e' opaco: si mostra, non si converte. */\r\n protected display(value: unknown): string {\r\n if (value === null || value === undefined) {\r\n return 'NULL';\r\n }\r\n return typeof value === 'object' ? JSON.stringify(value) : String(value);\r\n }\r\n}\r\n","/**\r\n * La vista dello schema: colonne in ingresso e in uscita, nodo per nodo.\r\n *\r\n * Tutto quello che si vede qui arriva da `Schemas` di `validate` (**I4**: propagazione pura e\r\n * deterministica, del backend). Il frontend non deduce niente — se il backend non ha ancora\r\n * risposto, la vista e' vuota e lo dice.\r\n *\r\n * Le colonne **in ingresso** sono lo schema dei nodi a monte, e servono accanto a quelle in\r\n * uscita per una cosa sola: vedere dove un **alias** cambia il nome di una colonna (**I5**) e\r\n * cosa arriva a valle con quel nome nuovo. Le colonne rinominate sono marcate: e' il punto in cui\r\n * un riferimento a valle sbaglia nome piu' spesso.\r\n */\r\n\r\nimport { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\r\n\r\nimport { DpeDocumentStore } from '../../core/dpe-document.store';\r\nimport { dpeAllNodes, dpeNodeSourceReferences } from '../../core/dpe-graph';\r\nimport { dpeNodeCategory } from '../../core/dpe-node-catalog';\r\nimport { DpeColumnInfo } from '../../model/dpe-api.model';\r\n\r\ninterface DpeSchemaRow {\r\n nodeName: string;\r\n categoryLabel: string;\r\n isSelected: boolean;\r\n isCompilable: boolean;\r\n hasSchema: boolean;\r\n inputColumns: readonly DpeColumnInfo[];\r\n outputColumns: readonly DpeColumnInfo[];\r\n /** Colonne in uscita che non esistono in ingresso: alias nuovi o colonne prodotte dal nodo. */\r\n introduced: ReadonlySet<string>;\r\n /** Colonne in ingresso che non arrivano in uscita: eliminate o rinominate. */\r\n dropped: readonly string[];\r\n}\r\n\r\n@Component({\r\n selector: 'dpe-schema-panel',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n template: `\r\n @if (!hasResult()) {\r\n <p class=\"dpe-schema__empty\">In attesa della propagazione dello schema dal backend…</p>\r\n }\r\n\r\n @for (row of rows(); track $index) {\r\n <section class=\"dpe-schema__node\" [class.dpe-schema__node--selected]=\"row.isSelected\">\r\n <div class=\"dpe-schema__head\">\r\n <span class=\"dpe-schema__name\">{{ row.nodeName }}</span>\r\n <span class=\"dpe-schema__category\">{{ row.categoryLabel }}</span>\r\n @if (!row.isCompilable) {\r\n <span class=\"dpe-schema__tag\" title=\"Valido, ma non traducibile in SQL\">non compilabile</span>\r\n }\r\n </div>\r\n\r\n @if (row.inputColumns.length > 0) {\r\n <div class=\"dpe-schema__line\">\r\n <span class=\"dpe-schema__label\">In ingresso</span>\r\n @for (column of row.inputColumns; track $index) {\r\n <span\r\n class=\"dpe-col\"\r\n [class.dpe-col--nullable]=\"column.isNullable\"\r\n [class.dpe-col--dropped]=\"row.dropped.includes(column.name)\"\r\n [title]=\"column.type.kind\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-schema__line\">\r\n <span class=\"dpe-schema__label\">In uscita</span>\r\n @if (!row.hasSchema) {\r\n <span class=\"dpe-schema__empty\">nessuno schema propagato</span>\r\n }\r\n @for (column of row.outputColumns; track $index) {\r\n <span\r\n class=\"dpe-col\"\r\n [class.dpe-col--nullable]=\"column.isNullable\"\r\n [class.dpe-col--new]=\"row.introduced.has(column.name.toLowerCase())\"\r\n [title]=\"column.type.kind + (column.isNullable ? ' · nullabile' : ' · non nulla')\"\r\n >\r\n {{ column.name }}\r\n </span>\r\n }\r\n </div>\r\n </section>\r\n }\r\n\r\n @if (rows().length > 0) {\r\n <p class=\"dpe-schema__empty\">\r\n In evidenza le colonne che il nodo <strong>introduce</strong> (alias nuovi e colonne\r\n calcolate) e barrate quelle che non arrivano a valle. Tratteggiate le nullabili.\r\n </p>\r\n }\r\n `,\r\n})\r\nexport class DpeSchemaPanelComponent {\r\n private readonly store = inject(DpeDocumentStore);\r\n\r\n readonly hasResult = computed(() => this.store.validateResult() !== undefined);\r\n\r\n readonly rows = computed<DpeSchemaRow[]>(() => {\r\n const definition = this.store.definition();\r\n const schemas = this.store.schemaByNode();\r\n const selected = this.store.selectedNodeName();\r\n const executionOrder = this.store.executionOrder();\r\n\r\n const located = dpeAllNodes(definition);\r\n // L'ordine e' quello **topologico** del backend quando c'e': leggere lo schema nell'ordine\r\n // in cui i dati scorrono e' l'unico modo di seguire un alias fino al sink.\r\n const ordered =\r\n executionOrder.length > 0\r\n ? [...located].sort(\r\n (left, right) =>\r\n indexOrLast(executionOrder, left.node.name) -\r\n indexOrLast(executionOrder, right.node.name),\r\n )\r\n : located;\r\n\r\n return ordered.map((entry) => {\r\n const schema = schemas.get(entry.node.name);\r\n const outputColumns = schema?.columns ?? [];\r\n const inputColumns: DpeColumnInfo[] = [];\r\n const seen = new Set<string>();\r\n for (const reference of dpeNodeSourceReferences(entry)) {\r\n if (!reference.isEdge || !reference.sourceName) {\r\n continue;\r\n }\r\n for (const column of schemas.get(reference.sourceName)?.columns ?? []) {\r\n const key = column.name.toLowerCase();\r\n if (!seen.has(key)) {\r\n seen.add(key);\r\n inputColumns.push(column);\r\n }\r\n }\r\n }\r\n const outputNames = new Set(outputColumns.map((column) => column.name.toLowerCase()));\r\n return {\r\n nodeName: entry.node.name,\r\n categoryLabel: dpeNodeCategory(entry.collection).label,\r\n isSelected: entry.node.name === selected,\r\n isCompilable: schema?.isCompilable !== false,\r\n hasSchema: schema !== undefined,\r\n inputColumns,\r\n outputColumns,\r\n introduced: new Set(\r\n outputColumns\r\n .map((column) => column.name.toLowerCase())\r\n .filter((name) => !seen.has(name)),\r\n ),\r\n dropped: inputColumns\r\n .filter((column) => !outputNames.has(column.name.toLowerCase()))\r\n .map((column) => column.name),\r\n };\r\n });\r\n });\r\n}\r\n\r\n/** I nodi fuori dall'ordine di esecuzione (irraggiungibili) finiscono in coda, non in testa. */\r\nfunction indexOrLast(order: readonly string[], name: string): number {\r\n const index = order.indexOf(name);\r\n return index < 0 ? Number.MAX_SAFE_INTEGER : index;\r\n}\r\n","/**\r\n * Il componente radice dell'editor: `<dpe-builder>`.\r\n *\r\n * Tiene i provider — store del documento, layout, validazione, metadati — **a livello di\r\n * componente** e non della root dell'applicazione: due editor sulla stessa pagina sono due\r\n * documenti indipendenti, con la loro cronologia e la loro selezione.\r\n *\r\n * Non conosce HTTP: tutto il traffico passa da `DpeBuilderApi`, che l'ospite fornisce.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n Signal,\r\n computed,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n signal,\r\n untracked,\r\n viewChild,\r\n} from '@angular/core';\r\n\r\n\r\nimport { DpeDocumentStore } from '../core/dpe-document.store';\r\nimport { DpeLayoutService } from '../core/dpe-layout.service';\r\nimport { DpeMetadataStore } from '../core/dpe-metadata.store';\r\nimport { DpeValidationService } from '../core/dpe-validation.service';\r\nimport { dpeHasCompleteLayout } from '../core/dpe-node-layout';\r\nimport { dpeAllNodes } from '../core/dpe-graph';\r\nimport { DPE_DIALECT_LABELS } from '../core/dpe-node-catalog';\r\nimport { DpeDefinition, DpeNodeCollectionName, SqlDialectKind } from '../model/dpe-definition.model';\r\nimport { DpeCanvasComponent } from './canvas/dpe-canvas.component';\r\nimport { DpeDiagnosticsPanelComponent } from './diagnostics/dpe-diagnostics-panel.component';\r\nimport { DpeNodeInspectorComponent } from './inspector/dpe-node-inspector.component';\r\nimport { DpeNodePaletteComponent } from './palette/dpe-node-palette.component';\r\nimport { DpeSqlPreviewComponent } from './preview/dpe-sql-preview.component';\r\nimport { DpeSchemaPanelComponent } from './schema/dpe-schema-panel.component';\r\n\r\n/** Le tre viste in basso: una alla volta, perche' guardano la stessa cosa da tre angoli. */\r\ntype DpeBottomTab = 'diagnostics' | 'schema' | 'sql';\r\n\r\n@Component({\r\n selector: 'dpe-builder',\r\n standalone: true,\r\n imports: [\r\n DpeCanvasComponent,\r\n DpeDiagnosticsPanelComponent,\r\n DpeNodeInspectorComponent,\r\n DpeNodePaletteComponent,\r\n DpeSchemaPanelComponent,\r\n DpeSqlPreviewComponent,\r\n ],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [DpeDocumentStore, DpeLayoutService, DpeValidationService, DpeMetadataStore],\r\n /**\r\n * `Ctrl+S` sul **componente**, non su `document`: due editor nella stessa pagina non devono\r\n * salvarsi a vicenda, e un ascoltatore globale installato dalla libreria intercetterebbe la\r\n * scorciatoia anche quando l'utente sta lavorando altrove nell'applicazione ospite.\r\n */\r\n host: { '(keydown)': 'onKeyDown($event)' },\r\n templateUrl: './dpe-builder.component.html',\r\n})\r\nexport class DpeBuilderComponent {\r\n protected readonly store = inject(DpeDocumentStore);\r\n protected readonly validation = inject(DpeValidationService);\r\n private readonly layout = inject(DpeLayoutService);\r\n\r\n /** La definizione da editare. Cambiarne l'identita' ricarica il documento. */\r\n readonly definition = input.required<DpeDefinition>();\r\n\r\n readonly isEditable = input(true);\r\n\r\n /**\r\n * Emessa a ogni mutazione. L'ospite **non deve** rimandarla dentro `definition`: sarebbe un\r\n * ciclo, e ricaricare azzera la cronologia. Serve per salvare, non per pilotare l'editor.\r\n */\r\n readonly definitionChange = output<DpeDefinition>();\r\n\r\n protected readonly dialectLabels = DPE_DIALECT_LABELS;\r\n\r\n protected readonly bottomTab = signal<DpeBottomTab>('diagnostics');\r\n\r\n private readonly canvas = viewChild(DpeCanvasComponent);\r\n\r\n /**\r\n * Il dialetto **della definizione**: e' quello con cui il backend compilera' (ADR 0009), quindi\r\n * e' quello che il badge mostra. In sola lettura: nessun comando dell'interfaccia lo cambia\r\n * (ADR 0017), perche' il database di destinazione e' un fatto dell'ambiente e non una\r\n * preferenza dell'autore.\r\n */\r\n protected readonly dialect = computed(() => this.store.definition().dialect);\r\n\r\n /**\r\n * Disallineamento fra cio' che l'ambiente dichiara e cio' che la definizione porta. Si\r\n * **segnala** e non si corregge: correggere vorrebbe dire migrare le espressioni SQL native\r\n * (ADR 0006), che e' dell'host. Assente `getEnvironment`, non c'e' niente da confrontare.\r\n */\r\n protected readonly dialectMismatch = computed<SqlDialectKind | undefined>(() => {\r\n const declared = this.validation.environmentDialect();\r\n return declared !== undefined && declared !== this.dialect() ? declared : undefined;\r\n });\r\n\r\n protected readonly canSave = computed(\r\n () => this.validation.isSaveAvailable() && !this.validation.isSaving() && this.store.isDirty(),\r\n );\r\n\r\n protected readonly nodeCount = computed(() => dpeAllNodes(this.store.definition()).length);\r\n\r\n constructor() {\r\n // Caricamento: si reagisce all'**identita'** dell'input, non al suo contenuto. Lo store\r\n // diventa la fonte di verita' da qui in poi.\r\n effect(() => {\r\n const incoming = this.definition();\r\n // `untracked` non e' prudenza: senza, questo effect **si richiama da solo**. Legge il\r\n // documento dello store (attraverso `load`, e a maggior ragione se un domani si leggesse\r\n // qualcosa dello store qui) e lo riscrive, quindi ogni scrittura successiva — anche quella\r\n // del layout automatico — lo farebbe ripartire e riportare il documento all'input,\r\n // cancellando il layout appena calcolato e ricominciando. Il sintomo non e' un errore: e'\r\n // una pagina che non si ferma piu' e uno schermo che sembra solo lento.\r\n untracked(() => this.store.load(incoming));\r\n });\r\n\r\n // Un documento senza coordinate (ADR 0013: sono opzionali) si dispone da solo, una volta.\r\n // Farlo a ogni cambio combatterebbe con chi sposta i nodi a mano.\r\n effect(() => {\r\n const nodes = dpeAllNodes(this.store.definition()).map((located) => located.node);\r\n if (nodes.length === 0 || dpeHasCompleteLayout(nodes)) {\r\n return;\r\n }\r\n // Il calcolo legge il grafo e le misure delle card: fuori da `untracked` diventerebbero\r\n // dipendenze di questo effect, che scrive proprio cio' che legge.\r\n untracked(() => this.runLayout(true));\r\n });\r\n\r\n // La definizione esce verso l'ospite a ogni mutazione: e' lui che sa se e quando salvare.\r\n effect(() => {\r\n this.definitionChange.emit(this.store.definition());\r\n });\r\n }\r\n\r\n /** Comando «Riordina»: e' un'azione dell'utente, quindi annullabile e \"modifica\". */\r\n protected runAutoLayout(): void {\r\n this.runLayout(false);\r\n }\r\n\r\n /**\r\n * `isInitial` distingue due cose che dagre calcola allo stesso modo e che l'editor deve trattare\r\n * in modo opposto: disporre un documento che **non porta** coordinate non e' una modifica\r\n * dell'utente; riordinare su richiesta lo e'.\r\n */\r\n private runLayout(isInitial: boolean): void {\r\n const canvas = this.canvas();\r\n if (!canvas) {\r\n return;\r\n }\r\n const positions = this.layout.layout(\r\n canvas.layoutInput(),\r\n this.store.graph().edges.map((edge) => ({\r\n from: edge.fromNodeName,\r\n to: edge.toNodeName,\r\n id: edge.id,\r\n })),\r\n );\r\n if (isInitial) {\r\n this.store.applyInitialPositions(positions);\r\n return;\r\n }\r\n this.store.applyPositions(positions);\r\n }\r\n\r\n protected onNodeDropped(event: { collection: DpeNodeCollectionName; x: number; y: number }): void {\r\n const name = this.store.createNodeAt(event.collection, { x: event.x, y: event.y });\r\n // Selezione immediata: chi ha appena creato un nodo lo deve configurare, e cercarlo con il\r\n // mouse subito dopo averlo rilasciato e' un passaggio inutile.\r\n this.store.select(name);\r\n }\r\n\r\n /** Clic sulla palette (via tastiera compresa): il nodo nasce in un punto libero e prevedibile. */\r\n protected onNodeRequested(collection: DpeNodeCollectionName): void {\r\n const existing = this.store.positions();\r\n let y = 60;\r\n for (const position of existing.values()) {\r\n y = Math.max(y, position.y + 140);\r\n }\r\n const name = this.store.createNodeAt(collection, { x: 80, y });\r\n this.store.select(name);\r\n }\r\n\r\n /**\r\n * `Ctrl+S` (e `Cmd+S`): stesse condizioni di abilitazione del bottone. `preventDefault` sempre\r\n * che la scorciatoia sia nostra, anche quando il salvataggio non e' possibile: lasciare passare\r\n * il «salva pagina» del browser proprio dentro un editor sarebbe la risposta sbagliata a un\r\n * gesto giusto.\r\n */\r\n protected onKeyDown(event: KeyboardEvent): void {\r\n if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== 's') {\r\n return;\r\n }\r\n event.preventDefault();\r\n if (this.canSave()) {\r\n this.validation.save();\r\n }\r\n }\r\n\r\n /**\r\n * Navigazione da una diagnostica: **selezione e vista**. Il `DiagnosticPath` promette di portare\r\n * sul nodo e sul campo; selezionare senza inquadrare mantiene meta' della promessa, e il nodo\r\n * resta fuori schermo mentre l'ispettore parla di lui.\r\n */\r\n protected onNavigate(event: { nodeName: string }): void {\r\n this.store.select(event.nodeName);\r\n // Si muove la **vista**, non il documento: le coordinate del nodo non si toccano.\r\n this.canvas()?.revealNode(event.nodeName);\r\n }\r\n\r\n /**\r\n * Stato **sporco** del documento, per l'ospite che deve decidere se lasciar navigare via\r\n * (ADR 0019). Delega a `DpeDocumentStore.isDirty`.\r\n *\r\n * Si legge tramite `viewChild` **quando serve**, non si rispecchia in uno stato dell'ospite: un\r\n * mirror di stato sporco che va fuori sincrono e' peggio del problema che risolve. La conferma\r\n * prima di abbandonare le modifiche e' dell'ospite, perche' e' l'ospite che naviga — la libreria\r\n * non sa se andare via significhi cambiare schermata, scheda o applicazione.\r\n */\r\n readonly isDirty: Signal<boolean> = this.store.isDirty;\r\n\r\n /**\r\n * Da chiamare dopo un salvataggio riuscito: da quel momento il documento risulta \"senza\r\n * modifiche\". Lo decide l'ospite, perche' solo lui sa se il salvataggio e' andato a buon fine.\r\n */\r\n markSaved(): void {\r\n this.store.markSaved();\r\n }\r\n}\r\n","<!--\r\n `.dpe-builder` porta le variabili del tema: e’ la classe radice su cui l’app ospite le\r\n sovrascrive, e `data-dpe-theme=\"dark\"` sul contenitore ridefinisce i soli token.\r\n-->\r\n<div class=\"dpe-builder dpe-shell\">\r\n <header class=\"dpe-shell__bar\">\r\n <div class=\"dpe-shell__title\">\r\n <strong>{{ store.definition().label || store.definition().name || 'Definizione DPE' }}</strong>\r\n <span class=\"dpe-shell__sub\">{{ nodeCount() }} nodi</span>\r\n <!--\r\n Stato **sporco** rispetto all’ultimo salvataggio, non un conteggio di operazioni: serve a\r\n decidere se salvare, e un contatore che sale quando si annulla risponde alla domanda\r\n sbagliata. Annullare fino allo stato di partenza torna qui a «nessuna modifica».\r\n -->\r\n <span\r\n class=\"dpe-shell__dirty\"\r\n [class.dpe-shell__dirty--on]=\"store.isDirty()\"\r\n [title]=\"\r\n store.isDirty()\r\n ? 'Il documento differisce dall’ultimo salvataggio'\r\n : 'Il documento coincide con l’ultimo salvataggio'\r\n \"\r\n >\r\n @if (store.isDirty()) {\r\n ● modificata\r\n } @else {\r\n ○ nessuna modifica\r\n }\r\n </span>\r\n </div>\r\n\r\n <!--\r\n Badge in **sola lettura** (ADR 0017): il dialetto e’ dichiarato dall’ambiente, non scelto\r\n qui. Mostra quello della definizione, che e’ quello con cui il backend compilera’ (ADR\r\n 0009). Il titolo dice le due cose che contano — chi lo decide, e che le espressioni sono\r\n SQL nativo di quel dialetto (ADR 0006).\r\n -->\r\n <span\r\n class=\"dpe-shell__dialect\"\r\n title=\"Il dialetto e’ dichiarato dall’ambiente e non si modifica dall’editor. Le espressioni sono SQL nativo di questo dialetto: la definizione gli appartiene.\"\r\n >\r\n Dialetto · <strong>{{ dialectLabels[dialect()] }}</strong>\r\n </span>\r\n\r\n <div class=\"dpe-shell__group\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn\"\r\n [disabled]=\"!store.canUndo()\"\r\n title=\"Annulla (la cronologia e’ una conseguenza dell’immutabilita’ dello stato)\"\r\n (click)=\"store.undo()\"\r\n >\r\n ↶ Annulla\r\n </button>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn\"\r\n [disabled]=\"!store.canRedo()\"\r\n title=\"Ripeti\"\r\n (click)=\"store.redo()\"\r\n >\r\n ↷ Ripeti\r\n </button>\r\n <button type=\"button\" class=\"dpe-shell__btn\" title=\"Riordina il grafo\" (click)=\"runAutoLayout()\">\r\n ⌗ Riordina\r\n </button>\r\n </div>\r\n\r\n <!--\r\n Salvataggio attraverso il contratto (`DpeBuilderApi.save`, opzionale). E’ il comando\r\n **primario**, separato dal gruppo annulla/ripeti/riordina: quelli disfano, questo scrive.\r\n\r\n **Sempre presente, mai nascosto.** Un bottone assente dice «questo editor non salva»; un\r\n bottone disabilitato con il motivo dice «qui non si salva, ed ecco perche’» — ed e’ la\r\n verita’ quando l’host non espone `save()`. La disponibilita’ si sa **prima del clic**\r\n (`core/dpe-capabilities.ts`), non dal primo fallimento.\r\n -->\r\n <div class=\"dpe-shell__group dpe-shell__group--primary\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-shell__btn dpe-shell__btn--primary\"\r\n [disabled]=\"!canSave()\"\r\n [title]=\"\r\n !validation.isSaveAvailable()\r\n ? 'Salvataggio non disponibile su questo ambiente: l’host non espone save()'\r\n : validation.isSaving()\r\n ? 'Salvataggio in corso'\r\n : store.isDirty()\r\n ? 'Salva la definizione (Ctrl+S)'\r\n : 'Nessuna modifica da salvare'\r\n \"\r\n (click)=\"validation.save()\"\r\n >\r\n @if (validation.isSaving()) {\r\n ⤓ Salvataggio…\r\n } @else {\r\n ⤓ Salva\r\n }\r\n </button>\r\n @if (validation.justSaved()) {\r\n <!-- Avviso transitorio: il fatto durevole e’ «nessuna modifica» nell’indicatore. -->\r\n <span class=\"dpe-shell__toast\" role=\"status\">✓ Salvata</span>\r\n }\r\n </div>\r\n\r\n <div class=\"dpe-shell__status\">\r\n @if (validation.isValidating()) {\r\n <span class=\"dpe-shell__pill dpe-shell__pill--busy\">Validazione in corso…</span>\r\n } @else if (validation.error(); as error) {\r\n <!--\r\n Un guasto di trasporto non cancella le diagnostiche precedenti: dire «va tutto bene»\r\n quando non lo sappiamo piu’ e’ peggio che mostrare un risultato vecchio dichiarandolo.\r\n -->\r\n <span class=\"dpe-shell__pill dpe-shell__pill--error\" [title]=\"error.message\">\r\n Backend non raggiungibile ({{ error.category }})\r\n </span>\r\n } @else if (store.validateResult()) {\r\n <span\r\n class=\"dpe-shell__pill\"\r\n [class.dpe-shell__pill--error]=\"store.validateResult()!.hasErrors\"\r\n [class.dpe-shell__pill--ok]=\"!store.validateResult()!.hasErrors\"\r\n >\r\n @if (store.validateResult()!.hasErrors) {\r\n Con errori\r\n } @else {\r\n Nessun errore\r\n }\r\n </span>\r\n }\r\n </div>\r\n </header>\r\n\r\n @if (dialectMismatch(); as declared) {\r\n <!--\r\n Disallineamento fra la dichiarazione dell’ambiente e la definizione (ADR 0017). Si nominano\r\n **entrambi** i dialetti e non si offre di correggere: correggere significherebbe migrare le\r\n espressioni SQL native, ed e’ dell’host. Non e’ una regola di dominio duplicata — non giudica\r\n la definizione, riporta il disaccordo fra due fatti che l’ospite ha fornito.\r\n -->\r\n <div class=\"dpe-shell__warn\" role=\"alert\">\r\n <strong>\r\n L’ambiente dichiara {{ dialectLabels[declared] }}, la definizione e’ scritta per\r\n {{ dialectLabels[dialect()] }}.\r\n </strong>\r\n <p>\r\n Il backend compilera’ con il dialetto <strong>della definizione</strong>. Allinearli e’ una\r\n migrazione delle espressioni SQL native e non si fa da qui.\r\n </p>\r\n </div>\r\n }\r\n\r\n @if (validation.saveError(); as error) {\r\n <!--\r\n Banner **persistente**: un salvataggio fallito in silenzio e’ peggio di nessun salvataggio,\r\n perche’ l’indicatore «modificata» sparirebbe per un’operazione che non e’ avvenuta. Qui non\r\n sparisce: `markSaved()` viene chiamato solo al successo.\r\n -->\r\n <div class=\"dpe-shell__warn dpe-shell__warn--error\" role=\"alert\">\r\n <strong>Salvataggio non riuscito ({{ error.category }})</strong>\r\n <p>{{ error.message }}</p>\r\n <div class=\"dpe-shell__group\">\r\n <button type=\"button\" class=\"dpe-shell__btn\" (click)=\"validation.dismissSaveError()\">\r\n Ho capito\r\n </button>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"dpe-shell__body\">\r\n <dpe-node-palette class=\"dpe-shell__palette\" (nodeRequested)=\"onNodeRequested($event)\" />\r\n\r\n <dpe-canvas\r\n class=\"dpe-shell__canvas\"\r\n [isEditable]=\"isEditable()\"\r\n (nodeDropped)=\"onNodeDropped($event)\"\r\n />\r\n\r\n <dpe-node-inspector class=\"dpe-shell__inspector\" (layoutRequested)=\"runAutoLayout()\" />\r\n </div>\r\n\r\n <div class=\"dpe-shell__bottom\">\r\n <div class=\"dpe-shell__tabs\" role=\"tablist\" aria-label=\"Pannelli\">\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'diagnostics'\"\r\n [attr.aria-selected]=\"bottomTab() === 'diagnostics'\"\r\n (click)=\"bottomTab.set('diagnostics')\"\r\n >\r\n Diagnostiche\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'schema'\"\r\n [attr.aria-selected]=\"bottomTab() === 'schema'\"\r\n (click)=\"bottomTab.set('schema')\"\r\n >\r\n Schema\r\n </button>\r\n <button\r\n type=\"button\"\r\n role=\"tab\"\r\n class=\"dpe-shell__tab\"\r\n [class.dpe-shell__tab--active]=\"bottomTab() === 'sql'\"\r\n [attr.aria-selected]=\"bottomTab() === 'sql'\"\r\n (click)=\"bottomTab.set('sql')\"\r\n >\r\n SQL generato\r\n </button>\r\n </div>\r\n\r\n @switch (bottomTab()) {\r\n @case ('diagnostics') {\r\n <dpe-diagnostics-panel class=\"dpe-shell__panel\" (navigate)=\"onNavigate($event)\" />\r\n }\r\n @case ('schema') {\r\n <dpe-schema-panel class=\"dpe-shell__panel\" />\r\n }\r\n @case ('sql') {\r\n <dpe-sql-preview class=\"dpe-shell__panel\" />\r\n }\r\n }\r\n </div>\r\n</div>\r\n","/**\r\n * Il catalogo delle definizioni: `<dpe-catalog>` (ADR 0019).\r\n *\r\n * **E' fratello dell'editor, non suo genitore.** `DpeBuilderComponent` non lo importa, non lo\r\n * conosce e non lo monta: `definition` resta `input.required`, l'ospite che vuole solo l'editor\r\n * non paga nulla, e due editor nella stessa pagina non diventano due cataloghi affiancati.\r\n *\r\n * Cosa fa: elenca, filtra in locale, crea, duplica, cancella. Cosa **non** fa: aprire. Emette il\r\n * **nome** con `open` e si ferma li', perche' chi apre puo' voler instradare, controllare permessi\r\n * o aprire in un'altra scheda — decisioni dell'ospite, non nostre.\r\n *\r\n * Provider dello store a livello di **componente**, come per l'editor: due cataloghi in due punti\r\n * dell'ospite sono due elenchi indipendenti.\r\n */\r\n\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n Injector,\r\n afterNextRender,\r\n computed,\r\n inject,\r\n output,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\n\r\nimport { DpeCatalogStore } from '../../core/dpe-catalog.store';\r\nimport { DPE_DIALECT_LABELS } from '../../core/dpe-node-catalog';\r\nimport { DpeDefinitionSummary } from '../../model/dpe-api.model';\r\n\r\n@Component({\r\n selector: 'dpe-catalog',\r\n standalone: true,\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [DpeCatalogStore],\r\n templateUrl: './dpe-catalog.component.html',\r\n})\r\nexport class DpeCatalogComponent {\r\n protected readonly store = inject(DpeCatalogStore);\r\n private readonly injector = inject(Injector);\r\n\r\n /**\r\n * Il **nome** della definizione da aprire. Non la definizione: caricarla e' dell'ospite, che\r\n * potrebbe volerlo fare per vie proprie.\r\n */\r\n readonly open = output<string>();\r\n\r\n protected readonly dialectLabels = DPE_DIALECT_LABELS;\r\n\r\n /** Filtro **locale** sui sommari gia' ricevuti: non e' una query al backend (ADR 0019). */\r\n protected readonly filter = signal('');\r\n\r\n protected readonly newName = signal('');\r\n protected readonly newLabel = signal('');\r\n\r\n /**\r\n * Conferma in **due passi**: un elenco in cui un clic distratto cancella non e' un elenco.\r\n * Tiene il nome invece di un booleano perche' la conferma appartiene a **quella** riga.\r\n */\r\n protected readonly pendingDelete = signal<string | null>(null);\r\n\r\n /** Riga in duplicazione, con i due campi del nome e dell'etichetta nuovi. */\r\n protected readonly duplicateSource = signal<string | null>(null);\r\n protected readonly duplicateName = signal('');\r\n protected readonly duplicateLabel = signal('');\r\n\r\n private readonly duplicateNameField =\r\n viewChild<ElementRef<HTMLInputElement>>('duplicateNameField');\r\n\r\n /**\r\n * Il filtro non tocca l'ordine: si tolgono righe, non si riordinano. `toLocaleLowerCase` e non\r\n * `toLowerCase` perche' un elenco di definizioni italiane si filtra anche per lettere accentate.\r\n */\r\n protected readonly visible = computed<readonly DpeDefinitionSummary[]>(() => {\r\n const needle = this.filter().trim().toLocaleLowerCase();\r\n if (needle.length === 0) {\r\n return this.store.summaries();\r\n }\r\n return this.store\r\n .summaries()\r\n .filter(\r\n (summary) =>\r\n summary.name.toLocaleLowerCase().includes(needle) ||\r\n summary.label.toLocaleLowerCase().includes(needle),\r\n );\r\n });\r\n\r\n /** Vero quando il filtro ha nascosto tutto: e' un messaggio diverso da «nessuna definizione». */\r\n protected readonly isFilteredEmpty = computed(\r\n () => this.store.summaries().length > 0 && this.visible().length === 0,\r\n );\r\n\r\n /**\r\n * Duplicare richiede **due** primitive, `load` e `createDefinition`: non esiste una primitiva\r\n * di duplicazione, il comando si compone da queste.\r\n */\r\n protected readonly canDuplicate = computed(\r\n () => this.store.capabilities.load && this.store.capabilities.createDefinition,\r\n );\r\n\r\n protected readonly duplicateReason = computed(() =>\r\n this.canDuplicate()\r\n ? 'Duplica: carica questa definizione e la ricrea con un nome nuovo'\r\n : 'Duplicazione non disponibile: questo ambiente non implementa load e createDefinition.',\r\n );\r\n\r\n /** Validazione **di forma**, l'unica ammessa nel frontend: due campi non vuoti. */\r\n protected readonly canSubmitNew = computed(\r\n () =>\r\n this.store.createCommand.isAvailable &&\r\n !this.store.isMutating() &&\r\n this.newName().trim().length > 0 &&\r\n this.newLabel().trim().length > 0,\r\n );\r\n\r\n protected readonly canSubmitDuplicate = computed(\r\n () =>\r\n this.canDuplicate() &&\r\n !this.store.isMutating() &&\r\n this.duplicateName().trim().length > 0 &&\r\n this.duplicateLabel().trim().length > 0,\r\n );\r\n\r\n protected onOpen(name: string): void {\r\n this.open.emit(name);\r\n }\r\n\r\n protected refresh(): void {\r\n this.pendingDelete.set(null);\r\n this.store.refresh();\r\n }\r\n\r\n /**\r\n * Crea e **apre il nome tornato dall'ospite**, non quello digitato: l'ospite puo' averlo\r\n * normalizzato, e aprire quello digitato aprirebbe una definizione che non esiste.\r\n */\r\n protected createNew(): void {\r\n if (!this.canSubmitNew()) {\r\n return;\r\n }\r\n const dialect = this.store.environmentDialect();\r\n if (dialect === undefined) {\r\n // Non dovrebbe accadere: `createCommand` lo esige. Se accade, non si ripiega su un\r\n // dialetto qualsiasi — sarebbe una definizione per il database sbagliato.\r\n return;\r\n }\r\n this.store\r\n .create(this.newName().trim(), this.newLabel().trim(), dialect)\r\n .subscribe((summary) => {\r\n this.newName.set('');\r\n this.newLabel.set('');\r\n this.open.emit(summary.name);\r\n });\r\n }\r\n\r\n protected startDuplicate(summary: DpeDefinitionSummary): void {\r\n this.pendingDelete.set(null);\r\n this.duplicateSource.set(summary.name);\r\n this.duplicateName.set(`${summary.name}Copia`);\r\n this.duplicateLabel.set(`${summary.label} (copia)`);\r\n // `afterNextRender` e non `setTimeout`: il rinvio al task successivo scatta **prima** del\r\n // refresh della view, la query e' ancora vuota e il focus non arriva — senza nessun errore.\r\n afterNextRender(() => this.duplicateNameField()?.nativeElement.focus(), {\r\n injector: this.injector,\r\n });\r\n }\r\n\r\n protected cancelDuplicate(): void {\r\n this.duplicateSource.set(null);\r\n }\r\n\r\n protected confirmDuplicate(): void {\r\n const source = this.duplicateSource();\r\n if (source === null || !this.canSubmitDuplicate()) {\r\n return;\r\n }\r\n this.store\r\n .duplicate(source, this.duplicateName().trim(), this.duplicateLabel().trim())\r\n .subscribe(() => {\r\n // Si resta nell'elenco: la riga nuova che compare **e'** la conferma. Aprire la copia\r\n // porterebbe via dall'elenco proprio chi sta riorganizzando il catalogo.\r\n this.duplicateSource.set(null);\r\n });\r\n }\r\n\r\n protected askDelete(name: string): void {\r\n this.duplicateSource.set(null);\r\n this.pendingDelete.set(name);\r\n }\r\n\r\n protected cancelDelete(): void {\r\n this.pendingDelete.set(null);\r\n }\r\n\r\n protected confirmDelete(name: string): void {\r\n this.pendingDelete.set(null);\r\n this.store.remove(name);\r\n }\r\n\r\n /** Solo la data, senza ora: un elenco non e' un registro di audit. */\r\n protected formatDate(value: string): string {\r\n const parsed = new Date(value);\r\n return Number.isNaN(parsed.getTime()) ? value : parsed.toLocaleDateString();\r\n }\r\n}\r\n","<!--\r\n `.dpe-theme` porta le variabili del tema anche fuori dall’editor: il catalogo e’ un componente\r\n **fratello**, quindi non puo’ contare sulla classe radice di `<dpe-builder>`. La variante scura\r\n resta quella prevista, `data-dpe-theme=\"dark\"` su un contenitore dell’ospite.\r\n-->\r\n<section class=\"dpe-theme dpe-cat\" aria-labelledby=\"dpe-cat-title\">\r\n <header class=\"dpe-cat__bar\">\r\n <h2 class=\"dpe-cat__title\" id=\"dpe-cat-title\">Definizioni DPE</h2>\r\n\r\n <span class=\"dpe-cat__count\">\r\n @if (store.isLoading()) {\r\n caricamento…\r\n } @else if (!store.capabilities.listDefinitions) {\r\n elenco non disponibile\r\n } @else {\r\n {{ visible().length }} di {{ store.summaries().length }}\r\n }\r\n </span>\r\n\r\n <input\r\n class=\"dpe-cat__filter\"\r\n type=\"search\"\r\n placeholder=\"Filtra per nome o etichetta\"\r\n aria-label=\"Filtra le definizioni\"\r\n [value]=\"filter()\"\r\n (input)=\"filter.set($any($event.target).value)\"\r\n />\r\n\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!store.capabilities.listDefinitions || store.isLoading()\"\r\n [title]=\"\r\n store.capabilities.listDefinitions\r\n ? 'Ricarica l’elenco'\r\n : 'Questo ambiente non implementa listDefinitions.'\r\n \"\r\n (click)=\"refresh()\"\r\n >\r\n ⟳ Aggiorna\r\n </button>\r\n </header>\r\n\r\n @if (store.error(); as error) {\r\n <!--\r\n Banner persistente: un errore di catalogo che svanisce lascia un elenco vecchio senza dire\r\n che e’ vecchio. La categoria si mostra perche’ distingue «riprova» da «chiedi all’ospite».\r\n -->\r\n <p class=\"dpe-cat__error\" role=\"alert\">\r\n <strong>{{ error.category }}</strong> {{ error.message }}\r\n <button type=\"button\" class=\"dpe-cat__dismiss\" aria-label=\"Chiudi\" (click)=\"store.dismissError()\">\r\n ×\r\n </button>\r\n </p>\r\n }\r\n\r\n <ul class=\"dpe-cat__list\">\r\n @for (summary of visible(); track summary.name) {\r\n <li class=\"dpe-cat__item\" [class.dpe-cat__item--busy]=\"store.isMutating()\">\r\n <div class=\"dpe-cat__row\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__open\"\r\n [title]=\"'Apri ' + summary.label\"\r\n (click)=\"onOpen(summary.name)\"\r\n >\r\n <span class=\"dpe-cat__label\">{{ summary.label }}</span>\r\n <span class=\"dpe-cat__meta\">\r\n <!--\r\n Solo i fatti **presenti**: cio’ che il sommario non porta non si stima. Contare i\r\n nodi lato client vorrebbe dire caricare tutte le definizioni per disegnare un\r\n elenco (ADR 0019).\r\n -->\r\n <code class=\"dpe-cat__name\">{{ summary.name }}</code>\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ dialectLabels[summary.dialect] }}\r\n @if (summary.status) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.status === 'Active' ? 'attiva' : 'non attiva' }}\r\n }\r\n @if (summary.runMode) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.runMode === 'Batch' ? 'batch' : 'a richiesta' }}\r\n }\r\n @if (summary.isTemplate) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n modello\r\n }\r\n @if (summary.nodeCount !== undefined) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ summary.nodeCount }} {{ summary.nodeCount === 1 ? 'nodo' : 'nodi' }}\r\n }\r\n @if (summary.updatedAt) {\r\n <span class=\"dpe-cat__dot\"> · </span>\r\n {{ formatDate(summary.updatedAt) }}\r\n @if (summary.updatedBy) {\r\n · {{ summary.updatedBy }}\r\n }\r\n }\r\n </span>\r\n @if (summary.description) {\r\n <span class=\"dpe-cat__desc\">{{ summary.description }}</span>\r\n }\r\n </button>\r\n\r\n <!--\r\n `hasErrors` e’ **riportato, non ricalcolato** (ADR 0019): il frontend non valida\r\n niente. Per questo l’etichetta dice «ultima validazione nota» e non «invalida»: puo’\r\n essere vecchia, e spacciarla per verita’ sarebbe una validazione fatta dal client per\r\n interposta persona. Assente, non compare nulla.\r\n -->\r\n @if (summary.hasErrors !== undefined) {\r\n <span\r\n class=\"dpe-cat__flag\"\r\n [class.dpe-cat__flag--errors]=\"summary.hasErrors\"\r\n [title]=\"\r\n summary.hasErrors\r\n ? 'Ultima validazione nota all’ambiente: con errori. E’ uno stato riportato, non ricalcolato qui.'\r\n : 'Ultima validazione nota all’ambiente: senza errori. E’ uno stato riportato, non ricalcolato qui.'\r\n \"\r\n >\r\n {{ summary.hasErrors ? 'con errori (stato noto)' : 'senza errori (stato noto)' }}\r\n </span>\r\n }\r\n\r\n <div class=\"dpe-cat__actions\">\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!canDuplicate() || store.isMutating()\"\r\n [title]=\"duplicateReason()\"\r\n (click)=\"startDuplicate(summary)\"\r\n >\r\n Duplica\r\n </button>\r\n\r\n @if (pendingDelete() === summary.name) {\r\n <!-- Conferma in **due passi**: la prima pressione chiede, la seconda cancella. -->\r\n <span class=\"dpe-cat__confirm\">\r\n Eliminare «{{ summary.name }}»?\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--danger\"\r\n (click)=\"confirmDelete(summary.name)\"\r\n >\r\n Elimina\r\n </button>\r\n <button type=\"button\" class=\"dpe-cat__btn\" (click)=\"cancelDelete()\">Annulla</button>\r\n </span>\r\n } @else {\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn\"\r\n [disabled]=\"!store.capabilities.deleteDefinition || store.isMutating()\"\r\n [title]=\"\r\n store.capabilities.deleteDefinition\r\n ? 'Elimina (chiede conferma)'\r\n : 'Eliminazione non disponibile: questo ambiente non implementa deleteDefinition.'\r\n \"\r\n (click)=\"askDelete(summary.name)\"\r\n >\r\n Elimina\r\n </button>\r\n }\r\n </div>\r\n </div>\r\n\r\n @if (duplicateSource() === summary.name) {\r\n <!--\r\n Duplicare e’ `load` piu’ `createDefinition`: nessuna primitiva nuova sul contratto.\r\n Il dialetto resta quello della definizione copiata — le espressioni sono SQL nativo.\r\n -->\r\n <div class=\"dpe-cat__form dpe-cat__form--inline\">\r\n <label class=\"dpe-cat__field\">\r\n <span>Nome della copia</span>\r\n <input\r\n #duplicateNameField\r\n class=\"dpe-cat__input\"\r\n [value]=\"duplicateName()\"\r\n (input)=\"duplicateName.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <label class=\"dpe-cat__field\">\r\n <span>Etichetta della copia</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n [value]=\"duplicateLabel()\"\r\n (input)=\"duplicateLabel.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--primary\"\r\n [disabled]=\"!canSubmitDuplicate()\"\r\n (click)=\"confirmDuplicate()\"\r\n >\r\n Duplica\r\n </button>\r\n <button type=\"button\" class=\"dpe-cat__btn\" (click)=\"cancelDuplicate()\">Annulla</button>\r\n </div>\r\n }\r\n </li>\r\n } @empty {\r\n <li class=\"dpe-cat__empty\">\r\n @if (!store.capabilities.listDefinitions) {\r\n Questo ambiente non implementa <code>listDefinitions</code>: l’elenco lo fornisce\r\n l’applicazione ospite.\r\n } @else if (store.isLoading()) {\r\n Caricamento dell’elenco…\r\n } @else if (isFilteredEmpty()) {\r\n Nessuna definizione corrisponde al filtro.\r\n } @else if (store.hasLoaded()) {\r\n Nessuna definizione. Creane una qui sotto.\r\n } @else {\r\n Elenco non disponibile.\r\n }\r\n </li>\r\n }\r\n </ul>\r\n\r\n <footer class=\"dpe-cat__foot\">\r\n <div class=\"dpe-cat__form\">\r\n <label class=\"dpe-cat__field\">\r\n <span>Nome tecnico</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n placeholder=\"RiepilogoOrdini\"\r\n [value]=\"newName()\"\r\n [disabled]=\"!store.createCommand.isAvailable\"\r\n (input)=\"newName.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <label class=\"dpe-cat__field\">\r\n <!--\r\n Si chiedono **due** campi e non uno: passare il nome anche come etichetta produce per\r\n sempre un catalogo di nomi tecnici, e un default sbagliato non si corregge piu’.\r\n -->\r\n <span>Etichetta</span>\r\n <input\r\n class=\"dpe-cat__input\"\r\n placeholder=\"Riepilogo ordini\"\r\n [value]=\"newLabel()\"\r\n [disabled]=\"!store.createCommand.isAvailable\"\r\n (input)=\"newLabel.set($any($event.target).value)\"\r\n />\r\n </label>\r\n <button\r\n type=\"button\"\r\n class=\"dpe-cat__btn dpe-cat__btn--primary\"\r\n [disabled]=\"!canSubmitNew()\"\r\n [title]=\"\r\n store.createCommand.reason ??\r\n 'Crea la definizione e la apre. Il dialetto viene dall’ambiente, non si sceglie qui.'\r\n \"\r\n (click)=\"createNew()\"\r\n >\r\n + Crea e apri\r\n </button>\r\n </div>\r\n\r\n <p class=\"dpe-cat__hint\">\r\n @if (store.createCommand.isAvailable) {\r\n <!--\r\n Detto **al momento della creazione**, non lasciato scoprire: una definizione nuova non\r\n ha sorgenti ne’ writeback, quindi l’editor la segnalera’ invalida. E’ normale — il\r\n modello tollera l’incompleto e la validazione lo racconta.\r\n -->\r\n Il dialetto della definizione nuova e’ quello dichiarato dall’ambiente\r\n @if (store.environmentDialect(); as declared) {\r\n (<strong>{{ dialectLabels[declared] }}</strong>)\r\n }\r\n e non si sceglie qui: le espressioni sono SQL nativo di quel dialetto. Una definizione appena creata\r\n e’ <strong>invalida</strong> — servono almeno una sorgente e un writeback — ed e’ normale.\r\n } @else {\r\n {{ store.createCommand.reason }}\r\n }\r\n </p>\r\n </footer>\r\n</section>\r\n","/*\r\n * Superficie pubblica di `@esfaenza/dpe-builder`.\r\n *\r\n * Cio' che non e' esportato qui non e' API: chi integra la libreria usa questi tipi e nulla\r\n * di piu'. In questa tranche esistono contratto, modello e `core/`; i componenti dell'editor\r\n * arrivano nella successiva.\r\n */\r\n\r\n// Contratto verso il backend: il contratto **e'** la classe astratta (ADR 0007).\r\nexport * from './lib/api/dpe-builder-api';\r\nexport * from './lib/api/dpe-api-error';\r\n// Client HTTP di libreria (ADR 0020, che revisiona la collocazione decisa dall'ADR 0007). E'\r\n// **una** implementazione del contratto, non il contratto: chi non usa HTTP non la registra e\r\n// `sideEffects: false` la rende eliminabile dal bundle.\r\nexport * from './lib/api/http-dpe-builder-api';\r\n\r\n// Modello: allineato a mano ai record C#.\r\nexport * from './lib/model/dpe-definition.model';\r\nexport * from './lib/model/dpe-diagnostics.model';\r\nexport * from './lib/model/dpe-api.model';\r\n\r\n// Stato e utility pure.\r\nexport * from './lib/core/dpe-capabilities';\r\nexport * from './lib/core/dpe-catalog.store';\r\nexport * from './lib/core/dpe-document.store';\r\nexport * from './lib/core/dpe-diagnostics.util';\r\nexport * from './lib/core/dpe-graph';\r\nexport * from './lib/core/dpe-layout.service';\r\nexport * from './lib/core/dpe-metadata.store';\r\nexport * from './lib/core/dpe-node-catalog';\r\nexport * from './lib/core/dpe-node-icons';\r\nexport * from './lib/core/dpe-node-factory';\r\nexport * from './lib/core/dpe-node-layout';\r\nexport * from './lib/core/dpe-validation.service';\r\nexport * from './lib/core/dpe-viewport';\r\n\r\n// UI: il componente radice e i pezzi montabili da soli.\r\nexport * from './lib/ui/dpe-builder.component';\r\nexport * from './lib/ui/canvas/dpe-canvas.component';\r\n// Il catalogo (ADR 0019) e' **fratello** dell'editor: esportato perche' l'ospite possa montarlo,\r\n// e non importato da `DpeBuilderComponent`. Chi vuole solo l'editor non lo paga.\r\nexport * from './lib/ui/catalog/dpe-catalog.component';\r\nexport * from './lib/ui/canvas/dpe-canvas.model';\r\nexport * from './lib/ui/palette/dpe-node-palette.component';\r\nexport * from './lib/ui/inspector/dpe-node-inspector.component';\r\nexport * from './lib/ui/inspector/dpe-node-inspector-base';\r\nexport * from './lib/ui/diagnostics/dpe-diagnostics-panel.component';\r\nexport * from './lib/ui/schema/dpe-schema-panel.component';\r\nexport * from './lib/ui/preview/dpe-sql-preview.component';\r\nexport * from './lib/ui/shared/dpe-expression-editor.component';\r\nexport * from './lib/ui/shared/dpe-column-type-editor.component';\r\nexport * from './lib/ui/shared/dpe-select-value.directive';\r\nexport * from './lib/ui/shared/dpe-node-icon.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["FUNCTIONS","KINDS","DELIMITERS"],"mappings":"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"}
|