ngx-dynamic-entity 1.12.0 → 1.14.0
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.
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, Type, EnvironmentProviders, WritableSignal, OnInit, OnChanges, OnDestroy, EventEmitter, SimpleChanges } from '@angular/core';
|
|
3
|
-
import { ReferenceOption
|
|
2
|
+
import { InjectionToken, Type, EnvironmentProviders, WritableSignal, OnInit, OnChanges, OnDestroy, EventEmitter, SimpleChanges, Provider } from '@angular/core';
|
|
3
|
+
import { ReferenceOption, LocalizedText, EntityFormConfig, FormRule, ImportLookups, MappingPlan, ImportResult, TemplateSpec, SheetData, CommonModuleEntry, EntityReferenceLoader, LookupListSource, RecordMigration, FileUploadHandler, FieldValidators, NestedFieldConfig, ReferenceLoaderContext, DropdownOption, LookupListValue, NestedTabConfig, RuleEvaluationResult, ImportColumn, UnsupportedColumn, ImportRowError } from '@dynamic-entity/core';
|
|
4
4
|
export { AutoPatchConfig, CommonModuleEntry, ComponentClass, DropdownOption, EntityFormConfig, EntityPermissions, EntityReferenceConfig, EntityReferenceLoader, FieldTableConfig, FieldValidators, FileRef, FormRule, LocalizedText, NestedFieldConfig, NestedTabConfig, PatchOnTrueMapping, RbacContext, ReferenceLoaderContext, ReferenceOption, RichFieldType, RuleAction, RuleCondition, RuleEvaluationResult, VersionedRecord, formatDisplayValue, normalizeConfig, normalizeOption, resolveLabel, resolveOptionLabel, resolveOptionValue, valuesMatch } from '@dynamic-entity/core';
|
|
5
5
|
import { ValidatorFn, AsyncValidatorFn, ValidationErrors, FormGroup, FormArray, AbstractControl } from '@angular/forms';
|
|
6
6
|
import * as rxjs from 'rxjs';
|
|
7
|
+
import * as ngx_dynamic_entity from 'ngx-dynamic-entity';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Backing store for cached reference options.
|
|
@@ -15,8 +16,8 @@ import * as rxjs from 'rxjs';
|
|
|
15
16
|
* that must not silently persist a tenant's data.
|
|
16
17
|
*/
|
|
17
18
|
interface EntityRefCacheStore {
|
|
18
|
-
get(key: string): ReferenceOption
|
|
19
|
-
set(key: string, value: ReferenceOption
|
|
19
|
+
get(key: string): ReferenceOption[] | undefined;
|
|
20
|
+
set(key: string, value: ReferenceOption[]): void;
|
|
20
21
|
delete(key: string): void;
|
|
21
22
|
/** Every key currently held — used for prefix invalidation of one entity. */
|
|
22
23
|
keys(): string[];
|
|
@@ -25,8 +26,8 @@ interface EntityRefCacheStore {
|
|
|
25
26
|
/** Default in-memory store. Lives as long as the injector that created it. */
|
|
26
27
|
declare class InMemoryEntityRefCacheStore implements EntityRefCacheStore {
|
|
27
28
|
private readonly map;
|
|
28
|
-
get(key: string): ReferenceOption
|
|
29
|
-
set(key: string, value: ReferenceOption
|
|
29
|
+
get(key: string): ReferenceOption[] | undefined;
|
|
30
|
+
set(key: string, value: ReferenceOption[]): void;
|
|
30
31
|
delete(key: string): void;
|
|
31
32
|
keys(): string[];
|
|
32
33
|
clear(): void;
|
|
@@ -95,6 +96,40 @@ declare const DEFAULT_UI_TEXT: {
|
|
|
95
96
|
criticalFieldUnlockHint: string;
|
|
96
97
|
dismissBanner: string;
|
|
97
98
|
jumpToField: string;
|
|
99
|
+
importUpload: string;
|
|
100
|
+
importMap: string;
|
|
101
|
+
importReview: string;
|
|
102
|
+
importDone: string;
|
|
103
|
+
importChooseFile: string;
|
|
104
|
+
importFileChosen: string;
|
|
105
|
+
importReading: string;
|
|
106
|
+
importNeedFile: string;
|
|
107
|
+
importTemplateHeading: string;
|
|
108
|
+
importTemplateExplain: string;
|
|
109
|
+
importTemplateDownload: string;
|
|
110
|
+
importTemplateSelectAll: string;
|
|
111
|
+
importTemplateSelectNone: string;
|
|
112
|
+
importTemplateUnsupported: string;
|
|
113
|
+
importColumnInFile: string;
|
|
114
|
+
importTargetField: string;
|
|
115
|
+
importUnmapped: string;
|
|
116
|
+
importGuessed: string;
|
|
117
|
+
importMappedCount: string;
|
|
118
|
+
importRequiredUnmapped: string;
|
|
119
|
+
importPreviewHeading: string;
|
|
120
|
+
importRowRejected: string;
|
|
121
|
+
importRunImport: string;
|
|
122
|
+
importImporting: string;
|
|
123
|
+
importSucceeded: string;
|
|
124
|
+
importSkippedRows: string;
|
|
125
|
+
importFailedRows: string;
|
|
126
|
+
importErrorsTruncated: string;
|
|
127
|
+
importStartOver: string;
|
|
128
|
+
importErrorsHeading: string;
|
|
129
|
+
importErrorRow: string;
|
|
130
|
+
importErrorField: string;
|
|
131
|
+
importErrorReason: string;
|
|
132
|
+
importPlanProblem: string;
|
|
98
133
|
entityLabel: string;
|
|
99
134
|
criticalFieldChanged: string;
|
|
100
135
|
recordModified: string;
|
|
@@ -162,6 +197,102 @@ declare class UiTextService {
|
|
|
162
197
|
static ɵprov: i0.ɵɵInjectableDeclaration<UiTextService>;
|
|
163
198
|
}
|
|
164
199
|
|
|
200
|
+
/**
|
|
201
|
+
* import-contracts.ts — the two seams the import wizard hangs on.
|
|
202
|
+
*
|
|
203
|
+
* Both follow the pattern the rest of this package already uses for anything the library
|
|
204
|
+
* cannot decide for a consumer — `FileUploadHandler`, `EntityReferenceLoader`,
|
|
205
|
+
* `LookupListLoader`: a function type here, a token to register it against, and a default
|
|
206
|
+
* that works without registering anything.
|
|
207
|
+
*
|
|
208
|
+
* **Why two rather than one.** Reading a file and deciding where the work happens are
|
|
209
|
+
* different questions with different answers. A consumer may want `.xlsx` support in a
|
|
210
|
+
* wizard that still runs entirely in the browser, or plain CSV that is nonetheless processed
|
|
211
|
+
* on a server because their files have fifty thousand rows. Collapsing them into one option
|
|
212
|
+
* would make each answer imply the other.
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Reads an uploaded file into headers and positional rows.
|
|
217
|
+
*
|
|
218
|
+
* Positional (`string[][]`), not keyed by header, because a real sheet carries duplicate
|
|
219
|
+
* headers and blank ones — and because a mapping entry addresses a column by index for
|
|
220
|
+
* exactly that reason. A parser that returned objects keyed by header would silently lose
|
|
221
|
+
* the second of two columns both called "Notes".
|
|
222
|
+
*
|
|
223
|
+
* The library ships a CSV implementation and no more. Registering one that understands
|
|
224
|
+
* `.xlsx` is how a consumer adds it, and which spreadsheet library they use stays their
|
|
225
|
+
* choice — this package has no runtime dependency and gains none here.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* provideNgxDynamicEntity({
|
|
229
|
+
* sheetParser: async file => {
|
|
230
|
+
* const workbook = XLSX.read(await file.arrayBuffer());
|
|
231
|
+
* const rows = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {
|
|
232
|
+
* header: 1, raw: false, defval: '',
|
|
233
|
+
* }) as string[][];
|
|
234
|
+
* return { headers: rows[0] ?? [], rows: rows.slice(1) };
|
|
235
|
+
* },
|
|
236
|
+
* })
|
|
237
|
+
*/
|
|
238
|
+
type SheetParser = (file: File) => SheetData | Promise<SheetData>;
|
|
239
|
+
/** The formats a generated template can be written in. CSV needs no dependency. */
|
|
240
|
+
type TemplateFormat = 'csv' | 'xlsx';
|
|
241
|
+
/** What the wizard needs to know about the entity it is importing into. */
|
|
242
|
+
interface ImportContext {
|
|
243
|
+
config: EntityFormConfig;
|
|
244
|
+
/**
|
|
245
|
+
* Rules that apply to this entity.
|
|
246
|
+
*
|
|
247
|
+
* Without them an import checks field validators only, which is **not** what the form
|
|
248
|
+
* enforces: a rule can attach an error, and a rule can hide a field, which must relax
|
|
249
|
+
* `required`. Pass the same rules the form is rendered with or the two disagree.
|
|
250
|
+
*/
|
|
251
|
+
rules?: readonly FormRule[];
|
|
252
|
+
/** Values for any `listName` field, already resolved — core cannot reach `LOOKUP_REGISTRY`. */
|
|
253
|
+
lookups?: ImportLookups;
|
|
254
|
+
lang?: string;
|
|
255
|
+
}
|
|
256
|
+
/** What a first look at an uploaded file yields. */
|
|
257
|
+
interface ImportPreview {
|
|
258
|
+
headers: string[];
|
|
259
|
+
/** The first few rows, for the mapping screen to show under each column. */
|
|
260
|
+
sample: string[][];
|
|
261
|
+
/** Where the suggester got to. Every inferred match is tagged `guess`. */
|
|
262
|
+
suggestion: MappingPlan;
|
|
263
|
+
/** Total data rows in the file, which may be far more than `sample` holds. */
|
|
264
|
+
rowCount: number;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Where the work happens.
|
|
268
|
+
*
|
|
269
|
+
* The default implementation does everything in the browser with `@dynamic-entity/core` and
|
|
270
|
+
* never touches the network, so the wizard is fully usable with no backend at all. Register
|
|
271
|
+
* an implementation that posts to a server and the same components drive it instead — the
|
|
272
|
+
* engine underneath is the same code either way, which is the point of it being pure.
|
|
273
|
+
*
|
|
274
|
+
* This is the real answer to "should parsing happen on the client or the server?": both,
|
|
275
|
+
* chosen at registration, without a second implementation of the mapping rules.
|
|
276
|
+
*/
|
|
277
|
+
interface ImportTransport {
|
|
278
|
+
/** Headers, a sample, and a suggested mapping for a freshly chosen file. */
|
|
279
|
+
preview(file: File, context: ImportContext): Promise<ImportPreview>;
|
|
280
|
+
/** Apply a plan to the whole file. */
|
|
281
|
+
commit(file: File, plan: MappingPlan, context: ImportContext): Promise<ImportResult>;
|
|
282
|
+
/**
|
|
283
|
+
* Render a template for download.
|
|
284
|
+
*
|
|
285
|
+
* `fields` is the selection the user actually made — refs with row numbers stripped, one per
|
|
286
|
+
* choice — and `spec` is that selection already expanded against the config. A transport that
|
|
287
|
+
* renders locally wants the spec; one that asks a server wants the selection, because the
|
|
288
|
+
* server has the config and only the choice needs to cross the wire. Passing both means
|
|
289
|
+
* neither has to reconstruct the other: the HTTP transport used to recover the selection from
|
|
290
|
+
* the expanded spec, which worked only because `stripIndices` happens to be exactly the
|
|
291
|
+
* inverse of the expansion. Optional, so an existing implementation keeps compiling.
|
|
292
|
+
*/
|
|
293
|
+
template(spec: TemplateSpec, format: TemplateFormat, context: ImportContext, fields?: readonly string[]): Promise<Blob>;
|
|
294
|
+
}
|
|
295
|
+
|
|
165
296
|
/** Roles that see XXXXXXXXX for masked fields. Presentational only — enforce authz server-side. */
|
|
166
297
|
declare const MASKED_ROLES: InjectionToken<string[]>;
|
|
167
298
|
/**
|
|
@@ -279,6 +410,46 @@ declare const COMMON_MODULES_REGISTRY: InjectionToken<CommonModuleEntry[]>;
|
|
|
279
410
|
* { provide: UPLOAD_HANDLER, useFactory: () => (file: File) => myUploadService.upload(file) }
|
|
280
411
|
*/
|
|
281
412
|
declare const UPLOAD_HANDLER: InjectionToken<FileUploadHandler>;
|
|
413
|
+
/**
|
|
414
|
+
* Reads an uploaded spreadsheet into headers and positional rows, for the import wizard.
|
|
415
|
+
*
|
|
416
|
+
* Unregistered, the wizard reads CSV with the dependency-free parser in
|
|
417
|
+
* `@dynamic-entity/core`, so it works with nothing provided. Register one to accept `.xlsx`
|
|
418
|
+
* — which spreadsheet library that uses stays the consumer's choice, and this package keeps
|
|
419
|
+
* having no runtime dependency.
|
|
420
|
+
*
|
|
421
|
+
* Rows come back **positional** (`string[][]`) rather than keyed by header, because a real
|
|
422
|
+
* sheet has duplicate headers and blank ones; a header-keyed row silently loses the second
|
|
423
|
+
* of two columns both called "Notes".
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* provideNgxDynamicEntity({
|
|
427
|
+
* sheetParser: async file => {
|
|
428
|
+
* const wb = XLSX.read(await file.arrayBuffer());
|
|
429
|
+
* const rows = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {
|
|
430
|
+
* header: 1, raw: false, defval: '',
|
|
431
|
+
* }) as string[][];
|
|
432
|
+
* return { headers: rows[0] ?? [], rows: rows.slice(1) };
|
|
433
|
+
* },
|
|
434
|
+
* })
|
|
435
|
+
*/
|
|
436
|
+
declare const SHEET_PARSER: InjectionToken<SheetParser>;
|
|
437
|
+
/**
|
|
438
|
+
* Where an import's work happens.
|
|
439
|
+
*
|
|
440
|
+
* Unregistered, everything runs in the browser through `@dynamic-entity/core` and nothing
|
|
441
|
+
* touches the network — the wizard is fully usable with no backend. Register one that posts
|
|
442
|
+
* to a server and the same components drive that instead, over the same pure mapping engine,
|
|
443
|
+
* which is what keeps a client-side import and a server-side one from disagreeing about what
|
|
444
|
+
* they produced.
|
|
445
|
+
*
|
|
446
|
+
* The reason to register one is size: the default reads the whole file into memory, which is
|
|
447
|
+
* right for a sheet somebody assembled and wrong for a fifty-thousand-row export.
|
|
448
|
+
*
|
|
449
|
+
* @example
|
|
450
|
+
* { provide: IMPORT_TRANSPORT, useClass: HttpImportTransport }
|
|
451
|
+
*/
|
|
452
|
+
declare const IMPORT_TRANSPORT: InjectionToken<ImportTransport>;
|
|
282
453
|
/**
|
|
283
454
|
* Backing store for the entity-reference options cache. Defaults to in-memory.
|
|
284
455
|
* Provide your own to make the cache outlive a page refresh.
|
|
@@ -375,13 +546,13 @@ interface NgxDynamicEntityConfig {
|
|
|
375
546
|
* Entity-ref option loaders keyed by entity key.
|
|
376
547
|
* Each receives `{ parentValue, filters, lang }` and may return an array, Promise, or Observable.
|
|
377
548
|
*/
|
|
378
|
-
entityRefs?: Record<string, EntityReferenceLoader
|
|
549
|
+
entityRefs?: Record<string, EntityReferenceLoader>;
|
|
379
550
|
/**
|
|
380
551
|
* Named master lists keyed by list name, for fields that set `listName`.
|
|
381
552
|
* Each may be the values themselves (array/Promise/Observable) or a loader function — prefer
|
|
382
553
|
* a loader for anything fetched, so an unused list is never loaded.
|
|
383
554
|
*/
|
|
384
|
-
lookups?: Record<string, LookupListSource
|
|
555
|
+
lookups?: Record<string, LookupListSource>;
|
|
385
556
|
/**
|
|
386
557
|
* Override the messages shown under invalid fields, keyed by Angular error key. A value is
|
|
387
558
|
* a string, or a function receiving `(language, error)` when it needs the error's detail.
|
|
@@ -414,7 +585,21 @@ interface NgxDynamicEntityConfig {
|
|
|
414
585
|
* Ordered steps that upgrade a saved record when `EntityFormConfig.version` moves ahead
|
|
415
586
|
* of the record's `_configVersion`. Applied to `initialData` before the form is patched.
|
|
416
587
|
*/
|
|
417
|
-
migrations?: RecordMigration
|
|
588
|
+
migrations?: RecordMigration[];
|
|
589
|
+
/**
|
|
590
|
+
* Reads an uploaded spreadsheet for the import wizard, as `{ headers, rows }` with rows
|
|
591
|
+
* positional rather than keyed by header.
|
|
592
|
+
*
|
|
593
|
+
* Omit it and CSV is read by the dependency-free parser in `@dynamic-entity/core`; supply
|
|
594
|
+
* one to accept `.xlsx`, using whichever spreadsheet library you already have.
|
|
595
|
+
*/
|
|
596
|
+
sheetParser?: SheetParser;
|
|
597
|
+
/**
|
|
598
|
+
* Where an import's work happens. Omit it and the whole import runs in the browser with no
|
|
599
|
+
* network at all; supply one that posts to a server for files too large to hold in memory.
|
|
600
|
+
* Either way the mapping, coercion and validation are the same pure functions.
|
|
601
|
+
*/
|
|
602
|
+
importTransport?: ImportTransport;
|
|
418
603
|
}
|
|
419
604
|
/**
|
|
420
605
|
* Provider function for ngx-dynamic-entity.
|
|
@@ -539,7 +724,7 @@ declare class EntityRefRegistryService {
|
|
|
539
724
|
* Get the option loader for an entity key.
|
|
540
725
|
* @returns The loader, or null if none is registered.
|
|
541
726
|
*/
|
|
542
|
-
resolve(entityKey: string): EntityReferenceLoader
|
|
727
|
+
resolve(entityKey: string): EntityReferenceLoader | null;
|
|
543
728
|
has(entityKey: string): boolean;
|
|
544
729
|
static ɵfac: i0.ɵɵFactoryDeclaration<EntityRefRegistryService, never>;
|
|
545
730
|
static ɵprov: i0.ɵɵInjectableDeclaration<EntityRefRegistryService>;
|
|
@@ -548,7 +733,7 @@ declare class EntityRefRegistryService {
|
|
|
548
733
|
interface EntityRefSelection {
|
|
549
734
|
fieldId: string;
|
|
550
735
|
/** The chosen option, or `null` when the selection was cleared. */
|
|
551
|
-
option: ReferenceOption
|
|
736
|
+
option: ReferenceOption | null;
|
|
552
737
|
}
|
|
553
738
|
/**
|
|
554
739
|
* EntityRefSelectionService — the channel an entity-ref field uses to publish *which record*
|
|
@@ -563,7 +748,7 @@ interface EntityRefSelection {
|
|
|
563
748
|
declare class EntityRefSelectionService {
|
|
564
749
|
private readonly subject;
|
|
565
750
|
readonly selection$: rxjs.Observable<EntityRefSelection>;
|
|
566
|
-
emit(fieldId: string, option: ReferenceOption
|
|
751
|
+
emit(fieldId: string, option: ReferenceOption | null): void;
|
|
567
752
|
static ɵfac: i0.ɵɵFactoryDeclaration<EntityRefSelectionService, never>;
|
|
568
753
|
static ɵprov: i0.ɵɵInjectableDeclaration<EntityRefSelectionService>;
|
|
569
754
|
}
|
|
@@ -588,7 +773,7 @@ declare class CascadeDataService {
|
|
|
588
773
|
* Load the options for a field, cascade-filtered against `parentValue`.
|
|
589
774
|
* Returns `[]` when no loader is registered, or when a cascade child has no parent value yet.
|
|
590
775
|
*/
|
|
591
|
-
load(field: NestedFieldConfig, ctx?: ReferenceLoaderContext): Promise<ReferenceOption
|
|
776
|
+
load(field: NestedFieldConfig, ctx?: ReferenceLoaderContext): Promise<ReferenceOption[]>;
|
|
592
777
|
/**
|
|
593
778
|
* Warm the cache for every entity a config's cascades depend on, so changing a parent
|
|
594
779
|
* resolves from memory instead of a round-trip.
|
|
@@ -603,7 +788,7 @@ declare class CascadeDataService {
|
|
|
603
788
|
* Child options for a parent selection, from cache only — no load is triggered.
|
|
604
789
|
* Returns `[]` when the entity has not been preloaded.
|
|
605
790
|
*/
|
|
606
|
-
getCachedChildOptions(field: NestedFieldConfig, parentValue: unknown, lang?: string): ReferenceOption
|
|
791
|
+
getCachedChildOptions(field: NestedFieldConfig, parentValue: unknown, lang?: string): ReferenceOption[];
|
|
607
792
|
/** Forget the preload for one config. The option cache itself is untouched. */
|
|
608
793
|
clearCache(formConfigId: string): void;
|
|
609
794
|
/** Every entity-ref field in the config that participates in a cascade. */
|
|
@@ -637,9 +822,9 @@ declare class EntityReferenceService {
|
|
|
637
822
|
* Options for an entity, from cache when present.
|
|
638
823
|
* Concurrent callers with the same key share one load.
|
|
639
824
|
*/
|
|
640
|
-
load(entityKey: string, ctx?: ReferenceLoaderContext): Promise<ReferenceOption
|
|
825
|
+
load(entityKey: string, ctx?: ReferenceLoaderContext): Promise<ReferenceOption[]>;
|
|
641
826
|
/** Cached options without triggering a load. `undefined` when not cached. */
|
|
642
|
-
peek(entityKey: string, ctx?: ReferenceLoaderContext): ReferenceOption
|
|
827
|
+
peek(entityKey: string, ctx?: ReferenceLoaderContext): ReferenceOption[] | undefined;
|
|
643
828
|
/**
|
|
644
829
|
* Display text for a stored reference value, synchronously.
|
|
645
830
|
* Returns `undefined` when the entity's options have never been loaded.
|
|
@@ -785,7 +970,7 @@ declare class RulesEvaluationService {
|
|
|
785
970
|
/**
|
|
786
971
|
* Evaluate rules against form values and optional original baseline values.
|
|
787
972
|
*/
|
|
788
|
-
evaluate(rules: FormRule[] | undefined | null, values: Record<string, unknown>, originalValues?: Record<string, unknown>): RuleEvaluationResult
|
|
973
|
+
evaluate(rules: FormRule[] | undefined | null, values: Record<string, unknown>, originalValues?: Record<string, unknown>): RuleEvaluationResult;
|
|
789
974
|
/**
|
|
790
975
|
* Filter rules pertinent to a single tab.
|
|
791
976
|
*/
|
|
@@ -990,7 +1175,7 @@ declare class DynamicFormComponent implements OnInit, OnChanges, OnDestroy {
|
|
|
990
1175
|
/** Previous values, for detecting `patchOnTrue` false→true transitions. */
|
|
991
1176
|
private previousValues;
|
|
992
1177
|
handleKeyboardEvent(event: KeyboardEvent): void;
|
|
993
|
-
readonly ruleResult: i0.Signal<RuleEvaluationResult>;
|
|
1178
|
+
readonly ruleResult: i0.Signal<ngx_dynamic_entity.RuleEvaluationResult>;
|
|
994
1179
|
/**
|
|
995
1180
|
* Critical fields whose value differs from the session baseline.
|
|
996
1181
|
* These drive the deferred `VALUE_CHANGED` banner — a critical edit is announced once,
|
|
@@ -1432,7 +1617,7 @@ declare class DynamicRecordFormComponent implements OnChanges {
|
|
|
1432
1617
|
* building a row's FormGroup inside the tab view races the tab's own initialisation, so
|
|
1433
1618
|
* the row form is kept detached and only pushed into the FormArray on save.
|
|
1434
1619
|
*/
|
|
1435
|
-
readonly inlineRowField: i0.WritableSignal<
|
|
1620
|
+
readonly inlineRowField: i0.WritableSignal<NestedFieldConfig>;
|
|
1436
1621
|
readonly inlineRowIndex: i0.WritableSignal<number>;
|
|
1437
1622
|
inlineRowForm: FormGroup | null;
|
|
1438
1623
|
/** `array` fields on the tab currently shown, so the template can list their rows. */
|
|
@@ -1667,6 +1852,376 @@ declare class DynamicFieldComponent implements OnChanges, OnDestroy {
|
|
|
1667
1852
|
static ɵcmp: i0.ɵɵComponentDeclaration<DynamicFieldComponent, "ngx-dynamic-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "config": { "alias": "config"; "required": false; }; "currentTabId": { "alias": "currentTabId"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; }, {}, never, never, true, never>;
|
|
1668
1853
|
}
|
|
1669
1854
|
|
|
1855
|
+
/**
|
|
1856
|
+
* sheet-parser.ts — the built-in CSV reader, and the reason it is the only one.
|
|
1857
|
+
*
|
|
1858
|
+
* CSV is what every spreadsheet tool exports and what a text editor can produce, and
|
|
1859
|
+
* `@dynamic-entity/core` parses it with no dependency. Shipping that as the default means the
|
|
1860
|
+
* import wizard works on a fresh `npm install` with nothing registered — `SHEET_PARSER` then
|
|
1861
|
+
* exists for the consumer who *also* wants `.xlsx`, rather than for the consumer who wants
|
|
1862
|
+
* the feature to work at all.
|
|
1863
|
+
*
|
|
1864
|
+
* The alternative was a hard dependency on a spreadsheet library in a package that currently
|
|
1865
|
+
* has none, for a file format many consumers will never see.
|
|
1866
|
+
*/
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* Read a text file as CSV.
|
|
1870
|
+
*
|
|
1871
|
+
* A binary workbook is refused by name rather than attempted: `.xlsx` is a zip, so reading it
|
|
1872
|
+
* as text yields a header row of mojibake and a mapping screen full of nonsense, which is a
|
|
1873
|
+
* much harder thing to diagnose than being told the format is not supported.
|
|
1874
|
+
*/
|
|
1875
|
+
declare const defaultSheetParser: SheetParser;
|
|
1876
|
+
|
|
1877
|
+
declare class LocalImportTransport implements ImportTransport {
|
|
1878
|
+
private readonly registered;
|
|
1879
|
+
/**
|
|
1880
|
+
* One parse per file, not one per call.
|
|
1881
|
+
*
|
|
1882
|
+
* A wizard run reads the same file twice — once to show its headers, once to import it —
|
|
1883
|
+
* and this is the transport whose stated limit is that it holds the file in memory. Doing
|
|
1884
|
+
* the work twice doubled both the parse and the peak memory of the one implementation that
|
|
1885
|
+
* can least afford it.
|
|
1886
|
+
*
|
|
1887
|
+
* A `WeakMap` keyed on the `File` itself: the entry lives exactly as long as something
|
|
1888
|
+
* still holds the file, so choosing a different file drops the old sheet without anything
|
|
1889
|
+
* having to remember to. Keying on a name or a size would collide between two files a user
|
|
1890
|
+
* picked in sequence.
|
|
1891
|
+
*/
|
|
1892
|
+
private readonly parsed;
|
|
1893
|
+
/** The registered parser, or the built-in CSV one. */
|
|
1894
|
+
private read;
|
|
1895
|
+
preview(file: File, context: ImportContext): Promise<ImportPreview>;
|
|
1896
|
+
commit(file: File, plan: MappingPlan, context: ImportContext): Promise<ImportResult>;
|
|
1897
|
+
template(spec: TemplateSpec, format: TemplateFormat): Promise<Blob>;
|
|
1898
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<LocalImportTransport, never>;
|
|
1899
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<LocalImportTransport>;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
/**
|
|
1903
|
+
* http-import-transport.ts — the same wizard, with the work happening on a server.
|
|
1904
|
+
*
|
|
1905
|
+
* The components do not change at all: they already talk to an `ImportTransport`, which was
|
|
1906
|
+
* the point of the seam. Registering this one moves the mapping, coercion and validation from
|
|
1907
|
+
* the tab to a server that runs the *same* `@dynamic-entity/core` functions — so the reason to
|
|
1908
|
+
* do it is size, not behaviour.
|
|
1909
|
+
*
|
|
1910
|
+
* **Built on `fetch`, not `HttpClient`.** This package has no `@angular/common/http` dependency
|
|
1911
|
+
* today, and four requests is not the reason to acquire one — a consumer who wants interceptors
|
|
1912
|
+
* passes their own `fetch`, which is a smaller seam than a dependency.
|
|
1913
|
+
*/
|
|
1914
|
+
|
|
1915
|
+
interface HttpImportTransportOptions {
|
|
1916
|
+
/** Where the router is mounted, e.g. `/api/import`. A trailing slash is ignored. */
|
|
1917
|
+
baseUrl: string;
|
|
1918
|
+
/** Supply one to add interceptors, retries, or credentials. Defaults to the global `fetch`. */
|
|
1919
|
+
fetch?: typeof fetch;
|
|
1920
|
+
/** Headers on every request — an `Authorization`, a tenant id. Never a `Content-Type`. */
|
|
1921
|
+
headers?: Record<string, string> | (() => Record<string, string>);
|
|
1922
|
+
/**
|
|
1923
|
+
* Where a warning goes. Defaults to `console.warn`.
|
|
1924
|
+
*
|
|
1925
|
+
* There is exactly one warning, and it is the engine-version mismatch below — which is a
|
|
1926
|
+
* developer's problem, not a user's, so it does not belong in the wizard's error banner.
|
|
1927
|
+
*/
|
|
1928
|
+
warn?: (message: string) => void;
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* Not `@Injectable`, and registered by value rather than by class.
|
|
1932
|
+
*
|
|
1933
|
+
* Its constructor takes options rather than dependencies, so there is nothing for an injector
|
|
1934
|
+
* to resolve — and a consumer who wants two of them, pointed at two backends, gets that for
|
|
1935
|
+
* free.
|
|
1936
|
+
*/
|
|
1937
|
+
declare class HttpImportTransport implements ImportTransport {
|
|
1938
|
+
private readonly options;
|
|
1939
|
+
constructor(options: HttpImportTransportOptions);
|
|
1940
|
+
private get base();
|
|
1941
|
+
private get send();
|
|
1942
|
+
private entityOf;
|
|
1943
|
+
/**
|
|
1944
|
+
* Warn when the server's engine is not the one this bundle was built against.
|
|
1945
|
+
*
|
|
1946
|
+
* The two halves are separately deployed and may differ. `MappingPlan.configVersion` catches
|
|
1947
|
+
* *config* drift and says nothing about *engine* drift, so "one engine, both sides" is only
|
|
1948
|
+
* true if something checks — and this is the something. A warning rather than a refusal: a
|
|
1949
|
+
* patch release is not a reason to stop somebody importing.
|
|
1950
|
+
*/
|
|
1951
|
+
private checkEngine;
|
|
1952
|
+
preview(file: File, context: ImportContext): Promise<ImportPreview>;
|
|
1953
|
+
commit(file: File, plan: MappingPlan, context: ImportContext): Promise<ImportResult>;
|
|
1954
|
+
template(spec: TemplateSpec, format: TemplateFormat, context: ImportContext, fields?: readonly string[]): Promise<Blob>;
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
* Register the HTTP transport.
|
|
1958
|
+
*
|
|
1959
|
+
* ```ts
|
|
1960
|
+
* provideNgxDynamicEntity({}),
|
|
1961
|
+
* provideHttpImportTransport({ baseUrl: '/api/import' }),
|
|
1962
|
+
* ```
|
|
1963
|
+
*
|
|
1964
|
+
* A plain `Provider` rather than `EnvironmentProviders`, so it composes inside a component's
|
|
1965
|
+
* or a route's `providers` array as well as at the root — which is how a consumer points one
|
|
1966
|
+
* part of an app at a different backend.
|
|
1967
|
+
*/
|
|
1968
|
+
declare function provideHttpImportTransport(options: HttpImportTransportOptions): Provider;
|
|
1969
|
+
|
|
1970
|
+
type Step = 'upload' | 'map' | 'review' | 'done';
|
|
1971
|
+
/**
|
|
1972
|
+
* The import wizard: choose a file, match its columns, look at what that produced, commit.
|
|
1973
|
+
*
|
|
1974
|
+
* It holds no import logic of its own. Everything it does goes through an `ImportTransport`,
|
|
1975
|
+
* which by default is the in-browser one built on `@dynamic-entity/core` — so the wizard
|
|
1976
|
+
* works with no backend, and a consumer who registers a server transport gets the same
|
|
1977
|
+
* screens over the same mapping rules rather than a second implementation of them.
|
|
1978
|
+
*
|
|
1979
|
+
* The review step exists because the expensive mistake here is not a file that fails to
|
|
1980
|
+
* import, it is one that imports *successfully into the wrong fields*. That is invisible in a
|
|
1981
|
+
* summary and obvious in five rendered rows.
|
|
1982
|
+
*/
|
|
1983
|
+
declare class EntityImportComponent {
|
|
1984
|
+
config: EntityFormConfig;
|
|
1985
|
+
/**
|
|
1986
|
+
* The rules the form is rendered with.
|
|
1987
|
+
*
|
|
1988
|
+
* Pass them, or the import checks field validators only — which is not what the form
|
|
1989
|
+
* enforces, and a required field hidden by a rule will fail every row.
|
|
1990
|
+
*/
|
|
1991
|
+
rules?: readonly FormRule[];
|
|
1992
|
+
/**
|
|
1993
|
+
* Named lists, overriding what the wizard already resolves from `LOOKUP_REGISTRY`.
|
|
1994
|
+
*
|
|
1995
|
+
* Not something a host has to supply: every `listName` a config mentions is loaded from the
|
|
1996
|
+
* registry the renderer is already holding. Pass this only to override one.
|
|
1997
|
+
*/
|
|
1998
|
+
lookups?: ImportLookups;
|
|
1999
|
+
language: string;
|
|
2000
|
+
/** Format asked of the transport when a template is downloaded. */
|
|
2001
|
+
templateFormat: TemplateFormat;
|
|
2002
|
+
/** The finished import, once it has run. */
|
|
2003
|
+
readonly importComplete: EventEmitter<ImportResult>;
|
|
2004
|
+
/** A template the transport produced, for a host that would rather save it its own way. */
|
|
2005
|
+
readonly templateReady: EventEmitter<Blob>;
|
|
2006
|
+
protected readonly ui: UiTextService;
|
|
2007
|
+
protected readonly steps: Step[];
|
|
2008
|
+
protected readonly step: i0.WritableSignal<Step>;
|
|
2009
|
+
protected readonly busy: i0.WritableSignal<boolean>;
|
|
2010
|
+
protected readonly problem: i0.WritableSignal<string>;
|
|
2011
|
+
protected readonly headers: i0.WritableSignal<string[]>;
|
|
2012
|
+
protected readonly sample: i0.WritableSignal<string[][]>;
|
|
2013
|
+
protected readonly rowCount: i0.WritableSignal<number>;
|
|
2014
|
+
protected readonly fileName: i0.WritableSignal<string>;
|
|
2015
|
+
protected readonly plan: i0.WritableSignal<MappingPlan>;
|
|
2016
|
+
protected readonly result: i0.WritableSignal<ImportResult>;
|
|
2017
|
+
private readonly registered;
|
|
2018
|
+
private readonly local;
|
|
2019
|
+
private readonly lookupRegistry;
|
|
2020
|
+
private file;
|
|
2021
|
+
/** Named lists resolved from `LOOKUP_REGISTRY`, merged under the `lookups` input. */
|
|
2022
|
+
protected readonly resolvedLookups: i0.WritableSignal<ImportLookups>;
|
|
2023
|
+
private get transport();
|
|
2024
|
+
private context;
|
|
2025
|
+
/**
|
|
2026
|
+
* Load every named list this config's fields refer to.
|
|
2027
|
+
*
|
|
2028
|
+
* `@dynamic-entity/core` is framework-agnostic and cannot reach `LOOKUP_REGISTRY`, so
|
|
2029
|
+
* `coerceCell` takes the values as an argument. That is a reason for *core* to ask, not a
|
|
2030
|
+
* reason for the host to be asked — this package is holding the registry, and making the
|
|
2031
|
+
* consumer re-supply what the library already has is how a `listName` column ends up
|
|
2032
|
+
* storing the raw text `"Gold"` instead of the option object. Such a record renders
|
|
2033
|
+
* correctly and then matches no rule, which is the exact failure the option-shape contract
|
|
2034
|
+
* exists to prevent.
|
|
2035
|
+
*
|
|
2036
|
+
* The `lookups` input still wins where it names a list, so a host can override one without
|
|
2037
|
+
* having to provide all of them.
|
|
2038
|
+
*/
|
|
2039
|
+
private loadLookups;
|
|
2040
|
+
protected stepLabel(step: Step): string;
|
|
2041
|
+
protected chooseFile(event: Event): Promise<void>;
|
|
2042
|
+
protected commit(): Promise<void>;
|
|
2043
|
+
protected downloadTemplate(fields: string[]): Promise<void>;
|
|
2044
|
+
/**
|
|
2045
|
+
* How many records were written.
|
|
2046
|
+
*
|
|
2047
|
+
* `records.length` for the in-browser transport, which returns every record it built, and
|
|
2048
|
+
* `imported` for a server one, which streamed the file precisely so that fifty thousand
|
|
2049
|
+
* records never had to exist at once and therefore has a number rather than a list. Reading
|
|
2050
|
+
* `records.length` alone would report a successful import of nothing.
|
|
2051
|
+
*/
|
|
2052
|
+
protected importedCount(result: ImportResult): number;
|
|
2053
|
+
/**
|
|
2054
|
+
* How many distinct rows failed, not how many problems they had between them.
|
|
2055
|
+
*
|
|
2056
|
+
* `failed` when the transport reports it, and the distinct rows in `errors` only when it does
|
|
2057
|
+
* not. Counting the errors alone was wrong the moment a transport started capping them: a run
|
|
2058
|
+
* of a thousand rows where two hundred failed said **seven**, because seven was how many
|
|
2059
|
+
* distinct rows fitted inside the first twenty retained problems. This is the number a user
|
|
2060
|
+
* acts on — which rows do I go and fix — so a confident wrong answer is the worst of the
|
|
2061
|
+
* available ones. The in-browser transport returns every error, so counting them there is
|
|
2062
|
+
* exact and `failed` is absent.
|
|
2063
|
+
*/
|
|
2064
|
+
protected failedRowCount(result: ImportResult): number;
|
|
2065
|
+
protected restart(): void;
|
|
2066
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EntityImportComponent, never>;
|
|
2067
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<EntityImportComponent, "ngx-entity-import", never, { "config": { "alias": "config"; "required": true; }; "rules": { "alias": "rules"; "required": false; }; "lookups": { "alias": "lookups"; "required": false; }; "language": { "alias": "language"; "required": false; }; "templateFormat": { "alias": "templateFormat"; "required": false; }; }, { "importComplete": "importComplete"; "templateReady": "templateReady"; }, never, never, true, never>;
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
/** One target field, and which of the sheet's columns feeds it. */
|
|
2071
|
+
interface MappingRow {
|
|
2072
|
+
column: ImportColumn;
|
|
2073
|
+
/** Index into the sheet's headers, or `null` for "not imported". */
|
|
2074
|
+
source: number | null;
|
|
2075
|
+
guessed: boolean;
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Match the sheet's columns to the config's fields.
|
|
2079
|
+
*
|
|
2080
|
+
* The table is driven by the **target fields**, not by the sheet's columns, which is the
|
|
2081
|
+
* choice that decides how the screen reads. A user is answering "where does Start Date come
|
|
2082
|
+
* from?", which they can do; column-first would ask "what is column G?", which they often
|
|
2083
|
+
* cannot, and would make a sheet with forty irrelevant columns forty questions long.
|
|
2084
|
+
*
|
|
2085
|
+
* A selection is a **column index**, never header text. Two columns headed "Notes" are two
|
|
2086
|
+
* different answers, and text cannot tell them apart.
|
|
2087
|
+
*/
|
|
2088
|
+
declare class ImportMapperComponent implements OnChanges {
|
|
2089
|
+
config: EntityFormConfig;
|
|
2090
|
+
headers: readonly string[];
|
|
2091
|
+
/** The starting point, normally `suggestMapping`'s output. */
|
|
2092
|
+
plan: MappingPlan | null;
|
|
2093
|
+
language: string;
|
|
2094
|
+
/** Emitted whenever the user changes a selection. */
|
|
2095
|
+
readonly planChange: EventEmitter<MappingPlan>;
|
|
2096
|
+
protected readonly ui: UiTextService;
|
|
2097
|
+
protected readonly rows: i0.WritableSignal<MappingRow[]>;
|
|
2098
|
+
/**
|
|
2099
|
+
* How many fields a spreadsheet cannot carry at all.
|
|
2100
|
+
*
|
|
2101
|
+
* Shown here as well as in the template picker, because a user who already had a sheet
|
|
2102
|
+
* skipped that screen — and this is the only place they would otherwise find out that an
|
|
2103
|
+
* attachment column was never going to arrive.
|
|
2104
|
+
*/
|
|
2105
|
+
protected readonly unsupported: i0.WritableSignal<number>;
|
|
2106
|
+
ngOnChanges(): void;
|
|
2107
|
+
protected mappedCount(): number;
|
|
2108
|
+
protected missingRequired(): number;
|
|
2109
|
+
protected choose(row: MappingRow, source: number | null): void;
|
|
2110
|
+
/** The current selections as the plan that will be applied. */
|
|
2111
|
+
private toPlan;
|
|
2112
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ImportMapperComponent, never>;
|
|
2113
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ImportMapperComponent, "ngx-import-mapper", never, { "config": { "alias": "config"; "required": true; }; "headers": { "alias": "headers"; "required": false; }; "plan": { "alias": "plan"; "required": false; }; "language": { "alias": "language"; "required": false; }; }, { "planChange": "planChange"; }, never, never, true, never>;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
/** One cell, already turned into the text the record will show. */
|
|
2117
|
+
interface PreviewCell {
|
|
2118
|
+
text: string;
|
|
2119
|
+
failed: boolean;
|
|
2120
|
+
}
|
|
2121
|
+
/** A row of cells, plus why the import will refuse it — if it will. */
|
|
2122
|
+
interface PreviewRow {
|
|
2123
|
+
cells: PreviewCell[];
|
|
2124
|
+
/** Empty when the row will be imported. */
|
|
2125
|
+
rejections: string[];
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* The first few rows as the record will hold them, not as the sheet holds them.
|
|
2129
|
+
*
|
|
2130
|
+
* Every cell goes through the same `coerceCell` the import will use and then through
|
|
2131
|
+
* `formatDisplayValue`, which is what the renderer uses to show a stored value. So a
|
|
2132
|
+
* `dropdown` cell reading `Aktiv` shows as `Active` here if that is the option it resolved
|
|
2133
|
+
* to, and a cell that will fail shows its reason before anyone commits to anything.
|
|
2134
|
+
*
|
|
2135
|
+
* Showing the raw text instead would be easier and would preview the wrong thing: the point
|
|
2136
|
+
* of this screen is to catch a mapping that is subtly wrong, and a column of unchanged text
|
|
2137
|
+
* looks correct whatever field it was pointed at.
|
|
2138
|
+
*
|
|
2139
|
+
* **The rows are also run through the real import**, not just through coercion. `coerceCell`
|
|
2140
|
+
* alone catches a cell that will not parse and says nothing about a row that will be rejected
|
|
2141
|
+
* — a missing required field, a rule that forbids the combination — so a heading promising
|
|
2142
|
+
* "as they will be saved" was showing rows that would never be saved at all, looking exactly
|
|
2143
|
+
* like the ones that would. `applyMapping` over the sample answers that with the same engine
|
|
2144
|
+
* the commit uses, rather than a second opinion about what counts as valid.
|
|
2145
|
+
*
|
|
2146
|
+
* The whole grid is built once per input change rather than from template method calls.
|
|
2147
|
+
* Deriving the config's columns inside a `@for` means re-walking the entire schema for every
|
|
2148
|
+
* cell on every change-detection pass, which is a lot of work to produce five rows.
|
|
2149
|
+
*/
|
|
2150
|
+
declare class ImportPreviewComponent implements OnChanges {
|
|
2151
|
+
config: EntityFormConfig;
|
|
2152
|
+
plan: MappingPlan;
|
|
2153
|
+
rows: readonly (readonly string[])[];
|
|
2154
|
+
lookups?: ImportLookups;
|
|
2155
|
+
/** The same rules the commit will apply; without them a rule-driven rejection is invisible. */
|
|
2156
|
+
rules?: readonly FormRule[];
|
|
2157
|
+
language: string;
|
|
2158
|
+
protected readonly ui: UiTextService;
|
|
2159
|
+
/** The columns this plan fills, in the plan's own order. */
|
|
2160
|
+
protected readonly columns: i0.WritableSignal<ImportColumn[]>;
|
|
2161
|
+
protected readonly grid: i0.WritableSignal<PreviewRow[]>;
|
|
2162
|
+
ngOnChanges(): void;
|
|
2163
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ImportPreviewComponent, never>;
|
|
2164
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ImportPreviewComponent, "ngx-import-preview", never, { "config": { "alias": "config"; "required": true; }; "plan": { "alias": "plan"; "required": true; }; "rows": { "alias": "rows"; "required": false; }; "lookups": { "alias": "lookups"; "required": false; }; "rules": { "alias": "rules"; "required": false; }; "language": { "alias": "language"; "required": false; }; }, {}, never, never, true, never>;
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
/** One field offered for the template, with the guidance that belongs to it. */
|
|
2168
|
+
interface TemplateChoice {
|
|
2169
|
+
/** The ref with any row number removed, so a repeating field is offered once. */
|
|
2170
|
+
ref: string;
|
|
2171
|
+
header: string;
|
|
2172
|
+
note: string;
|
|
2173
|
+
selected: boolean;
|
|
2174
|
+
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Pick the fields a template should carry, then download it.
|
|
2177
|
+
*
|
|
2178
|
+
* The guidance for each field is shown **here**, beside the checkbox, rather than written
|
|
2179
|
+
* into the file as a second header row. CSV has one header row and no concept of a second,
|
|
2180
|
+
* so a guidance row inside the file would come back as a record on re-import and fail row 2
|
|
2181
|
+
* of every import the user ever ran.
|
|
2182
|
+
*
|
|
2183
|
+
* A repeating field is offered once, not once per row number: "Contacts / Name" is a decision,
|
|
2184
|
+
* and "Contacts / Name 1", "Contacts / Name 2", "Contacts / Name 3" is the same decision
|
|
2185
|
+
* asked three times.
|
|
2186
|
+
*/
|
|
2187
|
+
declare class ImportTemplateComponent implements OnChanges {
|
|
2188
|
+
config: EntityFormConfig;
|
|
2189
|
+
language: string;
|
|
2190
|
+
/** The refs to include, with row numbers stripped — the caller builds the spec. */
|
|
2191
|
+
readonly download: EventEmitter<string[]>;
|
|
2192
|
+
protected readonly ui: UiTextService;
|
|
2193
|
+
protected readonly choices: i0.WritableSignal<TemplateChoice[]>;
|
|
2194
|
+
protected readonly unsupported: i0.WritableSignal<UnsupportedColumn[]>;
|
|
2195
|
+
ngOnChanges(): void;
|
|
2196
|
+
protected selectedCount(): number;
|
|
2197
|
+
protected selectedRefs(): string[];
|
|
2198
|
+
protected toggle(ref: string): void;
|
|
2199
|
+
protected selectAll(selected: boolean): void;
|
|
2200
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ImportTemplateComponent, never>;
|
|
2201
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ImportTemplateComponent, "ngx-import-template", never, { "config": { "alias": "config"; "required": true; }; "language": { "alias": "language"; "required": false; }; }, { "download": "download"; }, never, never, true, never>;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
/**
|
|
2205
|
+
* The rows an import could not take, and why.
|
|
2206
|
+
*
|
|
2207
|
+
* Grouped by row rather than listed flat: a row with four problems is one row to go and fix,
|
|
2208
|
+
* and four separate lines invite the reader to think there are four. The row number is the
|
|
2209
|
+
* one the spreadsheet shows in its gutter — header counted as row 1 — because that is the
|
|
2210
|
+
* number they will scroll to.
|
|
2211
|
+
*/
|
|
2212
|
+
declare class ImportErrorsComponent {
|
|
2213
|
+
errors: readonly ImportRowError[];
|
|
2214
|
+
language: string;
|
|
2215
|
+
protected readonly ui: UiTextService;
|
|
2216
|
+
/** Row number → its problems, in the order the rows appear in the file. */
|
|
2217
|
+
protected grouped(): {
|
|
2218
|
+
row: number;
|
|
2219
|
+
problems: ImportRowError[];
|
|
2220
|
+
}[];
|
|
2221
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<ImportErrorsComponent, never>;
|
|
2222
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<ImportErrorsComponent, "ngx-import-errors", never, { "errors": { "alias": "errors"; "required": false; }; "language": { "alias": "language"; "required": false; }; }, {}, never, never, true, never>;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
1670
2225
|
/**
|
|
1671
2226
|
* What a field component must accept to be registered with `provideFieldTypes`.
|
|
1672
2227
|
*
|
|
@@ -2312,7 +2867,7 @@ declare class DropdownFieldComponent {
|
|
|
2312
2867
|
readonly: boolean;
|
|
2313
2868
|
masked: boolean;
|
|
2314
2869
|
/** Inline `options`, or the field's named list resolved through the registry (§6.3). */
|
|
2315
|
-
readonly options: i0.WritableSignal<
|
|
2870
|
+
readonly options: i0.WritableSignal<ngx_dynamic_entity.LocalizedText[]>;
|
|
2316
2871
|
readonly compareFn: (o1: unknown, o2: unknown) => boolean;
|
|
2317
2872
|
isObjectVal(option: DropdownOption): boolean;
|
|
2318
2873
|
get label(): string;
|
|
@@ -2357,7 +2912,7 @@ declare class RadioFieldComponent {
|
|
|
2357
2912
|
readonly: boolean;
|
|
2358
2913
|
masked: boolean;
|
|
2359
2914
|
/** Inline `options`, or the field's named list resolved through the registry (§6.3). */
|
|
2360
|
-
readonly options: i0.WritableSignal<
|
|
2915
|
+
readonly options: i0.WritableSignal<ngx_dynamic_entity.LocalizedText[]>;
|
|
2361
2916
|
get label(): string;
|
|
2362
2917
|
getOptStoredVal(option: DropdownOption): unknown;
|
|
2363
2918
|
/**
|
|
@@ -2415,7 +2970,7 @@ declare class MultiSelectFieldComponent {
|
|
|
2415
2970
|
readonly: boolean;
|
|
2416
2971
|
masked: boolean;
|
|
2417
2972
|
/** Inline `options`, or the field's named list resolved through the registry (§6.3). */
|
|
2418
|
-
readonly options: i0.WritableSignal<
|
|
2973
|
+
readonly options: i0.WritableSignal<ngx_dynamic_entity.LocalizedText[]>;
|
|
2419
2974
|
readonly compareFn: (o1: unknown, o2: unknown) => boolean;
|
|
2420
2975
|
isObjectVal(option: DropdownOption): boolean;
|
|
2421
2976
|
get label(): string;
|
|
@@ -2641,5 +3196,5 @@ declare class FileFieldComponent {
|
|
|
2641
3196
|
static ɵcmp: i0.ɵɵComponentDeclaration<FileFieldComponent, "ngx-file-field", never, { "field": { "alias": "field"; "required": false; }; "control": { "alias": "control"; "required": false; }; "language": { "alias": "language"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "masked": { "alias": "masked"; "required": false; }; }, {}, never, never, true, never>;
|
|
2642
3197
|
}
|
|
2643
3198
|
|
|
2644
|
-
export { ASYNC_VALIDATOR_REGISTRY, ArrayFieldComponent, BooleanFieldComponent, COMMON_MODULES_REGISTRY, CONFIG_SOURCE, CascadeDataService, CheckboxFieldComponent, ConfigSourceService, CurrencyFieldComponent, DEFAULT_UI_TEXT, DEFAULT_VALIDATION_MESSAGES, DateFieldComponent, DateTimeFieldComponent, DropdownFieldComponent, DynamicFieldComponent, DynamicFormComponent, DynamicRecordFormComponent, ENTITY_REF_CACHE_STORE, ENTITY_REF_REGISTRY, EmailFieldComponent, EntityRefFieldComponent, EntityRefRegistryService, EntityRefSelectionService, EntityReferenceService, FIELD_TYPE_REGISTRY, FIELD_TYPE_SETS, FieldRegistryService, FileFieldComponent, GroupFieldComponent, HOOK_REGISTRY, HookRegistryService, ImageFieldComponent, InMemoryEntityRefCacheStore, LOOKUP_REGISTRY, LookupRegistryService, MARKDOWN_RENDERER, MASKED_PLACEHOLDER, MASKED_ROLES, MarkdownFieldComponent, MonthYearFieldComponent, MultiSelectFieldComponent, NumberFieldComponent, PasswordFieldComponent, RECORD_MIGRATIONS, RadioFieldComponent, RbacService, RulesEvaluationService, SYSTEM_DEFAULT_CAN_EDIT, TextFieldComponent, TextareaFieldComponent, TimeFieldComponent, UI_TEXT, UPLOAD_HANDLER, UiTextService, VALIDATION_MESSAGES, VALIDATOR_REGISTRY, ValidationMessagesService, ValidatorRegistryService, builtInFieldTypes, fieldDescribedBy, fieldDomId, nextFieldInstanceId, provideBuiltInFieldTypes, provideFieldTypes, provideNgxDynamicEntity, refreshChoiceOptions, resolveUiText };
|
|
2645
|
-
export type { ChoiceOptionHost, ConfigSourceHandler, DynamicFieldComponentContract, EntityRefCacheStore, EntityRefSelection, HookFn, InvalidField, MessageOrderEntry, NgxDynamicEntityConfig, UiTextKey, UiTextOverrides, UiTextOverridesFor, UiTextParams, UiTextResolver, UiTextResolverFor, UiTextValue, ValidationMessage };
|
|
3199
|
+
export { ASYNC_VALIDATOR_REGISTRY, ArrayFieldComponent, BooleanFieldComponent, COMMON_MODULES_REGISTRY, CONFIG_SOURCE, CascadeDataService, CheckboxFieldComponent, ConfigSourceService, CurrencyFieldComponent, DEFAULT_UI_TEXT, DEFAULT_VALIDATION_MESSAGES, DateFieldComponent, DateTimeFieldComponent, DropdownFieldComponent, DynamicFieldComponent, DynamicFormComponent, DynamicRecordFormComponent, ENTITY_REF_CACHE_STORE, ENTITY_REF_REGISTRY, EmailFieldComponent, EntityImportComponent, EntityRefFieldComponent, EntityRefRegistryService, EntityRefSelectionService, EntityReferenceService, FIELD_TYPE_REGISTRY, FIELD_TYPE_SETS, FieldRegistryService, FileFieldComponent, GroupFieldComponent, HOOK_REGISTRY, HookRegistryService, HttpImportTransport, IMPORT_TRANSPORT, ImageFieldComponent, ImportErrorsComponent, ImportMapperComponent, ImportPreviewComponent, ImportTemplateComponent, InMemoryEntityRefCacheStore, LOOKUP_REGISTRY, LocalImportTransport, LookupRegistryService, MARKDOWN_RENDERER, MASKED_PLACEHOLDER, MASKED_ROLES, MarkdownFieldComponent, MonthYearFieldComponent, MultiSelectFieldComponent, NumberFieldComponent, PasswordFieldComponent, RECORD_MIGRATIONS, RadioFieldComponent, RbacService, RulesEvaluationService, SHEET_PARSER, SYSTEM_DEFAULT_CAN_EDIT, TextFieldComponent, TextareaFieldComponent, TimeFieldComponent, UI_TEXT, UPLOAD_HANDLER, UiTextService, VALIDATION_MESSAGES, VALIDATOR_REGISTRY, ValidationMessagesService, ValidatorRegistryService, builtInFieldTypes, defaultSheetParser, fieldDescribedBy, fieldDomId, nextFieldInstanceId, provideBuiltInFieldTypes, provideFieldTypes, provideHttpImportTransport, provideNgxDynamicEntity, refreshChoiceOptions, resolveUiText };
|
|
3200
|
+
export type { ChoiceOptionHost, ConfigSourceHandler, DynamicFieldComponentContract, EntityRefCacheStore, EntityRefSelection, HookFn, HttpImportTransportOptions, ImportContext, ImportPreview, ImportTransport, InvalidField, MessageOrderEntry, NgxDynamicEntityConfig, SheetParser, TemplateFormat, UiTextKey, UiTextOverrides, UiTextOverridesFor, UiTextParams, UiTextResolver, UiTextResolverFor, UiTextValue, ValidationMessage };
|