@epistola.app/valtimo-plugin 0.3.0 → 0.3.1

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,7 +1,7 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, EventEmitter, Output, Input, Component, ChangeDetectionStrategy, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/common/http';
4
- import { HttpClientModule } from '@angular/common/http';
4
+ import { HttpHeaders, HttpClientModule } from '@angular/common/http';
5
5
  import * as i2 from '@valtimo/shared';
6
6
  import * as i1$1 from '@angular/common';
7
7
  import { CommonModule } from '@angular/common';
@@ -81,6 +81,12 @@ class EpistolaPluginService {
81
81
  }
82
82
  return this.http.get(`${this.apiEndpoint}/retry-form`, { params });
83
83
  }
84
+ /**
85
+ * Discover all previewable document sources for a given Valtimo document.
86
+ */
87
+ getPreviewSources(documentId) {
88
+ return this.http.get(`${this.apiEndpoint}/preview-sources`, { params: { documentId } });
89
+ }
84
90
  /**
85
91
  * Preview a document by dry-running the generate-document process link.
86
92
  * Returns the resolved data as a mock preview (Phase 1).
@@ -1494,6 +1500,246 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1494
1500
  type: Input
1495
1501
  }] } });
1496
1502
 
1503
+ class EpistolaDocumentPreviewComponent {
1504
+ epistolaPluginService;
1505
+ http;
1506
+ sanitizer;
1507
+ configService;
1508
+ formIoStateService;
1509
+ cdr;
1510
+ value;
1511
+ valueChange = new EventEmitter();
1512
+ disabled = false;
1513
+ label = 'Document Preview';
1514
+ sources = [];
1515
+ selectedIndex = 0;
1516
+ discovering = false;
1517
+ loading = false;
1518
+ error = null;
1519
+ previewUrl = null;
1520
+ initialized = false;
1521
+ currentBlobUrl = null;
1522
+ discoverSubscription;
1523
+ previewSubscription;
1524
+ apiEndpoint;
1525
+ constructor(epistolaPluginService, http, sanitizer, configService, formIoStateService, cdr) {
1526
+ this.epistolaPluginService = epistolaPluginService;
1527
+ this.http = http;
1528
+ this.sanitizer = sanitizer;
1529
+ this.configService = configService;
1530
+ this.formIoStateService = formIoStateService;
1531
+ this.cdr = cdr;
1532
+ this.apiEndpoint = `${this.configService.config.valtimoApi.endpointUri}v1/plugin/epistola`;
1533
+ }
1534
+ ngOnChanges(changes) {
1535
+ if (!this.initialized) {
1536
+ this.initialized = true;
1537
+ this.discoverSources();
1538
+ }
1539
+ }
1540
+ ngOnDestroy() {
1541
+ this.discoverSubscription?.unsubscribe();
1542
+ this.previewSubscription?.unsubscribe();
1543
+ this.revokeBlobUrl();
1544
+ }
1545
+ onSourceChange(event) {
1546
+ this.selectedIndex = +event.target.value;
1547
+ this.loadPreview();
1548
+ }
1549
+ refresh() {
1550
+ this.loadPreview();
1551
+ }
1552
+ discoverSources() {
1553
+ const documentId = this.formIoStateService.documentId;
1554
+ if (!documentId) {
1555
+ this.error = 'Could not determine document ID from context.';
1556
+ this.cdr.markForCheck();
1557
+ return;
1558
+ }
1559
+ this.discovering = true;
1560
+ this.error = null;
1561
+ this.cdr.markForCheck();
1562
+ this.discoverSubscription = this.epistolaPluginService.getPreviewSources(documentId).subscribe({
1563
+ next: (sources) => {
1564
+ this.sources = sources;
1565
+ this.discovering = false;
1566
+ this.cdr.markForCheck();
1567
+ if (sources.length > 0) {
1568
+ this.selectedIndex = 0;
1569
+ this.loadPreview();
1570
+ }
1571
+ },
1572
+ error: (err) => {
1573
+ this.error = err.error?.error || 'Failed to discover preview sources';
1574
+ this.discovering = false;
1575
+ this.cdr.markForCheck();
1576
+ }
1577
+ });
1578
+ }
1579
+ loadPreview() {
1580
+ const source = this.sources[this.selectedIndex];
1581
+ if (!source)
1582
+ return;
1583
+ const documentId = this.formIoStateService.documentId;
1584
+ if (!documentId)
1585
+ return;
1586
+ this.loading = true;
1587
+ this.error = null;
1588
+ this.cdr.markForCheck();
1589
+ this.revokeBlobUrl();
1590
+ this.previewSubscription?.unsubscribe();
1591
+ this.previewSubscription = this.http.post(`${this.apiEndpoint}/preview`, {
1592
+ documentId,
1593
+ processInstanceId: source.processInstanceId,
1594
+ sourceActivityId: source.activityId,
1595
+ overrides: null
1596
+ }, {
1597
+ responseType: 'blob',
1598
+ headers: new HttpHeaders().set('X-Skip-Interceptor', '422')
1599
+ }).subscribe({
1600
+ next: (blob) => {
1601
+ this.currentBlobUrl = URL.createObjectURL(blob);
1602
+ this.previewUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.currentBlobUrl);
1603
+ this.error = null;
1604
+ this.loading = false;
1605
+ this.cdr.markForCheck();
1606
+ },
1607
+ error: (err) => {
1608
+ this.previewUrl = null;
1609
+ if (err.error instanceof Blob) {
1610
+ err.error.text().then((text) => {
1611
+ try {
1612
+ const body = JSON.parse(text);
1613
+ this.error = body.details || body.error || 'Preview could not be generated';
1614
+ }
1615
+ catch {
1616
+ this.error = 'Preview could not be generated';
1617
+ }
1618
+ this.loading = false;
1619
+ this.cdr.markForCheck();
1620
+ });
1621
+ }
1622
+ else {
1623
+ this.error = err.error?.error || 'Preview could not be generated';
1624
+ this.loading = false;
1625
+ this.cdr.markForCheck();
1626
+ }
1627
+ }
1628
+ });
1629
+ }
1630
+ revokeBlobUrl() {
1631
+ if (this.currentBlobUrl) {
1632
+ URL.revokeObjectURL(this.currentBlobUrl);
1633
+ this.currentBlobUrl = null;
1634
+ this.previewUrl = null;
1635
+ }
1636
+ }
1637
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaDocumentPreviewComponent, deps: [{ token: EpistolaPluginService }, { token: i1.HttpClient }, { token: i4$1.DomSanitizer }, { token: i2.ConfigService }, { token: i3.FormIoStateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1638
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.20", type: EpistolaDocumentPreviewComponent, isStandalone: true, selector: "epistola-document-preview-component", inputs: { value: "value", disabled: "disabled", label: "label" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: `
1639
+ <div class="epistola-preview-panel">
1640
+ <div class="preview-header">
1641
+ <span>{{ label || 'Document Preview' }}</span>
1642
+ <div class="preview-controls">
1643
+ <select
1644
+ *ngIf="sources.length > 1"
1645
+ class="preview-select"
1646
+ [value]="selectedIndex"
1647
+ (change)="onSourceChange($event)"
1648
+ >
1649
+ <option *ngFor="let source of sources; let i = index" [value]="i">
1650
+ {{ source.templateName }} ({{ source.activityId }})
1651
+ </option>
1652
+ </select>
1653
+ <button type="button" class="preview-refresh" [disabled]="loading || discovering" (click)="refresh()">
1654
+ <i class="mdi mdi-refresh mr-1"></i>
1655
+ {{ loading ? 'Generating...' : 'Refresh' }}
1656
+ </button>
1657
+ </div>
1658
+ </div>
1659
+ <div class="preview-body">
1660
+ <div *ngIf="discovering" class="preview-loading">
1661
+ Discovering documents...
1662
+ </div>
1663
+ <div *ngIf="loading && !discovering" class="preview-loading">
1664
+ Generating preview...
1665
+ </div>
1666
+ <div *ngIf="error && !loading && !discovering" class="preview-unavailable">
1667
+ <i class="mdi mdi-information-outline"></i>
1668
+ Preview is niet beschikbaar — niet alle gegevens zijn al ingevuld.
1669
+ </div>
1670
+ <object
1671
+ *ngIf="previewUrl && !loading && !discovering"
1672
+ [data]="previewUrl"
1673
+ type="application/pdf"
1674
+ class="preview-pdf"
1675
+ >
1676
+ PDF preview is not supported in this browser.
1677
+ </object>
1678
+ <div *ngIf="!previewUrl && !loading && !discovering && !error && sources.length === 0" class="preview-empty">
1679
+ No previewable documents found
1680
+ </div>
1681
+ </div>
1682
+ </div>
1683
+ `, isInline: true, styles: [".epistola-preview-panel{border:1px solid #dee2e6;border-radius:4px;background:#f8f9fa;display:flex;flex-direction:column}.preview-header{display:flex;justify-content:space-between;align-items:center;padding:.5rem 1rem;border-bottom:1px solid #dee2e6;font-weight:700;color:#495057;flex-wrap:wrap;gap:.5rem}.preview-controls{display:flex;align-items:center;gap:.5rem}.preview-select{border:1px solid #ced4da;border-radius:4px;padding:.25rem .5rem;font-size:.8rem;background:#fff;max-width:300px}.preview-refresh{background:none;border:1px solid #6c757d;border-radius:4px;color:#6c757d;padding:.25rem .75rem;font-size:.8rem;cursor:pointer;display:flex;align-items:center;white-space:nowrap}.preview-refresh:hover:not(:disabled){background:#e9ecef}.preview-refresh:disabled{opacity:.5;cursor:not-allowed}.preview-body{display:flex;flex-direction:column;min-height:500px}.preview-loading{padding:2rem;text-align:center;color:#6c757d;font-style:italic}.preview-unavailable{padding:1.5rem;text-align:center;color:#6c757d;font-style:italic}.preview-unavailable i{margin-right:.25rem}.preview-pdf{width:100%;flex:1;min-height:500px}.preview-empty{padding:2rem;text-align:center;color:#6c757d;font-style:italic}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1684
+ }
1685
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaDocumentPreviewComponent, decorators: [{
1686
+ type: Component,
1687
+ args: [{ standalone: true, imports: [CommonModule], selector: 'epistola-document-preview-component', changeDetection: ChangeDetectionStrategy.OnPush, template: `
1688
+ <div class="epistola-preview-panel">
1689
+ <div class="preview-header">
1690
+ <span>{{ label || 'Document Preview' }}</span>
1691
+ <div class="preview-controls">
1692
+ <select
1693
+ *ngIf="sources.length > 1"
1694
+ class="preview-select"
1695
+ [value]="selectedIndex"
1696
+ (change)="onSourceChange($event)"
1697
+ >
1698
+ <option *ngFor="let source of sources; let i = index" [value]="i">
1699
+ {{ source.templateName }} ({{ source.activityId }})
1700
+ </option>
1701
+ </select>
1702
+ <button type="button" class="preview-refresh" [disabled]="loading || discovering" (click)="refresh()">
1703
+ <i class="mdi mdi-refresh mr-1"></i>
1704
+ {{ loading ? 'Generating...' : 'Refresh' }}
1705
+ </button>
1706
+ </div>
1707
+ </div>
1708
+ <div class="preview-body">
1709
+ <div *ngIf="discovering" class="preview-loading">
1710
+ Discovering documents...
1711
+ </div>
1712
+ <div *ngIf="loading && !discovering" class="preview-loading">
1713
+ Generating preview...
1714
+ </div>
1715
+ <div *ngIf="error && !loading && !discovering" class="preview-unavailable">
1716
+ <i class="mdi mdi-information-outline"></i>
1717
+ Preview is niet beschikbaar — niet alle gegevens zijn al ingevuld.
1718
+ </div>
1719
+ <object
1720
+ *ngIf="previewUrl && !loading && !discovering"
1721
+ [data]="previewUrl"
1722
+ type="application/pdf"
1723
+ class="preview-pdf"
1724
+ >
1725
+ PDF preview is not supported in this browser.
1726
+ </object>
1727
+ <div *ngIf="!previewUrl && !loading && !discovering && !error && sources.length === 0" class="preview-empty">
1728
+ No previewable documents found
1729
+ </div>
1730
+ </div>
1731
+ </div>
1732
+ `, styles: [".epistola-preview-panel{border:1px solid #dee2e6;border-radius:4px;background:#f8f9fa;display:flex;flex-direction:column}.preview-header{display:flex;justify-content:space-between;align-items:center;padding:.5rem 1rem;border-bottom:1px solid #dee2e6;font-weight:700;color:#495057;flex-wrap:wrap;gap:.5rem}.preview-controls{display:flex;align-items:center;gap:.5rem}.preview-select{border:1px solid #ced4da;border-radius:4px;padding:.25rem .5rem;font-size:.8rem;background:#fff;max-width:300px}.preview-refresh{background:none;border:1px solid #6c757d;border-radius:4px;color:#6c757d;padding:.25rem .75rem;font-size:.8rem;cursor:pointer;display:flex;align-items:center;white-space:nowrap}.preview-refresh:hover:not(:disabled){background:#e9ecef}.preview-refresh:disabled{opacity:.5;cursor:not-allowed}.preview-body{display:flex;flex-direction:column;min-height:500px}.preview-loading{padding:2rem;text-align:center;color:#6c757d;font-style:italic}.preview-unavailable{padding:1.5rem;text-align:center;color:#6c757d;font-style:italic}.preview-unavailable i{margin-right:.25rem}.preview-pdf{width:100%;flex:1;min-height:500px}.preview-empty{padding:2rem;text-align:center;color:#6c757d;font-style:italic}\n"] }]
1733
+ }], ctorParameters: () => [{ type: EpistolaPluginService }, { type: i1.HttpClient }, { type: i4$1.DomSanitizer }, { type: i2.ConfigService }, { type: i3.FormIoStateService }, { type: i0.ChangeDetectorRef }], propDecorators: { value: [{
1734
+ type: Input
1735
+ }], valueChange: [{
1736
+ type: Output
1737
+ }], disabled: [{
1738
+ type: Input
1739
+ }], label: [{
1740
+ type: Input
1741
+ }] } });
1742
+
1497
1743
  class EpistolaPluginModule {
1498
1744
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1499
1745
  static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, imports: [CommonModule,
@@ -1510,7 +1756,8 @@ class EpistolaPluginModule {
1510
1756
  FieldTreeComponent,
1511
1757
  EpistolaDownloadComponent,
1512
1758
  EpistolaRetryFormComponent,
1513
- EpistolaPreviewButtonComponent], exports: [EpistolaConfigurationComponent,
1759
+ EpistolaPreviewButtonComponent,
1760
+ EpistolaDocumentPreviewComponent], exports: [EpistolaConfigurationComponent,
1514
1761
  GenerateDocumentConfigurationComponent,
1515
1762
  CheckJobStatusConfigurationComponent,
1516
1763
  DownloadDocumentConfigurationComponent,
@@ -1518,7 +1765,8 @@ class EpistolaPluginModule {
1518
1765
  FieldTreeComponent,
1519
1766
  EpistolaDownloadComponent,
1520
1767
  EpistolaRetryFormComponent,
1521
- EpistolaPreviewButtonComponent] });
1768
+ EpistolaPreviewButtonComponent,
1769
+ EpistolaDocumentPreviewComponent] });
1522
1770
  static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, providers: [
1523
1771
  EpistolaPluginService
1524
1772
  ], imports: [CommonModule,
@@ -1535,7 +1783,8 @@ class EpistolaPluginModule {
1535
1783
  FieldTreeComponent,
1536
1784
  EpistolaDownloadComponent,
1537
1785
  EpistolaRetryFormComponent,
1538
- EpistolaPreviewButtonComponent] });
1786
+ EpistolaPreviewButtonComponent,
1787
+ EpistolaDocumentPreviewComponent] });
1539
1788
  }
1540
1789
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EpistolaPluginModule, decorators: [{
1541
1790
  type: NgModule,
@@ -1555,7 +1804,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1555
1804
  FieldTreeComponent,
1556
1805
  EpistolaDownloadComponent,
1557
1806
  EpistolaRetryFormComponent,
1558
- EpistolaPreviewButtonComponent
1807
+ EpistolaPreviewButtonComponent,
1808
+ EpistolaDocumentPreviewComponent
1559
1809
  ],
1560
1810
  exports: [
1561
1811
  EpistolaConfigurationComponent,
@@ -1566,7 +1816,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
1566
1816
  FieldTreeComponent,
1567
1817
  EpistolaDownloadComponent,
1568
1818
  EpistolaRetryFormComponent,
1569
- EpistolaPreviewButtonComponent
1819
+ EpistolaPreviewButtonComponent,
1820
+ EpistolaDocumentPreviewComponent
1570
1821
  ],
1571
1822
  providers: [
1572
1823
  EpistolaPluginService
@@ -1813,6 +2064,21 @@ function registerEpistolaPreviewButtonComponent(injector) {
1813
2064
  }
1814
2065
  }
1815
2066
 
2067
+ const EPISTOLA_DOCUMENT_PREVIEW_OPTIONS = {
2068
+ type: 'epistola-document-preview',
2069
+ selector: 'epistola-document-preview-element',
2070
+ title: 'Epistola Document Preview',
2071
+ group: 'basic',
2072
+ icon: 'file-pdf-o',
2073
+ emptyValue: null,
2074
+ fieldOptions: ['label'],
2075
+ };
2076
+ function registerEpistolaDocumentPreviewComponent(injector) {
2077
+ if (!customElements.get(EPISTOLA_DOCUMENT_PREVIEW_OPTIONS.selector)) {
2078
+ registerCustomFormioComponent(EPISTOLA_DOCUMENT_PREVIEW_OPTIONS, EpistolaDocumentPreviewComponent, injector);
2079
+ }
2080
+ }
2081
+
1816
2082
  /*
1817
2083
  * Public API Surface of epistola plugin
1818
2084
  */
@@ -1821,5 +2087,5 @@ function registerEpistolaPreviewButtonComponent(injector) {
1821
2087
  * Generated bundle index. Do not edit.
1822
2088
  */
1823
2089
 
1824
- export { CheckJobStatusConfigurationComponent, DataMappingTreeComponent, DownloadDocumentConfigurationComponent, EPISTOLA_DOWNLOAD_OPTIONS, EPISTOLA_PREVIEW_BUTTON_OPTIONS, EPISTOLA_RETRY_FORM_OPTIONS, EpistolaConfigurationComponent, EpistolaDownloadComponent, EpistolaPluginModule, EpistolaPluginService, EpistolaPreviewButtonComponent, EpistolaRetryFormComponent, FieldTreeComponent, GenerateDocumentConfigurationComponent, epistolaPluginSpecification, registerEpistolaDownloadComponent, registerEpistolaPreviewButtonComponent, registerEpistolaRetryFormComponent };
2090
+ export { CheckJobStatusConfigurationComponent, DataMappingTreeComponent, DownloadDocumentConfigurationComponent, EPISTOLA_DOCUMENT_PREVIEW_OPTIONS, EPISTOLA_DOWNLOAD_OPTIONS, EPISTOLA_PREVIEW_BUTTON_OPTIONS, EPISTOLA_RETRY_FORM_OPTIONS, EpistolaConfigurationComponent, EpistolaDocumentPreviewComponent, EpistolaDownloadComponent, EpistolaPluginModule, EpistolaPluginService, EpistolaPreviewButtonComponent, EpistolaRetryFormComponent, FieldTreeComponent, GenerateDocumentConfigurationComponent, epistolaPluginSpecification, registerEpistolaDocumentPreviewComponent, registerEpistolaDownloadComponent, registerEpistolaPreviewButtonComponent, registerEpistolaRetryFormComponent };
1825
2091
  //# sourceMappingURL=epistola.app-valtimo-plugin.mjs.map