@dignite/vault-extract 0.2.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.
Files changed (39) hide show
  1. package/README.md +17 -0
  2. package/fesm2022/dignite-vault-extract-config.mjs +82 -0
  3. package/fesm2022/dignite-vault-extract-config.mjs.map +1 -0
  4. package/fesm2022/dignite-vault-extract-documents-cabinet-list.component-Ch0gpSCc.mjs +184 -0
  5. package/fesm2022/dignite-vault-extract-documents-cabinet-list.component-Ch0gpSCc.mjs.map +1 -0
  6. package/fesm2022/dignite-vault-extract-documents-content-type-DjCs-s4E.mjs +115 -0
  7. package/fesm2022/dignite-vault-extract-documents-content-type-DjCs-s4E.mjs.map +1 -0
  8. package/fesm2022/dignite-vault-extract-documents-document-detail.component-DHs42DWJ.mjs +1146 -0
  9. package/fesm2022/dignite-vault-extract-documents-document-detail.component-DHs42DWJ.mjs.map +1 -0
  10. package/fesm2022/dignite-vault-extract-documents-document-file-preview.component-CStXf8v9.mjs +72 -0
  11. package/fesm2022/dignite-vault-extract-documents-document-file-preview.component-CStXf8v9.mjs.map +1 -0
  12. package/fesm2022/dignite-vault-extract-documents-document-list.component-jThR5cct.mjs +642 -0
  13. package/fesm2022/dignite-vault-extract-documents-document-list.component-jThR5cct.mjs.map +1 -0
  14. package/fesm2022/dignite-vault-extract-documents-document-overview.component-BHUUUIVr.mjs +318 -0
  15. package/fesm2022/dignite-vault-extract-documents-document-overview.component-BHUUUIVr.mjs.map +1 -0
  16. package/fesm2022/dignite-vault-extract-documents-document-recycle-bin.component-dqeBrw22.mjs +178 -0
  17. package/fesm2022/dignite-vault-extract-documents-document-recycle-bin.component-dqeBrw22.mjs.map +1 -0
  18. package/fesm2022/dignite-vault-extract-documents-document-type-list.component-C8kXFJGb.mjs +464 -0
  19. package/fesm2022/dignite-vault-extract-documents-document-type-list.component-C8kXFJGb.mjs.map +1 -0
  20. package/fesm2022/dignite-vault-extract-documents-export-template-list.component-DlmZFFF1.mjs +361 -0
  21. package/fesm2022/dignite-vault-extract-documents-export-template-list.component-DlmZFFF1.mjs.map +1 -0
  22. package/fesm2022/dignite-vault-extract-documents-extensible-table-DkLXuoWo.mjs +53 -0
  23. package/fesm2022/dignite-vault-extract-documents-extensible-table-DkLXuoWo.mjs.map +1 -0
  24. package/fesm2022/dignite-vault-extract-documents-field-definition-list.component-ClmWkRun.mjs +530 -0
  25. package/fesm2022/dignite-vault-extract-documents-field-definition-list.component-ClmWkRun.mjs.map +1 -0
  26. package/fesm2022/dignite-vault-extract-documents-field-reextraction-modal.component-D7OOycv9.mjs +163 -0
  27. package/fesm2022/dignite-vault-extract-documents-field-reextraction-modal.component-D7OOycv9.mjs.map +1 -0
  28. package/fesm2022/dignite-vault-extract-documents-format-bytes-Cd3QwfQZ.mjs +19 -0
  29. package/fesm2022/dignite-vault-extract-documents-format-bytes-Cd3QwfQZ.mjs.map +1 -0
  30. package/fesm2022/dignite-vault-extract-documents-format-field-value-Xjb8lwzA.mjs +22 -0
  31. package/fesm2022/dignite-vault-extract-documents-format-field-value-Xjb8lwzA.mjs.map +1 -0
  32. package/fesm2022/dignite-vault-extract-documents.mjs +71 -0
  33. package/fesm2022/dignite-vault-extract-documents.mjs.map +1 -0
  34. package/fesm2022/dignite-vault-extract.mjs +522 -0
  35. package/fesm2022/dignite-vault-extract.mjs.map +1 -0
  36. package/package.json +38 -0
  37. package/types/dignite-vault-extract-config.d.ts +5 -0
  38. package/types/dignite-vault-extract-documents.d.ts +5 -0
  39. package/types/dignite-vault-extract.d.ts +521 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dignite-vault-extract-documents-document-type-list.component-C8kXFJGb.mjs","sources":["../../../packages/vault-extract/documents/src/lib/reprocessing/reclassification-modal/reclassification-modal.component.ts","../../../packages/vault-extract/documents/src/lib/reprocessing/reclassification-modal/reclassification-modal.component.html","../../../packages/vault-extract/documents/src/lib/document-types/document-type-list/document-type-list.component.ts","../../../packages/vault-extract/documents/src/lib/document-types/document-type-list/document-type-list.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n EventEmitter,\n Input,\n OnInit,\n Output,\n inject,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { CommonModule } from '@angular/common';\nimport { FormBuilder, ReactiveFormsModule } from '@angular/forms';\nimport { EMPTY, Subject, catchError, switchMap } from 'rxjs';\nimport { LocalizationPipe } from '@abp/ng.core';\nimport { ToasterService } from '@abp/ng.theme.shared';\nimport {\n DocumentReprocessingService,\n ReclassificationScope,\n ReclassificationScopeInput,\n} from '@dignite/vault-extract';\n\n/**\n * Bulk reclassification preview and trigger modal (#289 scenario 1): cascading, destructive, and\n * strongly warned.\n * Humans choose the scope by intent (only this type / all documents across types / pending review\n * queue); the system does not prescribe a default. Manual confirmations are protected by default, and\n * overwriting manual results requires an explicit opt-in. Scope and toggle changes refresh the affected\n * document count preview immediately.\n *\n * When opened from a document type menu, [documentTypeId] is passed and the default scope is only that\n * type; users can switch to all documents or the pending review queue.\n * When opened without type context, such as a global entry, only-this-type is unavailable and the\n * default is all documents across types.\n */\n@Component({\n selector: 'lib-reclassification-modal',\n templateUrl: './reclassification-modal.component.html',\n standalone: true,\n imports: [CommonModule, ReactiveFormsModule, LocalizationPipe],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ReclassificationModalComponent implements OnInit {\n private readonly service = inject(DocumentReprocessingService);\n private readonly toaster = inject(ToasterService);\n private readonly fb = inject(FormBuilder);\n private readonly destroyRef = inject(DestroyRef);\n\n @Input() documentTypeId?: string;\n @Input() documentTypeDisplayName = '';\n\n @Output() closed = new EventEmitter<void>();\n\n readonly Scope = ReclassificationScope;\n\n readonly documentCount = signal<number | null>(null);\n readonly isLoadingPreview = signal(false);\n readonly previewFailed = signal(false);\n readonly isSubmitting = signal(false);\n\n readonly form = this.fb.nonNullable.group({\n scope: ReclassificationScope.OnlyCurrentType,\n includeManuallyConfirmed: false,\n });\n\n get hasType(): boolean {\n return !!this.documentTypeId;\n }\n\n // The protect-manual-confirmations toggle is meaningless for the pending review queue, because pending\n // review documents are not confirmed yet.\n get includeToggleApplies(): boolean {\n return this.form.controls.scope.value !== ReclassificationScope.PendingReviewQueue;\n }\n\n private readonly previewTrigger = new Subject<void>();\n\n ngOnInit(): void {\n // No type context: default to all documents across types; only-this-type is unavailable.\n this.form.controls.scope.setValue(\n this.hasType ? ReclassificationScope.OnlyCurrentType : ReclassificationScope.AllDocuments,\n { emitEvent: false },\n );\n this.applyIncludeTogglePolicy();\n\n // switchMap cancels in-flight preview requests when scope or toggles change quickly, preventing\n // out-of-order responses from showing counts for stale scopes (review round 1).\n this.previewTrigger\n .pipe(\n switchMap(() => {\n this.isLoadingPreview.set(true);\n this.previewFailed.set(false);\n return this.service.previewReclassification(this.buildInput()).pipe(\n catchError(() => {\n this.documentCount.set(null);\n this.previewFailed.set(true);\n this.isLoadingPreview.set(false);\n return EMPTY;\n }),\n );\n }),\n takeUntilDestroyed(this.destroyRef),\n )\n .subscribe(dto => {\n this.documentCount.set(dto.documentCount ?? null);\n this.isLoadingPreview.set(false);\n });\n\n this.form.valueChanges\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.applyIncludeTogglePolicy();\n this.previewTrigger.next();\n });\n\n this.previewTrigger.next();\n }\n\n // The protect-manual-confirmations toggle is meaningless for the pending review queue. Drive this with\n // reactive-forms disable/enable instead of template [disabled], avoiding Angular dev warnings on\n // formControlName [disabled] and keeping FormControl.disabled truly synchronized.\n private applyIncludeTogglePolicy(): void {\n const control = this.form.controls.includeManuallyConfirmed;\n if (this.includeToggleApplies) {\n if (control.disabled) control.enable({ emitEvent: false });\n } else if (control.enabled) {\n control.disable({ emitEvent: false });\n }\n }\n\n // Explicit retry after preview failure, aligned with the field re-extraction modal UX; switchMap\n // cancels any in-flight request.\n refreshPreview(): void {\n this.previewTrigger.next();\n }\n\n private buildInput(): ReclassificationScopeInput {\n const raw = this.form.getRawValue();\n return {\n scope: Number(raw.scope) as ReclassificationScope,\n documentTypeId: Number(raw.scope) === ReclassificationScope.OnlyCurrentType ? this.documentTypeId : undefined,\n includeManuallyConfirmed: raw.includeManuallyConfirmed,\n };\n }\n\n confirm(): void {\n if (this.isSubmitting()) return;\n this.isSubmitting.set(true);\n this.service\n .startReclassification(this.buildInput())\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n this.isSubmitting.set(false);\n this.toaster.success('::Document:Reprocess:Reclassification:Queued', '::Success');\n this.close();\n },\n error: () => {\n this.isSubmitting.set(false);\n this.toaster.error('::Document:Reprocess:Failed', '::Error');\n },\n });\n }\n\n close(): void {\n this.closed.emit();\n }\n\n private backdropMouseDownOnSelf = false;\n onBackdropMouseDown(event: MouseEvent): void {\n this.backdropMouseDownOnSelf = event.target === event.currentTarget;\n }\n onBackdropClick(event: MouseEvent): void {\n if (this.backdropMouseDownOnSelf && event.target === event.currentTarget && !this.isSubmitting()) {\n this.close();\n }\n this.backdropMouseDownOnSelf = false;\n }\n}\n","<div\n class=\"modal d-block\"\n tabindex=\"-1\"\n style=\"background:rgba(0,0,0,.4);\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n (click)=\"onBackdropClick($event)\"\n>\n <div class=\"modal-dialog modal-dialog-centered\">\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-shuffle me-2\"></i>\n {{ '::Document:Reprocess:Reclassification:Title' | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"close()\" [disabled]=\"isSubmitting()\"></button>\n </div>\n\n <div class=\"modal-body\" [formGroup]=\"form\">\n <!-- Scope selection: humans choose by intent; the system does not prescribe a default. -->\n <div class=\"mb-3\">\n <label class=\"form-label fw-semibold\">{{ '::Document:Reprocess:Reclassification:Scope' | abpLocalization }}</label>\n\n @if (hasType) {\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" formControlName=\"scope\" id=\"scope-type\"\n [value]=\"Scope.OnlyCurrentType\" />\n <label class=\"form-check-label\" for=\"scope-type\">\n {{ '::Document:Reprocess:Reclassification:Scope:OnlyCurrentType' | abpLocalization: documentTypeDisplayName }}\n <span class=\"d-block small text-muted\">{{ '::Document:Reprocess:Reclassification:Scope:OnlyCurrentType:Hint' | abpLocalization }}</span>\n </label>\n </div>\n }\n\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" formControlName=\"scope\" id=\"scope-all\"\n [value]=\"Scope.AllDocuments\" />\n <label class=\"form-check-label\" for=\"scope-all\">\n {{ '::Document:Reprocess:Reclassification:Scope:AllDocuments' | abpLocalization }}\n <span class=\"d-block small text-muted\">{{ '::Document:Reprocess:Reclassification:Scope:AllDocuments:Hint' | abpLocalization }}</span>\n </label>\n </div>\n\n <div class=\"form-check\">\n <input class=\"form-check-input\" type=\"radio\" formControlName=\"scope\" id=\"scope-pending\"\n [value]=\"Scope.PendingReviewQueue\" />\n <label class=\"form-check-label\" for=\"scope-pending\">\n {{ '::Document:Reprocess:Reclassification:Scope:PendingReviewQueue' | abpLocalization }}\n <span class=\"d-block small text-muted\">{{ '::Document:Reprocess:Reclassification:Scope:PendingReviewQueue:Hint' | abpLocalization }}</span>\n </label>\n </div>\n </div>\n\n <!-- Protect manual confirmations by default; checked means manually confirmed documents are reclassified too. -->\n <div class=\"form-check mb-3\" [class.opacity-50]=\"!includeToggleApplies\">\n <input class=\"form-check-input\" type=\"checkbox\" formControlName=\"includeManuallyConfirmed\"\n id=\"include-confirmed\" />\n <label class=\"form-check-label\" for=\"include-confirmed\">\n {{ '::Document:Reprocess:Reclassification:IncludeConfirmed' | abpLocalization }}\n <span class=\"d-block small text-muted\">{{ '::Document:Reprocess:Reclassification:IncludeConfirmed:Hint' | abpLocalization }}</span>\n </label>\n </div>\n\n <!-- Affected document count preview. -->\n <div class=\"alert alert-secondary py-2\">\n @if (isLoadingPreview()) {\n <span class=\"spinner-border spinner-border-sm me-2\"></span>\n {{ '::Document:Reprocess:Counting' | abpLocalization }}\n } @else if (previewFailed()) {\n <span class=\"d-flex justify-content-between align-items-center\">\n <span class=\"text-danger\">{{ '::Document:Reprocess:PreviewFailed' | abpLocalization }}</span>\n <button type=\"button\" class=\"btn btn-sm btn-outline-danger\" (click)=\"refreshPreview()\">\n {{ '::Refresh' | abpLocalization }}\n </button>\n </span>\n } @else {\n <span class=\"fw-semibold\">{{ '::Document:Reprocess:AffectedCount' | abpLocalization: (((documentCount() ?? 0) | number) ?? '') }}</span>\n }\n </div>\n\n <!-- Strong warning: cascading and destructive. -->\n <div class=\"alert alert-danger mb-0 small\">\n <i class=\"fas fa-triangle-exclamation me-1\"></i>\n {{ '::Document:Reprocess:Reclassification:Warning' | abpLocalization }}\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"close()\" [disabled]=\"isSubmitting()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button\n type=\"button\"\n class=\"btn btn-danger\"\n (click)=\"confirm()\"\n [disabled]=\"isLoadingPreview() || previewFailed() || isSubmitting() || (documentCount() ?? 0) === 0\"\n >\n @if (isSubmitting()) {\n <span class=\"spinner-border spinner-border-sm me-1\"></span>\n }\n {{ '::Document:Reprocess:Reclassification:Start' | abpLocalization }}\n </button>\n </div>\n </div>\n </div>\n</div>\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n OnInit,\n inject,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { CommonModule } from '@angular/common';\nimport { Router, RouterModule } from '@angular/router';\nimport { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { escapeHtmlChars, ListService, LocalizationPipe, PermissionService } from '@abp/ng.core';\nimport type { ABP } from '@abp/ng.core';\nimport {\n EntityProp,\n EXTENSIONS_IDENTIFIER,\n ExtensionsService,\n ExtensibleTableComponent,\n ePropType,\n} from '@abp/ng.components/extensible';\nimport { Confirmation, ConfirmationService, ToasterService } from '@abp/ng.theme.shared';\nimport { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';\nimport { map, of } from 'rxjs';\nimport {\n CreateDocumentTypeDto,\n DocumentTypeDto,\n DocumentTypeService,\n EXTRACT_PERMISSIONS,\n SlugSuggestionService,\n} from '@dignite/vault-extract';\nimport {\n ClientPagedResult,\n configureEntityTable,\n pageClientItems,\n EXTRACT_TABLES,\n SortAccessors,\n} from '../../shared/extensible-table';\nimport { SlugSuggestionHandle, wireSlugSuggestion } from '../../shared/slug-suggestion';\nimport { FieldReextractionModalComponent } from '../../reprocessing/field-reextraction-modal/field-reextraction-modal.component';\nimport { ReclassificationModalComponent } from '../../reprocessing/reclassification-modal/reclassification-modal.component';\n\n// Mirrors DocumentTypeConsts (Domain.Shared): TypeCode whitelist + length cap.\nconst TYPE_CODE_PATTERN = /^[A-Za-z0-9_\\-]+(\\.[A-Za-z0-9_\\-]+)*$/;\nconst MAX_TYPE_CODE_LENGTH = 128;\nconst MAX_DISPLAY_NAME_LENGTH = 128;\nconst MAX_DESCRIPTION_LENGTH = 512;\n\nconst DOCUMENT_TYPE_SORTS: SortAccessors<DocumentTypeDto> = {\n typeCode: type => type.typeCode,\n displayName: type => type.displayName,\n confidenceThreshold: type => type.confidenceThreshold,\n priority: type => type.priority,\n};\n\n@Component({\n selector: 'lib-document-type-list',\n templateUrl: './document-type-list.component.html',\n styleUrls: ['./document-type-list.component.scss'],\n imports: [\n CommonModule,\n RouterModule,\n ReactiveFormsModule,\n LocalizationPipe,\n ExtensibleTableComponent,\n NgbDropdownModule,\n FieldReextractionModalComponent,\n ReclassificationModalComponent,\n ],\n providers: [\n ListService,\n {\n provide: EXTENSIONS_IDENTIFIER,\n useValue: EXTRACT_TABLES.DocumentTypes,\n },\n ],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class DocumentTypeListComponent implements OnInit {\n private readonly service = inject(DocumentTypeService);\n private readonly slugService = inject(SlugSuggestionService);\n private readonly router = inject(Router);\n private readonly fb = inject(FormBuilder);\n private readonly confirmation = inject(ConfirmationService);\n private readonly toaster = inject(ToasterService);\n private readonly permissionService = inject(PermissionService);\n private readonly destroyRef = inject(DestroyRef);\n private readonly extensions = inject(ExtensionsService);\n\n readonly list = inject(ListService);\n\n // Create/edit/delete buttons require any DocumentTypes write grant (#217); the route's\n // DocumentTypes.Default only lists. ABP evaluates the `||` policy expression.\n readonly canManage = this.permissionService.getGrantedPolicy(\n `${EXTRACT_PERMISSIONS.DocumentTypes.Create} || ${EXTRACT_PERMISSIONS.DocumentTypes.Update} || ${EXTRACT_PERMISSIONS.DocumentTypes.Delete}`,\n );\n\n // Bulk reprocessing entry points (#289): admin-level and independent from type CRUD permissions.\n readonly canReextractFields = this.permissionService.getGrantedPolicy(\n EXTRACT_PERMISSIONS.Documents.Reprocessing.FieldExtraction,\n );\n readonly canReclassify = this.permissionService.getGrantedPolicy(\n EXTRACT_PERMISSIONS.Documents.Reprocessing.Reclassification,\n );\n\n // Target for the open reprocessing modal; null means closed.\n reextractTarget = signal<DocumentTypeDto | null>(null);\n reclassifyTarget = signal<DocumentTypeDto | null>(null);\n\n allTypes = signal<DocumentTypeDto[]>([]);\n types = signal<ClientPagedResult<DocumentTypeDto>>({ totalCount: 0, items: [] });\n isLoading = signal(true);\n showDeleted = signal(false);\n\n // null = closed; 'create' / DocumentTypeDto = open in the matching mode.\n editing = signal<DocumentTypeDto | 'create' | null>(null);\n isSubmitting = signal(false);\n isSuggesting = signal(false);\n\n private slugHandle?: SlugSuggestionHandle;\n private tableQuery: Partial<ABP.PageQueryParams> = {};\n\n readonly form = this.fb.nonNullable.group({\n typeCode: [\n '',\n [\n Validators.required,\n Validators.maxLength(MAX_TYPE_CODE_LENGTH),\n Validators.pattern(TYPE_CODE_PATTERN),\n ],\n ],\n displayName: ['', [Validators.required, Validators.maxLength(MAX_DISPLAY_NAME_LENGTH)]],\n // Optional classification helper description (#262): only helps AI identify the type and does not\n // participate in document content processing.\n description: ['', [Validators.maxLength(MAX_DESCRIPTION_LENGTH)]],\n confidenceThreshold: [0.7, [Validators.required, Validators.min(0), Validators.max(1)]],\n priority: [0, [Validators.required]],\n });\n\n constructor() {\n configureEntityTable<DocumentTypeDto>(this.extensions, EXTRACT_TABLES.DocumentTypes, [\n EntityProp.create<DocumentTypeDto>({\n type: ePropType.String,\n name: 'typeCode',\n displayName: '::DocumentType:TypeCode',\n sortable: true,\n columnWidth: 240,\n valueResolver: data =>\n of(`<span class=\"badge bg-info text-dark\">${escapeHtmlChars(data.record.typeCode)}</span>`),\n }),\n EntityProp.create<DocumentTypeDto>({\n type: ePropType.String,\n name: 'displayName',\n displayName: '::DocumentType:DisplayName',\n sortable: true,\n }),\n EntityProp.create<DocumentTypeDto>({\n type: ePropType.Number,\n name: 'confidenceThreshold',\n displayName: '::DocumentType:ConfidenceThreshold',\n sortable: true,\n columnWidth: 190,\n valueResolver: data => of(`${((data.record.confidenceThreshold ?? 0) * 100).toFixed(0)}%`),\n }),\n EntityProp.create<DocumentTypeDto>({\n type: ePropType.Number,\n name: 'priority',\n displayName: '::DocumentType:Priority',\n sortable: true,\n columnWidth: 140,\n }),\n ]);\n }\n\n ngOnInit(): void {\n this.hookTableQuery();\n this.slugHandle = wireSlugSuggestion({\n displayName: this.form.controls.displayName,\n target: this.form.controls.typeCode,\n suggest: text => this.slugService.suggest({ label: text }, undefined).pipe(map(r => r.slug ?? '')),\n fallback: () => this.nextTypeCode(),\n destroyRef: this.destroyRef,\n onPending: pending => this.isSuggesting.set(pending),\n });\n this.load();\n }\n\n // Local fallback when the LLM is unavailable or does not translate: choose the smallest type_{n} that\n // does not conflict with existing type codes.\n private nextTypeCode(): string {\n const existing = new Set(this.allTypes().map(t => t.typeCode));\n let i = 1;\n while (existing.has(`type_${i}`)) i++;\n return `type_${i}`;\n }\n\n refresh(): void {\n this.load();\n }\n\n toggleDeleted(): void {\n this.showDeleted.update(v => !v);\n this.load();\n }\n\n private load(): void {\n this.isLoading.set(true);\n const source$ = this.showDeleted() ? this.service.getDeleted() : this.service.getVisible();\n source$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe({\n next: list => {\n this.allTypes.set(list);\n this.list.totalCount = list.length;\n this.applyTableQuery();\n this.isLoading.set(false);\n },\n error: () => {\n this.allTypes.set([]);\n this.types.set({ totalCount: 0, items: [] });\n this.list.totalCount = 0;\n this.isLoading.set(false);\n },\n });\n }\n\n private hookTableQuery(): void {\n this.list.query$\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(query => this.applyTableQuery(query));\n }\n\n private applyTableQuery(query: Partial<ABP.PageQueryParams> = this.tableQuery): void {\n this.tableQuery = query;\n this.types.set(pageClientItems(this.allTypes(), query, DOCUMENT_TYPE_SORTS));\n }\n\n openCreate(): void {\n this.form.reset({ typeCode: '', displayName: '', description: '', confidenceThreshold: 0.7, priority: 0 });\n this.form.controls.typeCode.enable();\n // Must be called after form.reset()/enable(): both trigger valueChanges that can be misread as\n // \"manual edit\". reset() clears that marker and resets suggestion state, including the spinner.\n this.slugHandle?.reset();\n this.editing.set('create');\n }\n\n openEdit(type: DocumentTypeDto): void {\n // Disable before reset so slug auto-suggestion sees edit-mode reset as not automatically managed and\n // does not clear the existing typeCode as a stale key. See wireSlugSuggestion comments.\n this.form.controls.typeCode.disable();\n this.form.reset({\n typeCode: type.typeCode,\n displayName: type.displayName,\n description: type.description ?? '',\n confidenceThreshold: type.confidenceThreshold,\n priority: type.priority,\n });\n this.form.controls.typeCode.enable();\n this.slugHandle?.markManual();\n this.editing.set(type);\n }\n\n // Display-name blur triggers slug auto-suggestion. Measured feedback changed this from pause debounce\n // to blur trigger.\n onDisplayNameBlur(): void {\n this.slugHandle?.notifyDisplayNameBlur();\n }\n\n // Backdrop close guard: close only when both mousedown and click occur on the backdrop itself, not\n // inside the dialog.\n // Otherwise, dragging selected text inside an input and releasing over the backdrop can make the\n // browser fire click on the backdrop, the nearest common ancestor of mousedown/mouseup, closing the\n // modal and losing entered content. Recording the mousedown origin is the only reliable way to know\n // whether this click truly started from the backdrop.\n private backdropMouseDownOnSelf = false;\n\n onBackdropMouseDown(event: MouseEvent): void {\n this.backdropMouseDownOnSelf = event.target === event.currentTarget;\n }\n\n onBackdropClick(event: MouseEvent): void {\n if (this.backdropMouseDownOnSelf && event.target === event.currentTarget) {\n this.closeModal();\n }\n this.backdropMouseDownOnSelf = false;\n }\n\n closeModal(): void {\n this.editing.set(null);\n }\n\n submit(): void {\n if (this.form.invalid) {\n this.form.markAllAsTouched();\n return;\n }\n const mode = this.editing();\n if (mode === null) return;\n\n this.isSubmitting.set(true);\n const raw = this.form.getRawValue();\n\n if (mode === 'create') {\n const input: CreateDocumentTypeDto = {\n typeCode: raw.typeCode,\n displayName: raw.displayName,\n description: raw.description.trim() || undefined,\n confidenceThreshold: raw.confidenceThreshold,\n priority: raw.priority,\n };\n this.service.create(input)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => this.onSaved('::DocumentType:CreatedSuccessfully'),\n error: () => this.isSubmitting.set(false),\n });\n } else {\n this.service.update(mode.id!, {\n typeCode: raw.typeCode,\n displayName: raw.displayName,\n description: raw.description.trim() || undefined,\n confidenceThreshold: raw.confidenceThreshold,\n priority: raw.priority,\n })\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => this.onSaved('::DocumentType:UpdatedSuccessfully'),\n error: () => this.isSubmitting.set(false),\n });\n }\n }\n\n private onSaved(messageKey: string): void {\n this.isSubmitting.set(false);\n this.closeModal();\n this.toaster.success(messageKey, '::Success');\n this.load();\n }\n\n delete(type: DocumentTypeDto): void {\n this.confirmation\n .warn('::DocumentType:AreYouSureToDelete', '::AreYouSure')\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(status => {\n if (status !== Confirmation.Status.confirm) return;\n this.service.delete(type.id!)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n this.toaster.success('::DocumentType:DeletedSuccessfully', '::Success');\n this.load();\n },\n error: () => this.toaster.error('::DocumentType:DeleteFailed', '::Error'),\n });\n });\n }\n\n restore(type: DocumentTypeDto): void {\n this.service.restore(type.id!)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe({\n next: () => {\n this.toaster.success('::DocumentType:RestoredSuccessfully', '::Success');\n this.load();\n },\n });\n }\n\n manageFields(type: DocumentTypeDto): void {\n this.router.navigate(['/documents/types', type.id, 'fields']);\n }\n\n openReextractFields(type: DocumentTypeDto): void {\n this.reextractTarget.set(type);\n }\n\n openReclassify(type: DocumentTypeDto): void {\n this.reclassifyTarget.set(type);\n }\n}\n","<div class=\"container-fluid py-4\">\n <!-- Header -->\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\n <h4 class=\"mb-0\">\n <i class=\"fas fa-tags me-2\"></i>\n {{ '::DocumentType:Title' | abpLocalization }}\n </h4>\n <div class=\"d-flex gap-2\">\n <button\n class=\"btn btn-outline-secondary\"\n (click)=\"refresh()\"\n [disabled]=\"isLoading()\"\n title=\"{{ '::Refresh' | abpLocalization }}\"\n >\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"isLoading()\"></i>\n </button>\n <button\n class=\"btn\"\n [class.btn-secondary]=\"showDeleted()\"\n [class.btn-outline-secondary]=\"!showDeleted()\"\n (click)=\"toggleDeleted()\"\n >\n <i class=\"fas fa-trash-can me-1\"></i>\n {{ '::DocumentType:ShowDeleted' | abpLocalization }}\n </button>\n @if (canManage && !showDeleted()) {\n <button class=\"btn btn-primary\" (click)=\"openCreate()\">\n <i class=\"fas fa-plus me-1\"></i>\n {{ '::DocumentType:New' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n\n <!-- Loading spinner -->\n @if (isLoading()) {\n <div class=\"text-center py-5\">\n <div class=\"spinner-border text-primary\" role=\"status\"></div>\n </div>\n }\n\n <!-- Empty state -->\n @if (!isLoading() && types().totalCount === 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body text-center py-5\">\n <i class=\"fas fa-tags fa-3x text-muted mb-3 d-block\"></i>\n <p class=\"text-muted mb-0\">\n {{ (showDeleted() ? '::DocumentType:RecycleBinEmpty' : '::DocumentType:Empty') | abpLocalization }}\n </p>\n </div>\n </div>\n }\n\n <!-- Types table -->\n @if (!isLoading() && types().totalCount > 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body p-0\">\n <ng-template #actionsTemplate let-type>\n @if (showDeleted()) {\n @if (canManage) {\n <div ngbDropdown container=\"body\" class=\"d-inline-block\">\n <button type=\"button\" class=\"btn btn-sm btn-primary\" ngbDropdownToggle>\n {{ 'AbpUi::Actions' | abpLocalization }}\n </button>\n <div ngbDropdownMenu>\n <button type=\"button\" ngbDropdownItem (click)=\"restore(type)\">\n <i class=\"fas fa-rotate-left me-2\"></i>\n {{ '::DocumentType:Restore' | abpLocalization }}\n </button>\n </div>\n </div>\n }\n } @else {\n <div ngbDropdown container=\"body\" class=\"d-inline-block\">\n <button type=\"button\" class=\"btn btn-sm btn-primary\" ngbDropdownToggle>\n {{ 'AbpUi::Actions' | abpLocalization }}\n </button>\n <div ngbDropdownMenu>\n <button type=\"button\" ngbDropdownItem (click)=\"manageFields(type)\">\n <i class=\"fas fa-list-ul me-2\"></i>\n {{ '::DocumentType:ManageFields' | abpLocalization }}\n </button>\n @if (canManage) {\n <button type=\"button\" ngbDropdownItem (click)=\"openEdit(type)\">\n <i class=\"fas fa-pen me-2\"></i>\n {{ '::Edit' | abpLocalization }}\n </button>\n <button type=\"button\" ngbDropdownItem (click)=\"delete(type)\">\n <i class=\"fas fa-trash me-2\"></i>\n {{ '::Delete' | abpLocalization }}\n </button>\n }\n @if (canReextractFields || canReclassify) {\n <div class=\"dropdown-divider\"></div>\n }\n @if (canReextractFields) {\n <button type=\"button\" ngbDropdownItem (click)=\"openReextractFields(type)\">\n <i class=\"fas fa-wand-magic-sparkles me-2\"></i>\n {{ '::Document:Reprocess:FieldExtraction:Action' | abpLocalization }}\n </button>\n }\n @if (canReclassify) {\n <button type=\"button\" ngbDropdownItem class=\"text-danger\" (click)=\"openReclassify(type)\">\n <i class=\"fas fa-shuffle me-2\"></i>\n {{ '::Document:Reprocess:Reclassification:Action' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n }\n </ng-template>\n\n <abp-extensible-table\n [data]=\"types().items\"\n [recordsTotal]=\"types().totalCount\"\n [list]=\"list\"\n [actionsTemplate]=\"actionsTemplate\"\n actionsText=\"AbpUi::Actions\"\n [actionsColumnWidth]=\"150\"\n />\n </div>\n </div>\n }\n</div>\n\n<!-- Create / Edit modal -->\n@if (editing(); as mode) {\n <div\n class=\"modal d-block\"\n tabindex=\"-1\"\n style=\"background:rgba(0,0,0,.4);\"\n (mousedown)=\"onBackdropMouseDown($event)\"\n (click)=\"onBackdropClick($event)\"\n >\n <div class=\"modal-dialog modal-dialog-centered\">\n <div class=\"modal-content\">\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-tags me-2\"></i>\n {{ (mode === 'create' ? '::DocumentType:New' : '::DocumentType:Edit') | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"closeModal()\"></button>\n </div>\n <div class=\"modal-body\">\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::DocumentType:DisplayName' | abpLocalization }}</label>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"displayName\"\n (blur)=\"onDisplayNameBlur()\"\n [class.is-invalid]=\"form.controls.displayName.touched && form.controls.displayName.invalid\"\n />\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label d-flex align-items-center gap-2\">\n <span>{{ '::DocumentType:TypeCode' | abpLocalization }}</span>\n @if (isSuggesting()) {\n <span class=\"text-muted small fw-normal\">\n <span class=\"spinner-border spinner-border-sm me-1\" style=\"width:.75rem;height:.75rem;\"></span>\n {{ '::DocumentType:TypeCodeSuggesting' | abpLocalization }}\n </span>\n }\n </label>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"typeCode\"\n [class.is-invalid]=\"form.controls.typeCode.touched && form.controls.typeCode.invalid\"\n placeholder=\"host.contract\"\n />\n <div class=\"form-text\">{{ '::DocumentType:TypeCodeHint' | abpLocalization }}</div>\n @if (form.controls.typeCode.touched && form.controls.typeCode.invalid) {\n <div class=\"invalid-feedback d-block\">{{ '::DocumentType:TypeCodeInvalid' | abpLocalization }}</div>\n }\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::DocumentType:Description' | abpLocalization }}</label>\n <textarea\n class=\"form-control\"\n formControlName=\"description\"\n rows=\"3\"\n [class.is-invalid]=\"form.controls.description.touched && form.controls.description.invalid\"\n ></textarea>\n <div class=\"form-text\">{{ '::DocumentType:DescriptionHint' | abpLocalization }}</div>\n </div>\n <div class=\"row g-3\">\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::DocumentType:ConfidenceThreshold' | abpLocalization }}</label>\n <input\n type=\"number\"\n class=\"form-control\"\n formControlName=\"confidenceThreshold\"\n min=\"0\"\n max=\"1\"\n step=\"0.05\"\n [class.is-invalid]=\"form.controls.confidenceThreshold.touched && form.controls.confidenceThreshold.invalid\"\n />\n <div class=\"form-text\">{{ '::DocumentType:ConfidenceThresholdHint' | abpLocalization }}</div>\n </div>\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::DocumentType:Priority' | abpLocalization }}</label>\n <input type=\"number\" class=\"form-control\" formControlName=\"priority\" step=\"1\" />\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"closeModal()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button type=\"submit\" class=\"btn btn-primary\" [disabled]=\"form.invalid || isSubmitting()\">\n @if (isSubmitting()) {\n <span class=\"spinner-border spinner-border-sm me-1\"></span>\n }\n {{ '::Save' | abpLocalization }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n\n<!-- Bulk field re-extraction modal (#289) -->\n@if (reextractTarget(); as t) {\n <lib-field-reextraction-modal\n [documentTypeId]=\"t.id!\"\n [documentTypeDisplayName]=\"t.displayName ?? ''\"\n (closed)=\"reextractTarget.set(null)\"\n />\n}\n\n<!-- Bulk reclassification modal (#289) -->\n@if (reclassifyTarget(); as t) {\n <lib-reclassification-modal\n [documentTypeId]=\"t.id!\"\n [documentTypeDisplayName]=\"t.displayName ?? ''\"\n (closed)=\"reclassifyTarget.set(null)\"\n />\n}\n"],"names":["i2"],"mappings":";;;;;;;;;;;;;;;;;;AAuBA;;;;;;;;;;;;AAYG;MAQU,8BAA8B,CAAA;AAP3C,IAAA,WAAA,GAAA;AAQmB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,2BAA2B,CAAC;AAC7C,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC;AAChC,QAAA,IAAA,CAAA,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;AACxB,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;QAGvC,IAAA,CAAA,uBAAuB,GAAG,EAAE;AAE3B,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,YAAY,EAAQ;QAElC,IAAA,CAAA,KAAK,GAAG,qBAAqB;AAE7B,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAgB,IAAI,oFAAC;AAC3C,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAC,KAAK,uFAAC;AAChC,QAAA,IAAA,CAAA,aAAa,GAAG,MAAM,CAAC,KAAK,oFAAC;AAC7B,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,KAAK,mFAAC;QAE5B,IAAA,CAAA,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;YACxC,KAAK,EAAE,qBAAqB,CAAC,eAAe;AAC5C,YAAA,wBAAwB,EAAE,KAAK;AAChC,SAAA,CAAC;AAYe,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,OAAO,EAAQ;QA6F7C,IAAA,CAAA,uBAAuB,GAAG,KAAK;AAUxC,IAAA;AAjHC,IAAA,IAAI,OAAO,GAAA;AACT,QAAA,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc;IAC9B;;;AAIA,IAAA,IAAI,oBAAoB,GAAA;AACtB,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,qBAAqB,CAAC,kBAAkB;IACpF;IAIA,QAAQ,GAAA;;AAEN,QAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAC/B,IAAI,CAAC,OAAO,GAAG,qBAAqB,CAAC,eAAe,GAAG,qBAAqB,CAAC,YAAY,EACzF,EAAE,SAAS,EAAE,KAAK,EAAE,CACrB;QACD,IAAI,CAAC,wBAAwB,EAAE;;;AAI/B,QAAA,IAAI,CAAC;AACF,aAAA,IAAI,CACH,SAAS,CAAC,MAAK;AACb,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/B,YAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC;AAC7B,YAAA,OAAO,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CACjE,UAAU,CAAC,MAAK;AACd,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B,gBAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;AAChC,gBAAA,OAAO,KAAK;YACd,CAAC,CAAC,CACH;QACH,CAAC,CAAC,EACF,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;aAEpC,SAAS,CAAC,GAAG,IAAG;YACf,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,CAAC;AACjD,YAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC;AAClC,QAAA,CAAC,CAAC;QAEJ,IAAI,CAAC,IAAI,CAAC;AACP,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;aACxC,SAAS,CAAC,MAAK;YACd,IAAI,CAAC,wBAAwB,EAAE;AAC/B,YAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;AAC5B,QAAA,CAAC,CAAC;AAEJ,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;IAC5B;;;;IAKQ,wBAAwB,GAAA;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,wBAAwB;AAC3D,QAAA,IAAI,IAAI,CAAC,oBAAoB,EAAE;YAC7B,IAAI,OAAO,CAAC,QAAQ;gBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC5D;AAAO,aAAA,IAAI,OAAO,CAAC,OAAO,EAAE;YAC1B,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QACvC;IACF;;;IAIA,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;IAC5B;IAEQ,UAAU,GAAA;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QACnC,OAAO;AACL,YAAA,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAA0B;YACjD,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,qBAAqB,CAAC,eAAe,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS;YAC7G,wBAAwB,EAAE,GAAG,CAAC,wBAAwB;SACvD;IACH;IAEA,OAAO,GAAA;QACL,IAAI,IAAI,CAAC,YAAY,EAAE;YAAE;AACzB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,CAAC;AACF,aAAA,qBAAqB,CAAC,IAAI,CAAC,UAAU,EAAE;AACvC,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC;YACT,IAAI,EAAE,MAAK;AACT,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,8CAA8C,EAAE,WAAW,CAAC;gBACjF,IAAI,CAAC,KAAK,EAAE;YACd,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,SAAS,CAAC;YAC9D,CAAC;AACF,SAAA,CAAC;IACN;IAEA,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;IACpB;AAGA,IAAA,mBAAmB,CAAC,KAAiB,EAAA;QACnC,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa;IACrE;AACA,IAAA,eAAe,CAAC,KAAiB,EAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,uBAAuB,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE;YAChG,IAAI,CAAC,KAAK,EAAE;QACd;AACA,QAAA,IAAI,CAAC,uBAAuB,GAAG,KAAK;IACtC;+GAvIW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAA9B,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,8BAA8B,uNC3C3C,0wKAyGA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDjEY,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,mBAAmB,uyCAAE,gBAAgB,EAAA,IAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAGlD,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBAP1C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,4BAA4B,EAAA,UAAA,EAE1B,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,CAAC,EAAA,eAAA,EAC7C,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,0wKAAA,EAAA;;sBAQ9C;;sBACA;;sBAEA;;;AEVH;AACA,MAAM,iBAAiB,GAAG,uCAAuC;AACjE,MAAM,oBAAoB,GAAG,GAAG;AAChC,MAAM,uBAAuB,GAAG,GAAG;AACnC,MAAM,sBAAsB,GAAG,GAAG;AAElC,MAAM,mBAAmB,GAAmC;AAC1D,IAAA,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ;AAC/B,IAAA,WAAW,EAAE,IAAI,IAAI,IAAI,CAAC,WAAW;AACrC,IAAA,mBAAmB,EAAE,IAAI,IAAI,IAAI,CAAC,mBAAmB;AACrD,IAAA,QAAQ,EAAE,IAAI,IAAI,IAAI,CAAC,QAAQ;CAChC;MAyBY,yBAAyB,CAAA;AA6DpC,IAAA,WAAA,GAAA;AA5DiB,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC;AACrC,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,qBAAqB,CAAC;AAC3C,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,QAAA,IAAA,CAAA,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC;AACxB,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC;AAC1C,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAC,cAAc,CAAC;AAChC,QAAA,IAAA,CAAA,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAC7C,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAC/B,QAAA,IAAA,CAAA,UAAU,GAAG,MAAM,CAAC,iBAAiB,CAAC;AAE9C,QAAA,IAAA,CAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;;;QAI1B,IAAA,CAAA,SAAS,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAC1D,CAAA,EAAG,mBAAmB,CAAC,aAAa,CAAC,MAAM,CAAA,IAAA,EAAO,mBAAmB,CAAC,aAAa,CAAC,MAAM,CAAA,IAAA,EAAO,mBAAmB,CAAC,aAAa,CAAC,MAAM,CAAA,CAAE,CAC5I;;AAGQ,QAAA,IAAA,CAAA,kBAAkB,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CACnE,mBAAmB,CAAC,SAAS,CAAC,YAAY,CAAC,eAAe,CAC3D;AACQ,QAAA,IAAA,CAAA,aAAa,GAAG,IAAI,CAAC,iBAAiB,CAAC,gBAAgB,CAC9D,mBAAmB,CAAC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CAC5D;;AAGD,QAAA,IAAA,CAAA,eAAe,GAAG,MAAM,CAAyB,IAAI,sFAAC;AACtD,QAAA,IAAA,CAAA,gBAAgB,GAAG,MAAM,CAAyB,IAAI,uFAAC;AAEvD,QAAA,IAAA,CAAA,QAAQ,GAAG,MAAM,CAAoB,EAAE,+EAAC;AACxC,QAAA,IAAA,CAAA,KAAK,GAAG,MAAM,CAAqC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,4EAAC;AAChF,QAAA,IAAA,CAAA,SAAS,GAAG,MAAM,CAAC,IAAI,gFAAC;AACxB,QAAA,IAAA,CAAA,WAAW,GAAG,MAAM,CAAC,KAAK,kFAAC;;AAG3B,QAAA,IAAA,CAAA,OAAO,GAAG,MAAM,CAAoC,IAAI,8EAAC;AACzD,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,KAAK,mFAAC;AAC5B,QAAA,IAAA,CAAA,YAAY,GAAG,MAAM,CAAC,KAAK,mFAAC;QAGpB,IAAA,CAAA,UAAU,GAAiC,EAAE;QAE5C,IAAA,CAAA,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;AACxC,YAAA,QAAQ,EAAE;gBACR,EAAE;AACF,gBAAA;AACE,oBAAA,UAAU,CAAC,QAAQ;AACnB,oBAAA,UAAU,CAAC,SAAS,CAAC,oBAAoB,CAAC;AAC1C,oBAAA,UAAU,CAAC,OAAO,CAAC,iBAAiB,CAAC;AACtC,iBAAA;AACF,aAAA;AACD,YAAA,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC,CAAC;;;AAGvF,YAAA,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAAC,CAAC;YACjE,mBAAmB,EAAE,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACvF,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;AACrC,SAAA,CAAC;;;;;;;QAuIM,IAAA,CAAA,uBAAuB,GAAG,KAAK;QApIrC,oBAAoB,CAAkB,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,aAAa,EAAE;YACnF,UAAU,CAAC,MAAM,CAAkB;AACjC,gBAAA,IAAI,EAAA,QAAA;AACJ,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,WAAW,EAAE,yBAAyB;AACtC,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,WAAW,EAAE,GAAG;AAChB,gBAAA,aAAa,EAAE,IAAI,IACjB,EAAE,CAAC,CAAA,sCAAA,EAAyC,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;aAC9F,CAAC;YACF,UAAU,CAAC,MAAM,CAAkB;AACjC,gBAAA,IAAI,EAAA,QAAA;AACJ,gBAAA,IAAI,EAAE,aAAa;AACnB,gBAAA,WAAW,EAAE,4BAA4B;AACzC,gBAAA,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,UAAU,CAAC,MAAM,CAAkB;AACjC,gBAAA,IAAI,EAAA,QAAA;AACJ,gBAAA,IAAI,EAAE,qBAAqB;AAC3B,gBAAA,WAAW,EAAE,oCAAoC;AACjD,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,WAAW,EAAE,GAAG;gBAChB,aAAa,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA,EAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,CAAC,IAAI,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA,CAAA,CAAG,CAAC;aAC3F,CAAC;YACF,UAAU,CAAC,MAAM,CAAkB;AACjC,gBAAA,IAAI,EAAA,QAAA;AACJ,gBAAA,IAAI,EAAE,UAAU;AAChB,gBAAA,WAAW,EAAE,yBAAyB;AACtC,gBAAA,QAAQ,EAAE,IAAI;AACd,gBAAA,WAAW,EAAE,GAAG;aACjB,CAAC;AACH,SAAA,CAAC;IACJ;IAEA,QAAQ,GAAA;QACN,IAAI,CAAC,cAAc,EAAE;AACrB,QAAA,IAAI,CAAC,UAAU,GAAG,kBAAkB,CAAC;AACnC,YAAA,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW;AAC3C,YAAA,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ;AACnC,YAAA,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;AAClG,YAAA,QAAQ,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE;YACnC,UAAU,EAAE,IAAI,CAAC,UAAU;AAC3B,YAAA,SAAS,EAAE,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC;AACrD,SAAA,CAAC;QACF,IAAI,CAAC,IAAI,EAAE;IACb;;;IAIQ,YAAY,GAAA;QAClB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG,CAAC;AACT,QAAA,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAA,KAAA,EAAQ,CAAC,EAAE,CAAC;AAAE,YAAA,CAAC,EAAE;QACrC,OAAO,CAAA,KAAA,EAAQ,CAAC,CAAA,CAAE;IACpB;IAEA,OAAO,GAAA;QACL,IAAI,CAAC,IAAI,EAAE;IACb;IAEA,aAAa,GAAA;AACX,QAAA,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,EAAE;IACb;IAEQ,IAAI,GAAA;AACV,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AAC1F,QAAA,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;YAC1D,IAAI,EAAE,IAAI,IAAG;AACX,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM;gBAClC,IAAI,CAAC,eAAe,EAAE;AACtB,gBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;YAC3B,CAAC;YACD,KAAK,EAAE,MAAK;AACV,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;AACrB,gBAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AAC5C,gBAAA,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC;AACxB,gBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;YAC3B,CAAC;AACF,SAAA,CAAC;IACJ;IAEQ,cAAc,GAAA;QACpB,IAAI,CAAC,IAAI,CAAC;AACP,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IACpD;AAEQ,IAAA,eAAe,CAAC,KAAA,GAAsC,IAAI,CAAC,UAAU,EAAA;AAC3E,QAAA,IAAI,CAAC,UAAU,GAAG,KAAK;AACvB,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC9E;IAEA,UAAU,GAAA;QACR,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,mBAAmB,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QAC1G,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE;;;AAGpC,QAAA,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE;AACxB,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC5B;AAEA,IAAA,QAAQ,CAAC,IAAqB,EAAA;;;QAG5B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE;AACrC,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;YACd,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,WAAW,EAAE,IAAI,CAAC,WAAW;AAC7B,YAAA,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;YACnC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,QAAQ,EAAE,IAAI,CAAC,QAAQ;AACxB,SAAA,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,EAAE;AACpC,QAAA,IAAI,CAAC,UAAU,EAAE,UAAU,EAAE;AAC7B,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;;;IAIA,iBAAiB,GAAA;AACf,QAAA,IAAI,CAAC,UAAU,EAAE,qBAAqB,EAAE;IAC1C;AAUA,IAAA,mBAAmB,CAAC,KAAiB,EAAA;QACnC,IAAI,CAAC,uBAAuB,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa;IACrE;AAEA,IAAA,eAAe,CAAC,KAAiB,EAAA;AAC/B,QAAA,IAAI,IAAI,CAAC,uBAAuB,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,EAAE;YACxE,IAAI,CAAC,UAAU,EAAE;QACnB;AACA,QAAA,IAAI,CAAC,uBAAuB,GAAG,KAAK;IACtC;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACxB;IAEA,MAAM,GAAA;AACJ,QAAA,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AACrB,YAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE;YAC5B;QACF;AACA,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE;QAC3B,IAAI,IAAI,KAAK,IAAI;YAAE;AAEnB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;AAEnC,QAAA,IAAI,IAAI,KAAK,QAAQ,EAAE;AACrB,YAAA,MAAM,KAAK,GAA0B;gBACnC,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,SAAS;gBAChD,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;gBAC5C,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB;AACD,YAAA,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;AACtB,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,iBAAA,SAAS,CAAC;gBACT,IAAI,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,oCAAoC,CAAC;gBAC9D,KAAK,EAAE,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,aAAA,CAAC;QACN;aAAO;YACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG,EAAE;gBAC5B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,WAAW,EAAE,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,SAAS;gBAChD,mBAAmB,EAAE,GAAG,CAAC,mBAAmB;gBAC5C,QAAQ,EAAE,GAAG,CAAC,QAAQ;aACvB;AACE,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,iBAAA,SAAS,CAAC;gBACT,IAAI,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,oCAAoC,CAAC;gBAC9D,KAAK,EAAE,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1C,aAAA,CAAC;QACN;IACF;AAEQ,IAAA,OAAO,CAAC,UAAkB,EAAA;AAChC,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,UAAU,EAAE;QACjB,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC;QAC7C,IAAI,CAAC,IAAI,EAAE;IACb;AAEA,IAAA,MAAM,CAAC,IAAqB,EAAA;AAC1B,QAAA,IAAI,CAAC;AACF,aAAA,IAAI,CAAC,mCAAmC,EAAE,cAAc;AACxD,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;aACxC,SAAS,CAAC,MAAM,IAAG;AAClB,YAAA,IAAI,MAAM,KAAK,YAAY,CAAC,MAAM,CAAC,OAAO;gBAAE;YAC5C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAG;AACzB,iBAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,iBAAA,SAAS,CAAC;gBACT,IAAI,EAAE,MAAK;oBACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,oCAAoC,EAAE,WAAW,CAAC;oBACvE,IAAI,CAAC,IAAI,EAAE;gBACb,CAAC;AACD,gBAAA,KAAK,EAAE,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,SAAS,CAAC;AAC1E,aAAA,CAAC;AACN,QAAA,CAAC,CAAC;IACN;AAEA,IAAA,OAAO,CAAC,IAAqB,EAAA;QAC3B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAG;AAC1B,aAAA,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AACxC,aAAA,SAAS,CAAC;YACT,IAAI,EAAE,MAAK;gBACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,qCAAqC,EAAE,WAAW,CAAC;gBACxE,IAAI,CAAC,IAAI,EAAE;YACb,CAAC;AACF,SAAA,CAAC;IACN;AAEA,IAAA,YAAY,CAAC,IAAqB,EAAA;AAChC,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC/D;AAEA,IAAA,mBAAmB,CAAC,IAAqB,EAAA;AACvC,QAAA,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC;AAEA,IAAA,cAAc,CAAC,IAAqB,EAAA;AAClC,QAAA,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC;IACjC;+GA1SW,yBAAyB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAzB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,yBAAyB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,SAAA,EATzB;YACT,WAAW;AACX,YAAA;AACE,gBAAA,OAAO,EAAE,qBAAqB;gBAC9B,QAAQ,EAAE,cAAc,CAAC,aAAa;AACvC,aAAA;AACF,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC3EH,k5TAiPA,EAAA,MAAA,EAAA,CAAA,8CAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDrLI,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACZ,YAAY,8BACZ,mBAAmB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,iGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gHAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,QAAA,EAAA,gHAAA,EAAA,MAAA,EAAA,CAAA,KAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAEnB,wBAAwB,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,CAAA,aAAA,EAAA,MAAA,EAAA,MAAA,EAAA,cAAA,EAAA,oBAAA,EAAA,iBAAA,EAAA,YAAA,EAAA,eAAA,EAAA,UAAA,EAAA,gBAAA,EAAA,WAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,mBAAA,EAAA,iBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,iBAAA,CAAA,EAAA,QAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EACxB,iBAAiB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,WAAA,EAAA,QAAA,EAAA,eAAA,EAAA,MAAA,EAAA,CAAA,WAAA,EAAA,eAAA,EAAA,MAAA,EAAA,WAAA,EAAA,eAAA,EAAA,WAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,YAAA,CAAA,EAAA,QAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,iBAAA,EAAA,QAAA,EAAA,qBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EACjB,+BAA+B,EAAA,QAAA,EAAA,8BAAA,EAAA,MAAA,EAAA,CAAA,gBAAA,EAAA,yBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAC/B,8BAA8B,8IAJ9B,gBAAgB,EAAA,IAAA,EAAA,iBAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA,CAAA;;4FAeP,yBAAyB,EAAA,UAAA,EAAA,CAAA;kBAvBrC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,OAAA,EAGzB;wBACP,YAAY;wBACZ,YAAY;wBACZ,mBAAmB;wBACnB,gBAAgB;wBAChB,wBAAwB;wBACxB,iBAAiB;wBACjB,+BAA+B;wBAC/B,8BAA8B;qBAC/B,EAAA,SAAA,EACU;wBACT,WAAW;AACX,wBAAA;AACE,4BAAA,OAAO,EAAE,qBAAqB;4BAC9B,QAAQ,EAAE,cAAc,CAAC,aAAa;AACvC,yBAAA;qBACF,EAAA,eAAA,EACgB,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,k5TAAA,EAAA,MAAA,EAAA,CAAA,8CAAA,CAAA,EAAA;;;;;"}
@@ -0,0 +1,361 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, DestroyRef, signal, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { CommonModule } from '@angular/common';
5
+ import * as i1 from '@angular/forms';
6
+ import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
7
+ import { PermissionService, ListService, LocalizationService, escapeHtmlChars, LocalizationPipe } from '@abp/ng.core';
8
+ import { ExtensionsService, EntityProp, ExtensibleTableComponent, EXTENSIONS_IDENTIFIER } from '@abp/ng.components/extensible';
9
+ import { ConfirmationService, ToasterService, Confirmation } from '@abp/ng.theme.shared';
10
+ import * as i2 from '@ng-bootstrap/ng-bootstrap';
11
+ import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
12
+ import { of } from 'rxjs';
13
+ import { ExportTemplateService, DocumentTypeService, FieldDefinitionService, CabinetService, EXTRACT_PERMISSIONS, exportFormatOptions, ExportFormat, DocumentLifecycleStatus, documentLifecycleStatusOptions } from '@dignite/vault-extract';
14
+ import { c as configureEntityTable, E as EXTRACT_TABLES, p as pageClientItems } from './dignite-vault-extract-documents-extensible-table-DkLXuoWo.mjs';
15
+
16
+ // Mirrors ExportTemplateConsts (Domain.Shared).
17
+ const MAX_NAME_LENGTH = 128;
18
+ const EXPORT_TEMPLATE_SORTS = {
19
+ name: template => template.name,
20
+ format: template => template.format,
21
+ documentTypeId: template => template.documentTypeId,
22
+ columns: template => template.columns?.length ?? 0,
23
+ };
24
+ class ExportTemplateListComponent {
25
+ get columns() {
26
+ return this.form.controls.columns;
27
+ }
28
+ constructor() {
29
+ this.service = inject(ExportTemplateService);
30
+ this.documentTypeService = inject(DocumentTypeService);
31
+ this.fieldDefinitionService = inject(FieldDefinitionService);
32
+ this.cabinetService = inject(CabinetService);
33
+ this.fb = inject(FormBuilder);
34
+ this.confirmation = inject(ConfirmationService);
35
+ this.toaster = inject(ToasterService);
36
+ this.permissionService = inject(PermissionService);
37
+ this.destroyRef = inject(DestroyRef);
38
+ this.extensions = inject(ExtensionsService);
39
+ this.list = inject(ListService);
40
+ this.canManage = this.permissionService.getGrantedPolicy(EXTRACT_PERMISSIONS.Documents.Templates.Default);
41
+ this.canExport = this.permissionService.getGrantedPolicy(EXTRACT_PERMISSIONS.Documents.Export);
42
+ this.formatOptions = exportFormatOptions;
43
+ this.ExportFormat = ExportFormat;
44
+ this.DocumentLifecycleStatus = DocumentLifecycleStatus;
45
+ this.lifecycleStatusOptions = documentLifecycleStatusOptions;
46
+ this.allTemplates = signal([], ...(ngDevMode ? [{ debugName: "allTemplates" }] : /* istanbul ignore next */ []));
47
+ this.templates = signal({ totalCount: 0, items: [] }, ...(ngDevMode ? [{ debugName: "templates" }] : /* istanbul ignore next */ []));
48
+ this.documentTypes = signal([], ...(ngDevMode ? [{ debugName: "documentTypes" }] : /* istanbul ignore next */ []));
49
+ this.fieldDefinitions = signal([], ...(ngDevMode ? [{ debugName: "fieldDefinitions" }] : /* istanbul ignore next */ []));
50
+ this.cabinets = signal([], ...(ngDevMode ? [{ debugName: "cabinets" }] : /* istanbul ignore next */ []));
51
+ this.isLoading = signal(true, ...(ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []));
52
+ this.editing = signal(null, ...(ngDevMode ? [{ debugName: "editing" }] : /* istanbul ignore next */ []));
53
+ this.isSubmitting = signal(false, ...(ngDevMode ? [{ debugName: "isSubmitting" }] : /* istanbul ignore next */ []));
54
+ this.exportingId = signal(null, ...(ngDevMode ? [{ debugName: "exportingId" }] : /* istanbul ignore next */ []));
55
+ /** Export template currently configuring filters; when non-null, show the filter modal. */
56
+ this.filteringTemplate = signal(null, ...(ngDevMode ? [{ debugName: "filteringTemplate" }] : /* istanbul ignore next */ []));
57
+ this.tableQuery = {};
58
+ this.filterForm = this.fb.nonNullable.group({
59
+ lifecycleStatus: [null],
60
+ cabinetId: [null],
61
+ creationTimeMin: [null],
62
+ creationTimeMax: [null],
63
+ });
64
+ this.form = this.fb.nonNullable.group({
65
+ name: ['', [Validators.required, Validators.maxLength(MAX_NAME_LENGTH)]],
66
+ format: [ExportFormat.Csv, [Validators.required]],
67
+ documentTypeId: ['', [Validators.required]],
68
+ columns: this.fb.array([]),
69
+ });
70
+ configureEntityTable(this.extensions, EXTRACT_TABLES.ExportTemplates, [
71
+ EntityProp.create({
72
+ type: "string" /* ePropType.String */,
73
+ name: 'name',
74
+ displayName: '::ExportTemplate:Name',
75
+ sortable: true,
76
+ }),
77
+ EntityProp.create({
78
+ type: "string" /* ePropType.String */,
79
+ name: 'format',
80
+ displayName: '::ExportTemplate:Format',
81
+ sortable: true,
82
+ columnWidth: 150,
83
+ valueResolver: data => {
84
+ const localization = data.getInjected(LocalizationService);
85
+ return of(`<span class="badge bg-secondary">${escapeHtmlChars(localization.instant('::ExportFormat:' + this.formatLabel(data.record.format)))}</span>`);
86
+ },
87
+ }),
88
+ EntityProp.create({
89
+ type: "string" /* ePropType.String */,
90
+ name: 'documentTypeId',
91
+ displayName: '::ExportTemplate:DocumentType',
92
+ sortable: true,
93
+ columnWidth: 220,
94
+ valueResolver: data => {
95
+ const label = this.documentTypeLabel(data.record.documentTypeId);
96
+ return of(label
97
+ ? `<span class="badge bg-info text-dark">${escapeHtmlChars(label)}</span>`
98
+ : '<span class="text-muted">-</span>');
99
+ },
100
+ }),
101
+ EntityProp.create({
102
+ type: "number" /* ePropType.Number */,
103
+ name: 'columns',
104
+ displayName: '::ExportTemplate:Columns',
105
+ sortable: true,
106
+ columnWidth: 150,
107
+ valueResolver: data => of(data.record.columns?.length ?? 0),
108
+ }),
109
+ ]);
110
+ }
111
+ ngOnInit() {
112
+ this.hookTableQuery();
113
+ this.load();
114
+ this.loadDocumentTypes();
115
+ this.loadCabinets();
116
+ }
117
+ refresh() {
118
+ this.load();
119
+ }
120
+ load() {
121
+ this.isLoading.set(true);
122
+ this.service
123
+ .getList()
124
+ .pipe(takeUntilDestroyed(this.destroyRef))
125
+ .subscribe({
126
+ next: list => {
127
+ this.allTemplates.set(list);
128
+ this.list.totalCount = list.length;
129
+ this.applyTableQuery();
130
+ this.isLoading.set(false);
131
+ },
132
+ error: () => {
133
+ this.allTemplates.set([]);
134
+ this.templates.set({ totalCount: 0, items: [] });
135
+ this.list.totalCount = 0;
136
+ this.isLoading.set(false);
137
+ },
138
+ });
139
+ }
140
+ hookTableQuery() {
141
+ this.list.query$
142
+ .pipe(takeUntilDestroyed(this.destroyRef))
143
+ .subscribe(query => this.applyTableQuery(query));
144
+ }
145
+ applyTableQuery(query = this.tableQuery) {
146
+ this.tableQuery = query;
147
+ this.templates.set(pageClientItems(this.allTemplates(), query, EXPORT_TEMPLATE_SORTS));
148
+ }
149
+ loadDocumentTypes() {
150
+ this.documentTypeService
151
+ .getVisible()
152
+ .pipe(takeUntilDestroyed(this.destroyRef))
153
+ .subscribe({
154
+ next: list => {
155
+ this.documentTypes.set(list);
156
+ this.applyTableQuery();
157
+ },
158
+ });
159
+ }
160
+ loadCabinets() {
161
+ this.cabinetService
162
+ .getList()
163
+ .pipe(takeUntilDestroyed(this.destroyRef))
164
+ .subscribe({ next: list => this.cabinets.set(list) });
165
+ }
166
+ openCreate() {
167
+ this.columns.clear();
168
+ this.fieldDefinitions.set([]);
169
+ this.form.reset({ name: '', format: ExportFormat.Csv, documentTypeId: '' });
170
+ this.addColumn();
171
+ this.editing.set('create');
172
+ }
173
+ openEdit(template) {
174
+ this.columns.clear();
175
+ this.form.reset({
176
+ name: template.name,
177
+ format: template.format,
178
+ documentTypeId: template.documentTypeId,
179
+ });
180
+ this.loadFieldDefinitions(template.documentTypeId);
181
+ [...(template.columns ?? [])]
182
+ .sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
183
+ .forEach(c => this.addColumn(c.fieldDefinitionId));
184
+ this.editing.set(template);
185
+ }
186
+ addColumn(fieldDefinitionId = '') {
187
+ this.columns.push(this.fb.nonNullable.group({
188
+ fieldDefinitionId: [fieldDefinitionId, [Validators.required]],
189
+ }));
190
+ }
191
+ removeColumn(index) {
192
+ this.columns.removeAt(index);
193
+ }
194
+ // Switching the document type invalidates already-picked field columns (they belong to the prior type).
195
+ onDocumentTypeChange() {
196
+ const documentTypeId = this.form.controls.documentTypeId.value;
197
+ this.columns.controls.forEach(ctrl => ctrl.get('fieldDefinitionId')?.setValue(''));
198
+ this.loadFieldDefinitions(documentTypeId);
199
+ }
200
+ loadFieldDefinitions(documentTypeId) {
201
+ if (!documentTypeId) {
202
+ this.fieldDefinitions.set([]);
203
+ return;
204
+ }
205
+ this.fieldDefinitionService
206
+ .getList({ documentTypeId })
207
+ .pipe(takeUntilDestroyed(this.destroyRef))
208
+ .subscribe({
209
+ next: defs => this.fieldDefinitions.set(defs),
210
+ error: () => this.fieldDefinitions.set([]),
211
+ });
212
+ }
213
+ closeModal() {
214
+ this.editing.set(null);
215
+ }
216
+ submit() {
217
+ if (this.form.invalid || this.columns.length === 0) {
218
+ this.form.markAllAsTouched();
219
+ return;
220
+ }
221
+ const mode = this.editing();
222
+ if (mode === null)
223
+ return;
224
+ this.isSubmitting.set(true);
225
+ const raw = this.form.getRawValue();
226
+ // Order = array position; the editor's row order is the source of truth.
227
+ const columns = this.columns.controls.map((ctrl, i) => {
228
+ const v = ctrl.getRawValue();
229
+ return { fieldDefinitionId: v.fieldDefinitionId, order: i };
230
+ });
231
+ if (mode === 'create') {
232
+ const input = {
233
+ name: raw.name,
234
+ format: raw.format,
235
+ documentTypeId: raw.documentTypeId,
236
+ columns,
237
+ };
238
+ this.service
239
+ .create(input)
240
+ .pipe(takeUntilDestroyed(this.destroyRef))
241
+ .subscribe({
242
+ next: () => this.onSaved('::ExportTemplate:CreatedSuccessfully'),
243
+ error: () => this.isSubmitting.set(false),
244
+ });
245
+ }
246
+ else {
247
+ this.service
248
+ .update(mode.id, {
249
+ name: raw.name,
250
+ format: raw.format,
251
+ documentTypeId: raw.documentTypeId,
252
+ columns,
253
+ })
254
+ .pipe(takeUntilDestroyed(this.destroyRef))
255
+ .subscribe({
256
+ next: () => this.onSaved('::ExportTemplate:UpdatedSuccessfully'),
257
+ error: () => this.isSubmitting.set(false),
258
+ });
259
+ }
260
+ }
261
+ onSaved(messageKey) {
262
+ this.isSubmitting.set(false);
263
+ this.closeModal();
264
+ this.toaster.success(messageKey, '::Success');
265
+ this.load();
266
+ }
267
+ delete(template) {
268
+ this.confirmation
269
+ .warn('::ExportTemplate:AreYouSureToDelete', '::AreYouSure')
270
+ .pipe(takeUntilDestroyed(this.destroyRef))
271
+ .subscribe(status => {
272
+ if (status !== Confirmation.Status.confirm)
273
+ return;
274
+ this.service
275
+ .delete(template.id)
276
+ .pipe(takeUntilDestroyed(this.destroyRef))
277
+ .subscribe({
278
+ next: () => {
279
+ this.toaster.success('::ExportTemplate:DeletedSuccessfully', '::Success');
280
+ this.load();
281
+ },
282
+ error: () => this.toaster.error('::ExportTemplate:DeleteFailed', '::Error'),
283
+ });
284
+ });
285
+ }
286
+ exportTemplate(template) {
287
+ this.filterForm.reset({ lifecycleStatus: null, cabinetId: null, creationTimeMin: null, creationTimeMax: null });
288
+ this.filteringTemplate.set(template);
289
+ }
290
+ closeFilterModal() {
291
+ this.filteringTemplate.set(null);
292
+ }
293
+ startExport() {
294
+ const template = this.filteringTemplate();
295
+ if (!template)
296
+ return;
297
+ const f = this.filterForm.getRawValue();
298
+ this.exportingId.set(template.id);
299
+ this.filteringTemplate.set(null);
300
+ this.service
301
+ .export({
302
+ templateId: template.id,
303
+ lifecycleStatus: f.lifecycleStatus ?? undefined,
304
+ cabinetId: f.cabinetId ?? undefined,
305
+ creationTimeMin: f.creationTimeMin ?? undefined,
306
+ creationTimeMax: f.creationTimeMax ?? undefined,
307
+ })
308
+ .pipe(takeUntilDestroyed(this.destroyRef))
309
+ .subscribe({
310
+ next: blob => {
311
+ const ext = template.format === ExportFormat.Xlsx ? '.xlsx' : '.csv';
312
+ this.triggerDownload(blob, template.name + ext);
313
+ this.exportingId.set(null);
314
+ },
315
+ error: () => this.exportingId.set(null),
316
+ });
317
+ }
318
+ triggerDownload(blob, fileName) {
319
+ const url = URL.createObjectURL(blob);
320
+ const anchor = document.createElement('a');
321
+ anchor.href = url;
322
+ anchor.download = fileName;
323
+ anchor.click();
324
+ // Defer revoke so the browser's download handler has taken ownership of the
325
+ // blob before its backing URL is released (avoids a race on large files).
326
+ setTimeout(() => URL.revokeObjectURL(url), 0);
327
+ }
328
+ formatLabel(format) {
329
+ return this.formatOptions.find(o => o.value === format)?.key ?? String(format);
330
+ }
331
+ documentTypeLabel(documentTypeId) {
332
+ return this.documentTypes().find(dt => dt.id === documentTypeId)?.typeCode ?? null;
333
+ }
334
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ExportTemplateListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
335
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ExportTemplateListComponent, isStandalone: true, selector: "lib-export-template-list", providers: [
336
+ ListService,
337
+ {
338
+ provide: EXTENSIONS_IDENTIFIER,
339
+ useValue: EXTRACT_TABLES.ExportTemplates,
340
+ },
341
+ ], ngImport: i0, template: "<div class=\"container-fluid py-4\">\n <!-- Header -->\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\n <h4 class=\"mb-0\">\n <i class=\"fas fa-file-export me-2\"></i>\n {{ '::ExportTemplate:Title' | abpLocalization }}\n </h4>\n <div class=\"d-flex gap-2\">\n <button\n class=\"btn btn-outline-secondary\"\n (click)=\"refresh()\"\n [disabled]=\"isLoading()\"\n title=\"{{ '::Refresh' | abpLocalization }}\"\n >\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"isLoading()\"></i>\n </button>\n @if (canManage) {\n <button class=\"btn btn-primary\" (click)=\"openCreate()\">\n <i class=\"fas fa-plus me-1\"></i>\n {{ '::ExportTemplate:New' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n\n @if (isLoading()) {\n <div class=\"text-center py-5\">\n <div class=\"spinner-border text-primary\" role=\"status\"></div>\n </div>\n }\n\n @if (!isLoading() && templates().totalCount === 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body text-center py-5\">\n <i class=\"fas fa-file-export fa-3x text-muted mb-3 d-block\"></i>\n <p class=\"text-muted mb-0\">{{ '::ExportTemplate:Empty' | abpLocalization }}</p>\n </div>\n </div>\n }\n\n @if (!isLoading() && templates().totalCount > 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body p-0\">\n <ng-template #actionsTemplate let-template>\n @if (canExport || canManage) {\n <div ngbDropdown container=\"body\" class=\"d-inline-block\">\n <button type=\"button\" class=\"btn btn-sm btn-primary\" ngbDropdownToggle>\n {{ 'AbpUi::Actions' | abpLocalization }}\n </button>\n <div ngbDropdownMenu>\n @if (canExport) {\n <button\n type=\"button\"\n ngbDropdownItem\n (click)=\"exportTemplate(template)\"\n [disabled]=\"exportingId() === template.id\"\n >\n @if (exportingId() === template.id) {\n <span class=\"spinner-border spinner-border-sm me-2\"></span>\n } @else {\n <i class=\"fas fa-download me-2\"></i>\n }\n {{ '::ExportTemplate:Export' | abpLocalization }}\n </button>\n }\n @if (canManage) {\n <button type=\"button\" ngbDropdownItem (click)=\"openEdit(template)\">\n <i class=\"fas fa-pen me-2\"></i>\n {{ '::Edit' | abpLocalization }}\n </button>\n <button type=\"button\" ngbDropdownItem (click)=\"delete(template)\">\n <i class=\"fas fa-trash me-2\"></i>\n {{ '::Delete' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n }\n </ng-template>\n\n <abp-extensible-table\n [data]=\"templates().items\"\n [recordsTotal]=\"templates().totalCount\"\n [list]=\"list\"\n [actionsTemplate]=\"actionsTemplate\"\n actionsText=\"AbpUi::Actions\"\n [actionsColumnWidth]=\"150\"\n />\n </div>\n </div>\n }\n</div>\n\n<!-- Export filter modal -->\n@if (filteringTemplate(); as tmpl) {\n <div class=\"modal d-block\" tabindex=\"-1\" style=\"background:rgba(0,0,0,.4);\" (click)=\"closeFilterModal()\">\n <div class=\"modal-dialog modal-dialog-centered\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-content\">\n <form [formGroup]=\"filterForm\" (ngSubmit)=\"startExport()\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-filter me-2\"></i>\n {{ '::ExportTemplate:FilterAndExport' | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"closeFilterModal()\"></button>\n </div>\n <div class=\"modal-body\">\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::Document:Status' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"lifecycleStatus\">\n <option [ngValue]=\"null\">{{ '::Document:Filter:AllStatuses' | abpLocalization }}</option>\n @for (opt of lifecycleStatusOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ '::Document:Status:' + opt.key | abpLocalization }}</option>\n }\n </select>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::Document:Cabinet' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"cabinetId\">\n <option [ngValue]=\"null\">{{ '::Document:Filter:AllCabinets' | abpLocalization }}</option>\n @for (c of cabinets(); track c.id) {\n <option [value]=\"c.id\">{{ c.name }}</option>\n }\n </select>\n </div>\n <div class=\"row g-2\">\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::ExportTemplate:Filter:DateFrom' | abpLocalization }}</label>\n <input type=\"date\" class=\"form-control\" formControlName=\"creationTimeMin\" />\n </div>\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::ExportTemplate:Filter:DateTo' | abpLocalization }}</label>\n <input type=\"date\" class=\"form-control\" formControlName=\"creationTimeMax\" />\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"closeFilterModal()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button type=\"submit\" class=\"btn btn-success\">\n <i class=\"fas fa-download me-1\"></i>\n {{ '::ExportTemplate:Export' | abpLocalization }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n\n<!-- Create / Edit modal -->\n@if (editing(); as mode) {\n <div class=\"modal d-block\" tabindex=\"-1\" style=\"background:rgba(0,0,0,.4);\" (click)=\"closeModal()\">\n <div class=\"modal-dialog modal-dialog-centered modal-lg\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-content\">\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-file-export me-2\"></i>\n {{ (mode === 'create' ? '::ExportTemplate:New' : '::ExportTemplate:Edit') | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"closeModal()\"></button>\n </div>\n <div class=\"modal-body\">\n <div class=\"row g-3 mb-3\">\n <div class=\"col-md-5\">\n <label class=\"form-label\">{{ '::ExportTemplate:Name' | abpLocalization }}</label>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"name\"\n [class.is-invalid]=\"form.controls.name.touched && form.controls.name.invalid\"\n />\n </div>\n <div class=\"col-md-3\">\n <label class=\"form-label\">{{ '::ExportTemplate:Format' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"format\">\n @for (opt of formatOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ '::ExportFormat:' + opt.key | abpLocalization }}</option>\n }\n </select>\n </div>\n <div class=\"col-md-4\">\n <label class=\"form-label\">{{ '::ExportTemplate:DocumentType' | abpLocalization }}</label>\n <select\n class=\"form-select\"\n formControlName=\"documentTypeId\"\n (change)=\"onDocumentTypeChange()\"\n >\n <option value=\"\" disabled>{{ '::ExportTemplate:DocumentType' | abpLocalization }}</option>\n @for (dt of documentTypes(); track dt.id) {\n <option [value]=\"dt.id\">{{ dt.displayName }} ({{ dt.typeCode }})</option>\n }\n </select>\n </div>\n </div>\n\n <label class=\"form-label d-flex justify-content-between align-items-center\">\n <span>{{ '::ExportTemplate:Columns' | abpLocalization }}</span>\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"addColumn()\">\n <i class=\"fas fa-plus me-1\"></i>{{ '::ExportTemplate:AddColumn' | abpLocalization }}\n </button>\n </label>\n\n @if (columns.length === 0) {\n <p class=\"text-muted small\">{{ '::ExportTemplate:NoColumns' | abpLocalization }}</p>\n }\n\n <div formArrayName=\"columns\">\n @for (col of columns.controls; track $index) {\n <div class=\"row g-2 mb-2 align-items-center\" [formGroupName]=\"$index\">\n <div class=\"col-11\">\n <select class=\"form-select form-select-sm\" formControlName=\"fieldDefinitionId\">\n <option value=\"\" disabled>\n {{ '::ExportTemplate:ColumnKey' | abpLocalization }}\n </option>\n @for (fd of fieldDefinitions(); track fd.id) {\n <option [value]=\"fd.id\">{{ fd.displayName }} ({{ fd.name }})</option>\n }\n </select>\n </div>\n <div class=\"col-1 text-end\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-danger\"\n (click)=\"removeColumn($index)\"\n title=\"{{ '::Delete' | abpLocalization }}\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"closeModal()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"form.invalid || columns.length === 0 || isSubmitting()\"\n >\n @if (isSubmitting()) {\n <span class=\"spinner-border spinner-border-sm me-1\"></span>\n }\n {{ '::Save' | abpLocalization }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: ExtensibleTableComponent, selector: "abp-extensible-table", inputs: ["actionsText", "data", "list", "recordsTotal", "actionsColumnWidth", "actionsTemplate", "selectable", "selectionType", "selected", "infiniteScroll", "isLoading", "scrollThreshold", "tableHeight", "rowDetailTemplate", "rowDetailHeight"], outputs: ["tableActivate", "selectionChange", "loadMore", "rowDetailToggle"], exportAs: ["abpExtensibleTable"] }, { kind: "ngmodule", type: NgbDropdownModule }, { kind: "directive", type: i2.NgbDropdown, selector: "[ngbDropdown]", inputs: ["autoClose", "dropdownClass", "open", "placement", "popperOptions", "container", "display"], outputs: ["openChange"], exportAs: ["ngbDropdown"] }, { kind: "directive", type: i2.NgbDropdownToggle, selector: "[ngbDropdownToggle]" }, { kind: "directive", type: i2.NgbDropdownMenu, selector: "[ngbDropdownMenu]" }, { kind: "directive", type: i2.NgbDropdownItem, selector: "[ngbDropdownItem]", inputs: ["tabindex", "disabled"] }, { kind: "directive", type: i2.NgbDropdownButtonItem, selector: "button[ngbDropdownItem]" }, { kind: "pipe", type: LocalizationPipe, name: "abpLocalization" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
342
+ }
343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ExportTemplateListComponent, decorators: [{
344
+ type: Component,
345
+ args: [{ selector: 'lib-export-template-list', imports: [
346
+ CommonModule,
347
+ ReactiveFormsModule,
348
+ LocalizationPipe,
349
+ ExtensibleTableComponent,
350
+ NgbDropdownModule,
351
+ ], providers: [
352
+ ListService,
353
+ {
354
+ provide: EXTENSIONS_IDENTIFIER,
355
+ useValue: EXTRACT_TABLES.ExportTemplates,
356
+ },
357
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"container-fluid py-4\">\n <!-- Header -->\n <div class=\"d-flex justify-content-between align-items-center mb-3\">\n <h4 class=\"mb-0\">\n <i class=\"fas fa-file-export me-2\"></i>\n {{ '::ExportTemplate:Title' | abpLocalization }}\n </h4>\n <div class=\"d-flex gap-2\">\n <button\n class=\"btn btn-outline-secondary\"\n (click)=\"refresh()\"\n [disabled]=\"isLoading()\"\n title=\"{{ '::Refresh' | abpLocalization }}\"\n >\n <i class=\"fas fa-sync-alt\" [class.fa-spin]=\"isLoading()\"></i>\n </button>\n @if (canManage) {\n <button class=\"btn btn-primary\" (click)=\"openCreate()\">\n <i class=\"fas fa-plus me-1\"></i>\n {{ '::ExportTemplate:New' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n\n @if (isLoading()) {\n <div class=\"text-center py-5\">\n <div class=\"spinner-border text-primary\" role=\"status\"></div>\n </div>\n }\n\n @if (!isLoading() && templates().totalCount === 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body text-center py-5\">\n <i class=\"fas fa-file-export fa-3x text-muted mb-3 d-block\"></i>\n <p class=\"text-muted mb-0\">{{ '::ExportTemplate:Empty' | abpLocalization }}</p>\n </div>\n </div>\n }\n\n @if (!isLoading() && templates().totalCount > 0) {\n <div class=\"card shadow-sm\">\n <div class=\"card-body p-0\">\n <ng-template #actionsTemplate let-template>\n @if (canExport || canManage) {\n <div ngbDropdown container=\"body\" class=\"d-inline-block\">\n <button type=\"button\" class=\"btn btn-sm btn-primary\" ngbDropdownToggle>\n {{ 'AbpUi::Actions' | abpLocalization }}\n </button>\n <div ngbDropdownMenu>\n @if (canExport) {\n <button\n type=\"button\"\n ngbDropdownItem\n (click)=\"exportTemplate(template)\"\n [disabled]=\"exportingId() === template.id\"\n >\n @if (exportingId() === template.id) {\n <span class=\"spinner-border spinner-border-sm me-2\"></span>\n } @else {\n <i class=\"fas fa-download me-2\"></i>\n }\n {{ '::ExportTemplate:Export' | abpLocalization }}\n </button>\n }\n @if (canManage) {\n <button type=\"button\" ngbDropdownItem (click)=\"openEdit(template)\">\n <i class=\"fas fa-pen me-2\"></i>\n {{ '::Edit' | abpLocalization }}\n </button>\n <button type=\"button\" ngbDropdownItem (click)=\"delete(template)\">\n <i class=\"fas fa-trash me-2\"></i>\n {{ '::Delete' | abpLocalization }}\n </button>\n }\n </div>\n </div>\n }\n </ng-template>\n\n <abp-extensible-table\n [data]=\"templates().items\"\n [recordsTotal]=\"templates().totalCount\"\n [list]=\"list\"\n [actionsTemplate]=\"actionsTemplate\"\n actionsText=\"AbpUi::Actions\"\n [actionsColumnWidth]=\"150\"\n />\n </div>\n </div>\n }\n</div>\n\n<!-- Export filter modal -->\n@if (filteringTemplate(); as tmpl) {\n <div class=\"modal d-block\" tabindex=\"-1\" style=\"background:rgba(0,0,0,.4);\" (click)=\"closeFilterModal()\">\n <div class=\"modal-dialog modal-dialog-centered\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-content\">\n <form [formGroup]=\"filterForm\" (ngSubmit)=\"startExport()\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-filter me-2\"></i>\n {{ '::ExportTemplate:FilterAndExport' | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"closeFilterModal()\"></button>\n </div>\n <div class=\"modal-body\">\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::Document:Status' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"lifecycleStatus\">\n <option [ngValue]=\"null\">{{ '::Document:Filter:AllStatuses' | abpLocalization }}</option>\n @for (opt of lifecycleStatusOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ '::Document:Status:' + opt.key | abpLocalization }}</option>\n }\n </select>\n </div>\n <div class=\"mb-3\">\n <label class=\"form-label\">{{ '::Document:Cabinet' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"cabinetId\">\n <option [ngValue]=\"null\">{{ '::Document:Filter:AllCabinets' | abpLocalization }}</option>\n @for (c of cabinets(); track c.id) {\n <option [value]=\"c.id\">{{ c.name }}</option>\n }\n </select>\n </div>\n <div class=\"row g-2\">\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::ExportTemplate:Filter:DateFrom' | abpLocalization }}</label>\n <input type=\"date\" class=\"form-control\" formControlName=\"creationTimeMin\" />\n </div>\n <div class=\"col-6\">\n <label class=\"form-label\">{{ '::ExportTemplate:Filter:DateTo' | abpLocalization }}</label>\n <input type=\"date\" class=\"form-control\" formControlName=\"creationTimeMax\" />\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"closeFilterModal()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button type=\"submit\" class=\"btn btn-success\">\n <i class=\"fas fa-download me-1\"></i>\n {{ '::ExportTemplate:Export' | abpLocalization }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n\n<!-- Create / Edit modal -->\n@if (editing(); as mode) {\n <div class=\"modal d-block\" tabindex=\"-1\" style=\"background:rgba(0,0,0,.4);\" (click)=\"closeModal()\">\n <div class=\"modal-dialog modal-dialog-centered modal-lg\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-content\">\n <form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n <div class=\"modal-header\">\n <h5 class=\"modal-title\">\n <i class=\"fas fa-file-export me-2\"></i>\n {{ (mode === 'create' ? '::ExportTemplate:New' : '::ExportTemplate:Edit') | abpLocalization }}\n </h5>\n <button type=\"button\" class=\"btn-close\" (click)=\"closeModal()\"></button>\n </div>\n <div class=\"modal-body\">\n <div class=\"row g-3 mb-3\">\n <div class=\"col-md-5\">\n <label class=\"form-label\">{{ '::ExportTemplate:Name' | abpLocalization }}</label>\n <input\n type=\"text\"\n class=\"form-control\"\n formControlName=\"name\"\n [class.is-invalid]=\"form.controls.name.touched && form.controls.name.invalid\"\n />\n </div>\n <div class=\"col-md-3\">\n <label class=\"form-label\">{{ '::ExportTemplate:Format' | abpLocalization }}</label>\n <select class=\"form-select\" formControlName=\"format\">\n @for (opt of formatOptions; track opt.value) {\n <option [ngValue]=\"opt.value\">{{ '::ExportFormat:' + opt.key | abpLocalization }}</option>\n }\n </select>\n </div>\n <div class=\"col-md-4\">\n <label class=\"form-label\">{{ '::ExportTemplate:DocumentType' | abpLocalization }}</label>\n <select\n class=\"form-select\"\n formControlName=\"documentTypeId\"\n (change)=\"onDocumentTypeChange()\"\n >\n <option value=\"\" disabled>{{ '::ExportTemplate:DocumentType' | abpLocalization }}</option>\n @for (dt of documentTypes(); track dt.id) {\n <option [value]=\"dt.id\">{{ dt.displayName }} ({{ dt.typeCode }})</option>\n }\n </select>\n </div>\n </div>\n\n <label class=\"form-label d-flex justify-content-between align-items-center\">\n <span>{{ '::ExportTemplate:Columns' | abpLocalization }}</span>\n <button type=\"button\" class=\"btn btn-sm btn-outline-primary\" (click)=\"addColumn()\">\n <i class=\"fas fa-plus me-1\"></i>{{ '::ExportTemplate:AddColumn' | abpLocalization }}\n </button>\n </label>\n\n @if (columns.length === 0) {\n <p class=\"text-muted small\">{{ '::ExportTemplate:NoColumns' | abpLocalization }}</p>\n }\n\n <div formArrayName=\"columns\">\n @for (col of columns.controls; track $index) {\n <div class=\"row g-2 mb-2 align-items-center\" [formGroupName]=\"$index\">\n <div class=\"col-11\">\n <select class=\"form-select form-select-sm\" formControlName=\"fieldDefinitionId\">\n <option value=\"\" disabled>\n {{ '::ExportTemplate:ColumnKey' | abpLocalization }}\n </option>\n @for (fd of fieldDefinitions(); track fd.id) {\n <option [value]=\"fd.id\">{{ fd.displayName }} ({{ fd.name }})</option>\n }\n </select>\n </div>\n <div class=\"col-1 text-end\">\n <button\n type=\"button\"\n class=\"btn btn-sm btn-outline-danger\"\n (click)=\"removeColumn($index)\"\n title=\"{{ '::Delete' | abpLocalization }}\"\n >\n <i class=\"fas fa-times\"></i>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"closeModal()\">\n {{ '::Cancel' | abpLocalization }}\n </button>\n <button\n type=\"submit\"\n class=\"btn btn-primary\"\n [disabled]=\"form.invalid || columns.length === 0 || isSubmitting()\"\n >\n @if (isSubmitting()) {\n <span class=\"spinner-border spinner-border-sm me-1\"></span>\n }\n {{ '::Save' | abpLocalization }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n}\n", styles: [":host{display:block}\n"] }]
358
+ }], ctorParameters: () => [] });
359
+
360
+ export { ExportTemplateListComponent };
361
+ //# sourceMappingURL=dignite-vault-extract-documents-export-template-list.component-DlmZFFF1.mjs.map