@forgeroute/ui 0.4.41 → 0.4.42

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.
@@ -9381,6 +9381,9 @@ var ImportExportComponent = class ImportExportComponent {
9381
9381
  this.importSources = input(void 0, ...ngDevMode ? [{ debugName: "importSources" }] : /* istanbul ignore next */ []);
9382
9382
  this.exportParams = input({}, ...ngDevMode ? [{ debugName: "exportParams" }] : /* istanbul ignore next */ []);
9383
9383
  this.exportOnly = input(false, ...ngDevMode ? [{ debugName: "exportOnly" }] : /* istanbul ignore next */ []);
9384
+ this.closeOnly = input(false, ...ngDevMode ? [{ debugName: "closeOnly" }] : /* istanbul ignore next */ []);
9385
+ this.submit = input(null, ...ngDevMode ? [{ debugName: "submit" }] : /* istanbul ignore next */ []);
9386
+ this.finished = output();
9384
9387
  this.imported = output();
9385
9388
  this.http = inject(HttpClient);
9386
9389
  this.apiBase = inject(FORGEROUTE_CONFIG, { optional: true })?.baseUrl ?? "/api";
@@ -9400,6 +9403,7 @@ var ImportExportComponent = class ImportExportComponent {
9400
9403
  this.mappingError = null;
9401
9404
  this.importing = false;
9402
9405
  this.importResult = null;
9406
+ this.csvFile = null;
9403
9407
  this.destroyRef.onDestroy(() => this.stopImportTimer());
9404
9408
  effect(() => {
9405
9409
  const v = this._configInput();
@@ -9466,6 +9470,7 @@ var ImportExportComponent = class ImportExportComponent {
9466
9470
  this.selectedSource = "";
9467
9471
  this.csvHeaders = [];
9468
9472
  this.csvRows = [];
9473
+ this.csvFile = null;
9469
9474
  this.fileError = null;
9470
9475
  this.columnMapping = {};
9471
9476
  this.mappingError = null;
@@ -9492,6 +9497,7 @@ var ImportExportComponent = class ImportExportComponent {
9492
9497
  }
9493
9498
  finishImport() {
9494
9499
  this.importOpen = false;
9500
+ if (this.importResult) this.finished.emit(this.importResult);
9495
9501
  this.imported.emit();
9496
9502
  }
9497
9503
  onFileChange(event) {
@@ -9500,6 +9506,7 @@ var ImportExportComponent = class ImportExportComponent {
9500
9506
  this.readCsvFile(file);
9501
9507
  }
9502
9508
  readCsvFile(file, encoding) {
9509
+ this.csvFile = file;
9503
9510
  const reader = new FileReader();
9504
9511
  reader.onload = (e) => {
9505
9512
  const raw = e.target.result;
@@ -9641,7 +9648,12 @@ var ImportExportComponent = class ImportExportComponent {
9641
9648
  }
9642
9649
  return record;
9643
9650
  });
9644
- this.http.post(`${this.apiBase}${this.config.importEndpoint ?? ""}`, { records }).subscribe({
9651
+ const custom = this.submit();
9652
+ (custom ? custom({
9653
+ file: this.csvFile,
9654
+ records,
9655
+ mapping: { ...this.columnMapping }
9656
+ }) : this.http.post(`${this.apiBase}${this.config.importEndpoint ?? ""}`, { records })).subscribe({
9645
9657
  next: (result) => {
9646
9658
  this.stopImportTimer();
9647
9659
  this.importing = false;
@@ -9654,10 +9666,21 @@ var ImportExportComponent = class ImportExportComponent {
9654
9666
  if (result.imported > 0) this.toast.show(`${result.imported} ${this.config.entityNamePlural.toLowerCase()} imported successfully`);
9655
9667
  this.cdr.detectChanges();
9656
9668
  },
9657
- error: () => {
9669
+ error: (err) => {
9658
9670
  this.stopImportTimer();
9659
9671
  this.importing = false;
9660
- this.toast.error("Import failed. Please check your data and try again.");
9672
+ if (custom && Array.isArray(err?.error?.errors)) {
9673
+ this.importResult = {
9674
+ imported: err.error.successCount ?? 0,
9675
+ errors: err.error.errors,
9676
+ warnings: []
9677
+ };
9678
+ this.step = "result";
9679
+ this.cdr.detectChanges();
9680
+ return;
9681
+ }
9682
+ const serverMessage = custom && typeof err?.error?.message === "string" ? err.error.message : "";
9683
+ this.toast.error(serverMessage || "Import failed. Please check your data and try again.");
9661
9684
  this.cdr.detectChanges();
9662
9685
  }
9663
9686
  });
@@ -9707,9 +9730,26 @@ var ImportExportComponent = class ImportExportComponent {
9707
9730
  isSignal: true,
9708
9731
  isRequired: false,
9709
9732
  transformFunction: null
9733
+ },
9734
+ closeOnly: {
9735
+ classPropertyName: "closeOnly",
9736
+ publicName: "closeOnly",
9737
+ isSignal: true,
9738
+ isRequired: false,
9739
+ transformFunction: null
9740
+ },
9741
+ submit: {
9742
+ classPropertyName: "submit",
9743
+ publicName: "submit",
9744
+ isSignal: true,
9745
+ isRequired: false,
9746
+ transformFunction: null
9710
9747
  }
9711
9748
  },
9712
- outputs: { imported: "imported" },
9749
+ outputs: {
9750
+ finished: "finished",
9751
+ imported: "imported"
9752
+ },
9713
9753
  ngImport: i0,
9714
9754
  template: `
9715
9755
  <!-- Trigger buttons -->
@@ -9768,7 +9808,7 @@ var ImportExportComponent = class ImportExportComponent {
9768
9808
  <div class="ie-template-hint">
9769
9809
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
9770
9810
  Start with our CSV template to ensure correct column names.
9771
- <ui-button variant="ghost" size="sm" (click)="downloadTemplate()">Download template</ui-button>
9811
+ <ui-button variant="ghost" size="sm" data-testid="import-template-button" (click)="downloadTemplate()">{{ config.templateLabel || 'Download template' }}</ui-button>
9772
9812
  </div>
9773
9813
  <label class="ie-dropzone" [class.has-error]="!!fileError">
9774
9814
  <input type="file" class="ie-file-hidden" accept=".csv,text/csv" aria-label="Choose CSV file to import" (change)="onFileChange($event)" />
@@ -9901,6 +9941,21 @@ var ImportExportComponent = class ImportExportComponent {
9901
9941
  }
9902
9942
 
9903
9943
  <!-- Footer -->
9944
+ @if (closeOnly()) {
9945
+ <!-- no Back: one Close that shuts the window at once (the setup wizard) -->
9946
+ @if (step !== 'result') {
9947
+ <ui-button modal-footer-left variant="secondary" size="sm" data-testid="import-close-button" [disabled]="importing" (click)="closeImport()">Close</ui-button>
9948
+ }
9949
+ @if (step === 'source') {
9950
+ <ui-button modal-footer-right variant="primary" size="sm" [disabled]="!selectedSource" (click)="confirmSource()">Next</ui-button>
9951
+ }
9952
+ @if (step === 'mapping') {
9953
+ <ui-button modal-footer-right variant="primary" size="sm" [disabled]="!canSubmit" (click)="goToPreview()">Preview Import</ui-button>
9954
+ }
9955
+ @if (step === 'preview') {
9956
+ <ui-button modal-footer-right variant="primary" size="sm" [loading]="importing" (click)="submitImport()">Import {{ csvRows.length }} Record(s)</ui-button>
9957
+ }
9958
+ } @else {
9904
9959
  @if (step === 'source') {
9905
9960
  <ui-button modal-footer-left variant="secondary" size="sm" (click)="closeImport()">Cancel</ui-button>
9906
9961
  }
@@ -9937,6 +9992,7 @@ var ImportExportComponent = class ImportExportComponent {
9937
9992
  <ui-button variant="primary" size="sm" [loading]="importing" (click)="submitImport()">Import {{ csvRows.length }} Record(s)</ui-button>
9938
9993
  </div>
9939
9994
  }
9995
+ }
9940
9996
  @if (step === 'result') {
9941
9997
  <span modal-footer-left></span>
9942
9998
  }
@@ -10131,7 +10187,7 @@ i0.ɵɵngDeclareClassMetadata({
10131
10187
  <div class="ie-template-hint">
10132
10188
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
10133
10189
  Start with our CSV template to ensure correct column names.
10134
- <ui-button variant="ghost" size="sm" (click)="downloadTemplate()">Download template</ui-button>
10190
+ <ui-button variant="ghost" size="sm" data-testid="import-template-button" (click)="downloadTemplate()">{{ config.templateLabel || 'Download template' }}</ui-button>
10135
10191
  </div>
10136
10192
  <label class="ie-dropzone" [class.has-error]="!!fileError">
10137
10193
  <input type="file" class="ie-file-hidden" accept=".csv,text/csv" aria-label="Choose CSV file to import" (change)="onFileChange($event)" />
@@ -10264,6 +10320,21 @@ i0.ɵɵngDeclareClassMetadata({
10264
10320
  }
10265
10321
 
10266
10322
  <!-- Footer -->
10323
+ @if (closeOnly()) {
10324
+ <!-- no Back: one Close that shuts the window at once (the setup wizard) -->
10325
+ @if (step !== 'result') {
10326
+ <ui-button modal-footer-left variant="secondary" size="sm" data-testid="import-close-button" [disabled]="importing" (click)="closeImport()">Close</ui-button>
10327
+ }
10328
+ @if (step === 'source') {
10329
+ <ui-button modal-footer-right variant="primary" size="sm" [disabled]="!selectedSource" (click)="confirmSource()">Next</ui-button>
10330
+ }
10331
+ @if (step === 'mapping') {
10332
+ <ui-button modal-footer-right variant="primary" size="sm" [disabled]="!canSubmit" (click)="goToPreview()">Preview Import</ui-button>
10333
+ }
10334
+ @if (step === 'preview') {
10335
+ <ui-button modal-footer-right variant="primary" size="sm" [loading]="importing" (click)="submitImport()">Import {{ csvRows.length }} Record(s)</ui-button>
10336
+ }
10337
+ } @else {
10267
10338
  @if (step === 'source') {
10268
10339
  <ui-button modal-footer-left variant="secondary" size="sm" (click)="closeImport()">Cancel</ui-button>
10269
10340
  }
@@ -10300,6 +10371,7 @@ i0.ɵɵngDeclareClassMetadata({
10300
10371
  <ui-button variant="primary" size="sm" [loading]="importing" (click)="submitImport()">Import {{ csvRows.length }} Record(s)</ui-button>
10301
10372
  </div>
10302
10373
  }
10374
+ }
10303
10375
  @if (step === 'result') {
10304
10376
  <span modal-footer-left></span>
10305
10377
  }
@@ -10346,6 +10418,26 @@ i0.ɵɵngDeclareClassMetadata({
10346
10418
  required: false
10347
10419
  }]
10348
10420
  }],
10421
+ closeOnly: [{
10422
+ type: i0.Input,
10423
+ args: [{
10424
+ isSignal: true,
10425
+ alias: "closeOnly",
10426
+ required: false
10427
+ }]
10428
+ }],
10429
+ submit: [{
10430
+ type: i0.Input,
10431
+ args: [{
10432
+ isSignal: true,
10433
+ alias: "submit",
10434
+ required: false
10435
+ }]
10436
+ }],
10437
+ finished: [{
10438
+ type: i0.Output,
10439
+ args: ["finished"]
10440
+ }],
10349
10441
  imported: [{
10350
10442
  type: i0.Output,
10351
10443
  args: ["imported"]
@@ -13650,9 +13742,11 @@ var DataTableComponent = class DataTableComponent {
13650
13742
  "config",
13651
13743
  "importSources",
13652
13744
  "exportParams",
13653
- "exportOnly"
13745
+ "exportOnly",
13746
+ "closeOnly",
13747
+ "submit"
13654
13748
  ],
13655
- outputs: ["imported"]
13749
+ outputs: ["finished", "imported"]
13656
13750
  },
13657
13751
  {
13658
13752
  kind: "component",
@@ -43299,7 +43393,6 @@ const DEFAULT_TEXTS = {
43299
43393
  selectSource: "Select",
43300
43394
  connected: "Connected",
43301
43395
  importMore: "Import more",
43302
- downloadSample: "Download CSV Template",
43303
43396
  importRequired: "Import your data to continue, or skip this step.",
43304
43397
  importErrorsTitle: (errors) => `${errors} row${errors === 1 ? "" : "s"} could not be imported`,
43305
43398
  importErrorsText: (_imported, errors) => `Nothing was imported yet. Fix the ${errors === 1 ? "row" : "rows"} listed in the import window in your file, then import the whole file again to continue.`,
@@ -43523,9 +43616,6 @@ var SetupWizardComponent = class SetupWizardComponent {
43523
43616
  importer.onSourceSelected(source);
43524
43617
  importer.confirmSource();
43525
43618
  }
43526
- downloadSample() {
43527
- this.importers()[0]?.downloadTemplate();
43528
- }
43529
43619
  openImport(key) {
43530
43620
  if (this.steps().findIndex((s) => s.key === key) < 0) return;
43531
43621
  this.importers()[0]?.openImport();
@@ -43870,16 +43960,13 @@ var SetupWizardComponent = class SetupWizardComponent {
43870
43960
  </ui-alert>
43871
43961
  } @else {
43872
43962
  @if (imp.hint) { <p class="sw-hint">{{ imp.hint }}</p> }
43873
- @if (imp.config.importFields?.length) {
43874
- <ui-button variant="link" [attr.data-testid]="'download-sample-' + current().key" (click)="downloadSample()">{{ imp.templateLabel || t().downloadSample }}</ui-button>
43875
- }
43876
43963
  @if (imp.sources?.length) {
43877
43964
  <ui-import-source-grid appearance="card" [disabled]="busy()" [actionLabel]="t().selectSource" [sources]="imp.sources!" [ariaLabel]="'Select your ' + imp.config.entityName + ' source'" (sourceSelect)="startImport(current().key, $event)" />
43878
43965
  } @else {
43879
43966
  <ui-button variant="primary" size="sm" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ imp.buttonLabel }}</ui-button>
43880
43967
  }
43881
43968
  }
43882
- <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" (imported)="onImported(current().key)" />
43969
+ <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" [closeOnly]="true" [submit]="imp.submit ?? null" (imported)="onImported(current().key)" />
43883
43970
  }
43884
43971
  }
43885
43972
  @case ('integrations') {
@@ -44013,9 +44100,11 @@ var SetupWizardComponent = class SetupWizardComponent {
44013
44100
  "config",
44014
44101
  "importSources",
44015
44102
  "exportParams",
44016
- "exportOnly"
44103
+ "exportOnly",
44104
+ "closeOnly",
44105
+ "submit"
44017
44106
  ],
44018
- outputs: ["imported"]
44107
+ outputs: ["finished", "imported"]
44019
44108
  },
44020
44109
  {
44021
44110
  kind: "component",
@@ -44350,16 +44439,13 @@ i0.ɵɵngDeclareClassMetadata({
44350
44439
  </ui-alert>
44351
44440
  } @else {
44352
44441
  @if (imp.hint) { <p class="sw-hint">{{ imp.hint }}</p> }
44353
- @if (imp.config.importFields?.length) {
44354
- <ui-button variant="link" [attr.data-testid]="'download-sample-' + current().key" (click)="downloadSample()">{{ imp.templateLabel || t().downloadSample }}</ui-button>
44355
- }
44356
44442
  @if (imp.sources?.length) {
44357
44443
  <ui-import-source-grid appearance="card" [disabled]="busy()" [actionLabel]="t().selectSource" [sources]="imp.sources!" [ariaLabel]="'Select your ' + imp.config.entityName + ' source'" (sourceSelect)="startImport(current().key, $event)" />
44358
44444
  } @else {
44359
44445
  <ui-button variant="primary" size="sm" [attr.data-testid]="'open-import-' + current().key" (click)="openImport(current().key)"><svg class="sw-ico" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="iconD('upload')" /></svg> {{ imp.buttonLabel }}</ui-button>
44360
44446
  }
44361
44447
  }
44362
- <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" (imported)="onImported(current().key)" />
44448
+ <ui-import-export #importer style="display:none" [config]="imp.config" [importSources]="imp.sources" [closeOnly]="true" [submit]="imp.submit ?? null" (imported)="onImported(current().key)" />
44363
44449
  }
44364
44450
  }
44365
44451
  @case ('integrations') {