@maro-tech/card 0.1.18 → 0.2.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,4 +1,4 @@
1
- import * as i1$1 from '@angular/common';
1
+ import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { input, inject, DestroyRef, signal, Component, computed, viewChild, viewChildren, output, effect, HostListener, Input, InjectionToken, forwardRef, Injectable, ViewChild, untracked } from '@angular/core';
@@ -6,14 +6,13 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
6
6
  import { EventBus, UiButtonComponent, UiToastService, UiModalComponent, UiConfirmService } from '@maro-tech/core';
7
7
  import { DomSanitizer } from '@angular/platform-browser';
8
8
  import Panzoom from '@panzoom/panzoom';
9
- import * as i1 from 'lucide-angular';
10
- import { Download, LucideAngularModule, Eye, FileText, Plus, Sparkles, Trash } from 'lucide-angular';
9
+ import { LucideDownload, LucideDynamicIcon, LucideEye, LucideFileText, LucidePlus, LucideSparkles, LucideTrash } from '@lucide/angular';
11
10
  import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
12
11
  import { map, shareReplay, forkJoin, switchMap, timer, of, firstValueFrom } from 'rxjs';
13
12
  import { UiTableComponent } from '@maro-tech/table';
14
13
  import { ActivatedRoute, Router, RouterLink } from '@angular/router';
15
14
  import { map as map$1, exhaustMap, catchError, takeWhile, takeUntil, finalize } from 'rxjs/operators';
16
- import * as i1$2 from '@angular/forms';
15
+ import * as i1$1 from '@angular/forms';
17
16
  import { FormsModule } from '@angular/forms';
18
17
  import { InputSelectComponent } from '@maro-tech/form';
19
18
 
@@ -117,8 +116,8 @@ class CardSectionHeaderComponent {
117
116
  return this.actions().some((action) => action.context?.entity === context.entity
118
117
  && (!context.recordId || action.context?.recordId === context.recordId));
119
118
  }
120
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardSectionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
121
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CardSectionHeaderComponent, isStandalone: true, selector: "app-card-section-header", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
119
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardSectionHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
120
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: CardSectionHeaderComponent, isStandalone: true, selector: "app-card-section-header", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
122
121
  @if (variant() === 'tabs') {
123
122
  <header class="mb-4 flex justify-end">
124
123
  <div class="flex flex-wrap gap-2 md:justify-end">
@@ -170,7 +169,7 @@ class CardSectionHeaderComponent {
170
169
  }
171
170
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }] });
172
171
  }
173
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardSectionHeaderComponent, decorators: [{
172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardSectionHeaderComponent, decorators: [{
174
173
  type: Component,
175
174
  args: [{
176
175
  selector: 'app-card-section-header',
@@ -281,16 +280,16 @@ class CardHtmlTabComponent {
281
280
  return null;
282
281
  }
283
282
  }
284
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardHtmlTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
285
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.20", type: CardHtmlTabComponent, isStandalone: true, selector: "app-card-html-tab", inputs: { html: { classPropertyName: "html", publicName: "html", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section\n (click)=\"onClick($event)\"\n (keydown.enter)=\"onKeydown($event)\"\n (keydown.space)=\"onKeydown($event)\"\n>\n <div [innerHTML]=\"safeHtml()\"></div>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
283
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardHtmlTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
284
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.24", type: CardHtmlTabComponent, isStandalone: true, selector: "app-card-html-tab", inputs: { html: { classPropertyName: "html", publicName: "html", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section\n (click)=\"onClick($event)\"\n (keydown.enter)=\"onKeydown($event)\"\n (keydown.space)=\"onKeydown($event)\"\n>\n <div [innerHTML]=\"safeHtml()\"></div>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }] });
286
285
  }
287
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardHtmlTabComponent, decorators: [{
286
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardHtmlTabComponent, decorators: [{
288
287
  type: Component,
289
288
  args: [{ selector: 'app-card-html-tab', standalone: true, imports: [CommonModule], template: "<section\n (click)=\"onClick($event)\"\n (keydown.enter)=\"onKeydown($event)\"\n (keydown.space)=\"onKeydown($event)\"\n>\n <div [innerHTML]=\"safeHtml()\"></div>\n</section>\n" }]
290
289
  }], propDecorators: { html: [{ type: i0.Input, args: [{ isSignal: true, alias: "html", required: false }] }] } });
291
290
 
292
291
  class ImagesViewerComponent {
293
- downloadIcon = Download;
292
+ downloadIcon = LucideDownload;
294
293
  urls = input([], ...(ngDevMode ? [{ debugName: "urls" }] : /* istanbul ignore next */ []));
295
294
  initialIndex = input(0, ...(ngDevMode ? [{ debugName: "initialIndex" }] : /* istanbul ignore next */ []));
296
295
  currentIndex = signal(0, ...(ngDevMode ? [{ debugName: "currentIndex" }] : /* istanbul ignore next */ []));
@@ -482,12 +481,12 @@ class ImagesViewerComponent {
482
481
  getOriginalUrl(url) {
483
482
  return String(url || '').replace(/\/preview(?:\?[^#]*)?$/i, '');
484
483
  }
485
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ImagesViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
486
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ImagesViewerComponent, isStandalone: true, selector: "app-images-viewer", inputs: { urls: { classPropertyName: "urls", publicName: "urls", isSignal: true, isRequired: false, transformFunction: null }, initialIndex: { classPropertyName: "initialIndex", publicName: "initialIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscape()", "document:keydown.arrowleft": "onArrowLeft()", "document:keydown.arrowright": "onArrowRight()" } }, viewQueries: [{ propertyName: "currentImage", first: true, predicate: ["currentImage"], descendants: true, isSignal: true }, { propertyName: "thumbnailButtons", predicate: ["thumbnailButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <lucide-icon [img]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></lucide-icon>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }] });
484
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesViewerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
485
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: ImagesViewerComponent, isStandalone: true, selector: "app-images-viewer", inputs: { urls: { classPropertyName: "urls", publicName: "urls", isSignal: true, isRequired: false, transformFunction: null }, initialIndex: { classPropertyName: "initialIndex", publicName: "initialIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, host: { listeners: { "document:keydown.escape": "onEscape()", "document:keydown.arrowleft": "onArrowLeft()", "document:keydown.arrowright": "onArrowRight()" } }, viewQueries: [{ propertyName: "currentImage", first: true, predicate: ["currentImage"], descendants: true, isSignal: true }, { propertyName: "thumbnailButtons", predicate: ["thumbnailButton"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <svg [lucideIcon]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></svg>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }] });
487
486
  }
488
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ImagesViewerComponent, decorators: [{
487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesViewerComponent, decorators: [{
489
488
  type: Component,
490
- args: [{ selector: 'app-images-viewer', standalone: true, imports: [CommonModule, LucideAngularModule], template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <lucide-icon [img]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></lucide-icon>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n" }]
489
+ args: [{ selector: 'app-images-viewer', standalone: true, imports: [CommonModule, LucideDynamicIcon], template: "<div class=\"fixed inset-0 z-[2300] flex items-center justify-center bg-black/80 p-3 md:p-4\" role=\"dialog\" aria-modal=\"true\" aria-label=\"\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0444\u043E\u0442\u043E\">\n <button type=\"button\" class=\"absolute inset-0\" aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438 \u043F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\" (click)=\"closeViewer()\"></button>\n <div class=\"relative z-[1] flex h-full w-full max-w-[1500px] flex-col items-center justify-center gap-4\" (click)=\"$event.stopPropagation()\">\n <button\n type=\"button\"\n class=\"absolute right-2 top-2 z-20 inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white md:right-3 md:top-3\"\n aria-label=\"\u0417\u0430\u043A\u0440\u0438\u0442\u0438\"\n (click)=\"closeViewer()\">\n \u2715\n </button>\n\n <div\n class=\"relative flex min-h-0 w-full flex-1 items-center justify-center overflow-hidden rounded-[18px]\"\n (touchstart)=\"onTouchStart($event)\"\n (touchend)=\"onTouchEnd($event)\">\n <div class=\"h-full w-full overflow-hidden rounded-[18px]\">\n <div\n class=\"flex h-full w-full\"\n style=\"will-change: transform; backface-visibility: hidden;\"\n [style.transition]=\"imageViewerTransitionStyle\"\n [style.transform]=\"imageViewerTransform\">\n @for (url of urls(); track $index; let idx = $index) {\n <div class=\"flex h-full w-full min-w-full shrink-0 items-center justify-center overflow-hidden\" (wheel)=\"onWheel($event)\">\n @if (isPreloadIndex(idx)) {\n @if (idx === currentIndex() && isOriginalVisible() && originalPreviewUnavailable()) {\n <div class=\"max-w-md rounded-2xl bg-white/95 px-6 py-5 text-center text-sm text-slate-700 shadow-xl\">\n <p class=\"font-semibold text-slate-900\">\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u0443 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0438\u0439</p>\n <p class=\"mt-1\">\u0426\u0435\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u0436\u043D\u0430 \u043B\u0438\u0448\u0435 \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438.</p>\n </div>\n } @else {\n @if (idx === currentIndex()) {\n <img\n #currentImage\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"eager\"\n decoding=\"async\"\n (load)=\"onImageLoad()\"\n (error)=\"onImageError(idx)\"\n (dblclick)=\"toggleZoom()\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n } @else {\n <img\n [src]=\"getImageUrl(url, idx)\"\n [attr.alt]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n loading=\"lazy\"\n decoding=\"async\"\n (error)=\"onImageError(idx)\"\n class=\"block max-h-[74vh] max-w-[96vw] object-contain md:max-h-[78vh]\">\n }\n }\n }\n </div>\n }\n </div>\n </div>\n\n @if (urls().length > 1) {\n <button type=\"button\" class=\"absolute left-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:left-3\" aria-label=\"\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0454 \u0444\u043E\u0442\u043E\" (click)=\"showPreviousImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u2039</span>\n </button>\n <button type=\"button\" class=\"absolute right-2 top-1/2 z-10 inline-flex h-11 w-11 -translate-y-1/2 items-center justify-center rounded-full md:right-3\" aria-label=\"\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0435 \u0444\u043E\u0442\u043E\" (click)=\"showNextImage()\">\n <span class=\"inline-flex h-11 w-11 items-center justify-center rounded-full bg-white/90 text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.22)] transition hover:bg-white\">\u203A</span>\n </button>\n }\n\n @if (currentUrl) {\n <div class=\"absolute bottom-3 right-3 z-20 inline-flex max-w-[calc(100%-1.5rem)] items-center gap-1.5 rounded-2xl bg-black/55 p-1.5 text-white shadow-[0_12px_28px_rgba(15,23,42,0.24)] backdrop-blur-md md:bottom-4 md:right-4\">\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u0431\u0456\u043B\u044C\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomIn()\">+</button>\n <button type=\"button\" class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl text-lg transition hover:bg-white/10\" aria-label=\"\u0417\u043C\u0435\u043D\u0448\u0438\u0442\u0438 \u0444\u043E\u0442\u043E\" (click)=\"zoomOut()\">\u2212</button>\n <button type=\"button\" class=\"inline-flex h-9 items-center justify-center rounded-xl px-2 text-xs font-semibold transition hover:bg-white/10\" aria-label=\"\u0421\u043A\u0438\u043D\u0443\u0442\u0438 \u043C\u0430\u0441\u0448\u0442\u0430\u0431\" (click)=\"resetZoom()\">100%</button>\n <button\n type=\"button\"\n class=\"inline-flex h-9 items-center gap-2 rounded-xl px-2.5 text-xs font-semibold transition hover:bg-white/10\"\n [class.bg-emerald-500\\/20]=\"isOriginalVisible()\"\n [class.text-emerald-100]=\"isOriginalVisible()\"\n [attr.aria-pressed]=\"isOriginalVisible()\"\n aria-label=\"\u041F\u0435\u0440\u0435\u043C\u043A\u043D\u0443\u0442\u0438 \u043C\u0456\u0436 \u043F\u0440\u0435\u0432\u2019\u044E \u0442\u0430 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B\u043E\u043C\"\n (click)=\"toggleOriginal()\">\n <span>\u041E\u0440\u0438\u0433\u0456\u043D\u0430\u043B</span>\n <span\n class=\"relative inline-flex h-5 w-9 items-center rounded-full border p-0.5 transition-colors\"\n [class.bg-emerald-500]=\"isOriginalVisible()\"\n [class.bg-white\\/15]=\"!isOriginalVisible()\"\n [class.border-emerald-200]=\"isOriginalVisible()\"\n [class.border-white\\/45]=\"!isOriginalVisible()\"\n [class.ring-2]=\"isOriginalVisible()\"\n [class.ring-emerald-300\\/70]=\"isOriginalVisible()\">\n <span\n class=\"h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200\"\n [class.translate-x-4]=\"isOriginalVisible()\">\n </span>\n </span>\n </button>\n <a\n class=\"inline-flex h-9 w-9 items-center justify-center rounded-xl transition hover:bg-white/10\"\n [href]=\"getOriginalUrl(currentUrl)\"\n download\n aria-label=\"\u0421\u043A\u0430\u0447\u0430\u0442\u0438 \u043E\u0440\u0438\u0433\u0456\u043D\u0430\u043B \u0444\u043E\u0442\u043E\">\n <svg [lucideIcon]=\"downloadIcon\" [size]=\"19\" [strokeWidth]=\"2.25\"></svg>\n </a>\n </div>\n }\n </div>\n\n @if (urls().length > 1) {\n <div class=\"flex w-full flex-col items-center gap-3 pb-1 md:pb-2\">\n <div class=\"flex w-full max-w-[92vw] flex-nowrap justify-start gap-2 overflow-x-auto overflow-y-hidden overscroll-x-contain px-2 py-3 md:max-w-[80vw]\">\n @for (url of urls(); track url; let idx = $index) {\n <button\n #thumbnailButton\n type=\"button\"\n class=\"h-14 w-14 shrink-0 overflow-hidden rounded-xl border-2 border-transparent bg-white p-1 transition-transform duration-200\"\n [class.border-slate-900]=\"idx === currentIndex()\"\n [class.mx-2]=\"idx === currentIndex()\"\n [style.transform]=\"idx === currentIndex() ? 'scale(1.4)' : 'scale(1)'\"\n [class.origin-center]=\"idx === currentIndex()\"\n [class.relative]=\"idx === currentIndex()\"\n [class.z-10]=\"idx === currentIndex()\"\n [attr.aria-current]=\"idx === currentIndex() ? 'true' : null\"\n [attr.aria-label]=\"'\u0424\u043E\u0442\u043E ' + (idx + 1)\"\n (click)=\"selectImage(idx, $event)\">\n <img class=\"block aspect-square w-full rounded-lg object-contain\" [src]=\"getThumbnailUrl(url)\" [attr.alt]=\"'\u041C\u0456\u043D\u0456\u0430\u0442\u044E\u0440\u0430 ' + (idx + 1)\" loading=\"lazy\" decoding=\"async\">\n </button>\n }\n </div>\n <div class=\"rounded-full bg-white/95 px-3 py-1.5 text-xs font-semibold text-slate-900 shadow-[0_12px_28px_rgba(15,23,42,0.2)]\">\n {{ currentIndex() + 1 }} / {{ urls().length }}\n </div>\n </div>\n }\n </div>\n</div>\n" }]
491
490
  }], ctorParameters: () => [], propDecorators: { urls: [{ type: i0.Input, args: [{ isSignal: true, alias: "urls", required: false }] }], initialIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialIndex", required: false }] }], currentImage: [{ type: i0.ViewChild, args: ['currentImage', { isSignal: true }] }], thumbnailButtons: [{ type: i0.ViewChildren, args: ['thumbnailButton', { isSignal: true }] }], closed: [{ type: i0.Output, args: ["closed"] }], onEscape: [{
492
491
  type: HostListener,
493
492
  args: ['document:keydown.escape']
@@ -611,10 +610,10 @@ class DetailsGridComponent {
611
610
  ? { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }
612
611
  : { day: '2-digit', month: '2-digit', year: 'numeric' }).format(date);
613
612
  }
614
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DetailsGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
615
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DetailsGridComponent, isStandalone: true, selector: "app-details-grid", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"grid gap-4\" [class.grid-cols-1]=\"!hasExplicitColumns()\" [class.sm:grid-cols-3]=\"!hasExplicitColumns()\" [class.sm:grid-cols-12]=\"hasExplicitColumns()\">\n @for (field of displayFields(); track $index) {\n <div class=\"rounded-2xl border border-slate-100 bg-slate-200 p-4\" [ngClass]=\"getFieldColumnClass(field)\" [class.flex]=\"field.type === 'image'\" [class.flex-col]=\"field.type === 'image'\" [class.min-h-64]=\"field.type === 'image'\">\n <p class=\"text-xs uppercase tracking-[0.18em] text-slate-500\">{{ field.label }}</p>\n @if (field.type === 'image') {\n @if (field.imageSrc) {\n <button type=\"button\" class=\"mt-2 block flex-1 cursor-zoom-in overflow-hidden rounded-xl border border-slate-200 bg-white\" [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 ' + field.label\" (click)=\"openViewer(field.imageSrc)\">\n <img [src]=\"field.imageSrc\" [alt]=\"field.label\" class=\"h-full w-full object-cover\" />\n </button>\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">-</p>\n }\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">{{ field.displayValue ?? '-' }}</p>\n }\n </div>\n }\n</div>\n\n@if (selectedImageSrc(); as imageSrc) {\n <app-images-viewer [urls]=\"[imageSrc]\" (closed)=\"closeViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
613
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DetailsGridComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
614
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DetailsGridComponent, isStandalone: true, selector: "app-details-grid", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"grid gap-4\" [class.grid-cols-1]=\"!hasExplicitColumns()\" [class.sm:grid-cols-3]=\"!hasExplicitColumns()\" [class.sm:grid-cols-12]=\"hasExplicitColumns()\">\n @for (field of displayFields(); track $index) {\n <div class=\"rounded-2xl border border-slate-100 bg-slate-200 p-4\" [ngClass]=\"getFieldColumnClass(field)\" [class.flex]=\"field.type === 'image'\" [class.flex-col]=\"field.type === 'image'\" [class.min-h-64]=\"field.type === 'image'\">\n <p class=\"text-xs uppercase tracking-[0.18em] text-slate-500\">{{ field.label }}</p>\n @if (field.type === 'image') {\n @if (field.imageSrc) {\n <button type=\"button\" class=\"mt-2 block flex-1 cursor-zoom-in overflow-hidden rounded-xl border border-slate-200 bg-white\" [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 ' + field.label\" (click)=\"openViewer(field.imageSrc)\">\n <img [src]=\"field.imageSrc\" [alt]=\"field.label\" class=\"h-full w-full object-cover\" />\n </button>\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">-</p>\n }\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">{{ field.displayValue ?? '-' }}</p>\n }\n </div>\n }\n</div>\n\n@if (selectedImageSrc(); as imageSrc) {\n <app-images-viewer [urls]=\"[imageSrc]\" (closed)=\"closeViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
616
615
  }
617
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DetailsGridComponent, decorators: [{
616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DetailsGridComponent, decorators: [{
618
617
  type: Component,
619
618
  args: [{ selector: 'app-details-grid', standalone: true, imports: [CommonModule, ImagesViewerComponent], template: "<div class=\"grid gap-4\" [class.grid-cols-1]=\"!hasExplicitColumns()\" [class.sm:grid-cols-3]=\"!hasExplicitColumns()\" [class.sm:grid-cols-12]=\"hasExplicitColumns()\">\n @for (field of displayFields(); track $index) {\n <div class=\"rounded-2xl border border-slate-100 bg-slate-200 p-4\" [ngClass]=\"getFieldColumnClass(field)\" [class.flex]=\"field.type === 'image'\" [class.flex-col]=\"field.type === 'image'\" [class.min-h-64]=\"field.type === 'image'\">\n <p class=\"text-xs uppercase tracking-[0.18em] text-slate-500\">{{ field.label }}</p>\n @if (field.type === 'image') {\n @if (field.imageSrc) {\n <button type=\"button\" class=\"mt-2 block flex-1 cursor-zoom-in overflow-hidden rounded-xl border border-slate-200 bg-white\" [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 ' + field.label\" (click)=\"openViewer(field.imageSrc)\">\n <img [src]=\"field.imageSrc\" [alt]=\"field.label\" class=\"h-full w-full object-cover\" />\n </button>\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">-</p>\n }\n } @else {\n <p class=\"mt-2 text-base font-semibold text-slate-900\">{{ field.displayValue ?? '-' }}</p>\n }\n </div>\n }\n</div>\n\n@if (selectedImageSrc(); as imageSrc) {\n <app-images-viewer [urls]=\"[imageSrc]\" (closed)=\"closeViewer()\" />\n}\n" }]
620
619
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
@@ -659,10 +658,10 @@ class ImagesComponent {
659
658
  .map((item) => String(item || '').trim())
660
659
  .filter(Boolean)));
661
660
  }
662
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ImagesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
663
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ImagesComponent, isStandalone: true, selector: "app-images", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (resolvedImageUrls().length === 0) {\n <p class=\"text-sm text-slate-500\">\u0424\u043E\u0442\u043E \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456</p>\n} @else {\n <div\n class=\"grid gap-3 lg:h-[400px] lg:max-h-[400px]\"\n [ngClass]=\"resolvedImageUrls().length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'\"\n >\n @let previewUrls = resolvedImagePreviewUrls();\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E 1'\"\n (click)=\"openViewer(0)\"\n >\n <img\n [src]=\"previewUrls[0]\"\n [alt]=\"'\u0424\u043E\u0442\u043E 1'\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-56 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n </button>\n\n @if (previewUrls.length > 1) {\n <div class=\"grid grid-cols-2 grid-rows-2 gap-3 lg:h-full lg:min-h-0\">\n @for (image of previewUrls.slice(1, 5); track image; let i = $index) {\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E ' + (i + 2)\"\n (click)=\"openViewer(i + 1)\"\n >\n <img\n [src]=\"image\"\n [alt]=\"'\u0424\u043E\u0442\u043E ' + (i + 2)\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-28 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n @if (i === 3 && resolvedImageUrls().length > 5) {\n <span class=\"absolute inset-0 flex items-center justify-center bg-slate-950/55 text-2xl font-semibold text-white transition group-hover:bg-slate-950/65\">\n +{{ resolvedImageUrls().length - 5 }}\n </span>\n }\n </button>\n }\n </div>\n }\n </div>\n\n @if (isViewerOpen()) {\n <app-images-viewer\n [urls]=\"resolvedImageUrls()\"\n [initialIndex]=\"viewerStartIndex()\"\n (closed)=\"closeViewer()\"\n ></app-images-viewer>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
661
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
662
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: ImagesComponent, isStandalone: true, selector: "app-images", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (resolvedImageUrls().length === 0) {\n <p class=\"text-sm text-slate-500\">\u0424\u043E\u0442\u043E \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456</p>\n} @else {\n <div\n class=\"grid gap-3 lg:h-[400px] lg:max-h-[400px]\"\n [ngClass]=\"resolvedImageUrls().length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'\"\n >\n @let previewUrls = resolvedImagePreviewUrls();\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E 1'\"\n (click)=\"openViewer(0)\"\n >\n <img\n [src]=\"previewUrls[0]\"\n [alt]=\"'\u0424\u043E\u0442\u043E 1'\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-56 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n </button>\n\n @if (previewUrls.length > 1) {\n <div class=\"grid grid-cols-2 grid-rows-2 gap-3 lg:h-full lg:min-h-0\">\n @for (image of previewUrls.slice(1, 5); track image; let i = $index) {\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E ' + (i + 2)\"\n (click)=\"openViewer(i + 1)\"\n >\n <img\n [src]=\"image\"\n [alt]=\"'\u0424\u043E\u0442\u043E ' + (i + 2)\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-28 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n @if (i === 3 && resolvedImageUrls().length > 5) {\n <span class=\"absolute inset-0 flex items-center justify-center bg-slate-950/55 text-2xl font-semibold text-white transition group-hover:bg-slate-950/65\">\n +{{ resolvedImageUrls().length - 5 }}\n </span>\n }\n </button>\n }\n </div>\n }\n </div>\n\n @if (isViewerOpen()) {\n <app-images-viewer\n [urls]=\"resolvedImageUrls()\"\n [initialIndex]=\"viewerStartIndex()\"\n (closed)=\"closeViewer()\"\n ></app-images-viewer>\n }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }] });
664
663
  }
665
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ImagesComponent, decorators: [{
664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: ImagesComponent, decorators: [{
666
665
  type: Component,
667
666
  args: [{ selector: 'app-images', standalone: true, imports: [CommonModule, ImagesViewerComponent], template: "@if (resolvedImageUrls().length === 0) {\n <p class=\"text-sm text-slate-500\">\u0424\u043E\u0442\u043E \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456</p>\n} @else {\n <div\n class=\"grid gap-3 lg:h-[400px] lg:max-h-[400px]\"\n [ngClass]=\"resolvedImageUrls().length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'\"\n >\n @let previewUrls = resolvedImagePreviewUrls();\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E 1'\"\n (click)=\"openViewer(0)\"\n >\n <img\n [src]=\"previewUrls[0]\"\n [alt]=\"'\u0424\u043E\u0442\u043E 1'\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-56 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n </button>\n\n @if (previewUrls.length > 1) {\n <div class=\"grid grid-cols-2 grid-rows-2 gap-3 lg:h-full lg:min-h-0\">\n @for (image of previewUrls.slice(1, 5); track image; let i = $index) {\n <button\n type=\"button\"\n class=\"group relative block h-full min-h-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 text-left\"\n [attr.aria-label]=\"'\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u043D\u0443\u0442\u0438 \u0444\u043E\u0442\u043E ' + (i + 2)\"\n (click)=\"openViewer(i + 1)\"\n >\n <img\n [src]=\"image\"\n [alt]=\"'\u0424\u043E\u0442\u043E ' + (i + 2)\"\n loading=\"lazy\"\n decoding=\"async\"\n class=\"h-28 w-full object-cover transition duration-200 group-hover:scale-[1.02] lg:h-full\"\n [style.max-height.px]=\"resolvedImageMaxHeight()\"\n />\n @if (i === 3 && resolvedImageUrls().length > 5) {\n <span class=\"absolute inset-0 flex items-center justify-center bg-slate-950/55 text-2xl font-semibold text-white transition group-hover:bg-slate-950/65\">\n +{{ resolvedImageUrls().length - 5 }}\n </span>\n }\n </button>\n }\n </div>\n }\n </div>\n\n @if (isViewerOpen()) {\n <app-images-viewer\n [urls]=\"resolvedImageUrls()\"\n [initialIndex]=\"viewerStartIndex()\"\n (closed)=\"closeViewer()\"\n ></app-images-viewer>\n }\n}\n" }]
668
667
  }], propDecorators: { config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
@@ -930,10 +929,10 @@ class TableComponent {
930
929
  return this.resolveObject(value, row);
931
930
  return value;
932
931
  }
933
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
934
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: TableComponent, isStandalone: true, selector: "app-card-table", inputs: { config: "config", data: "data" }, usesOnChanges: true, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (headerActions().length) {\n <div class=\"flex justify-end gap-2\">\n @for (action of headerActions(); track action.id) {\n <button type=\"button\" class=\"rounded-lg border border-slate-200 px-3 py-1.5 text-sm\" (click)=\"onHeaderAction(action)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <app-ui-table\n class=\"flex min-h-0 max-h-[80dvh] flex-col overflow-hidden\"\n [data]=\"tableData()\"\n [columns]=\"columns()\"\n [pageSizeOptions]=\"pageSizeOptionsSignal()\"\n [isLoading]=\"isLoading()\"\n [disablePaging]=\"disablePaging\"\n (pageChange)=\"onPageChange($event)\"\n (actionClick)=\"onAction($event)\"\n (cellChange)=\"onCellChange($event)\"\n ></app-ui-table>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiTableComponent, selector: "app-ui-table", inputs: ["pageSizeOptions", "columns", "isLoading", "data", "disablePaging", "rowClickable", "imageResolver"], outputs: ["pageChange", "rowClick", "actionClick", "cellChange"] }] });
932
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
933
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: TableComponent, isStandalone: true, selector: "app-card-table", inputs: { config: "config", data: "data" }, usesOnChanges: true, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (headerActions().length) {\n <div class=\"flex justify-end gap-2\">\n @for (action of headerActions(); track action.id) {\n <button type=\"button\" class=\"rounded-lg border border-slate-200 px-3 py-1.5 text-sm\" (click)=\"onHeaderAction(action)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <app-ui-table\n class=\"flex min-h-0 max-h-[80dvh] flex-col overflow-hidden\"\n [data]=\"tableData()\"\n [columns]=\"columns()\"\n [pageSizeOptions]=\"pageSizeOptionsSignal()\"\n [isLoading]=\"isLoading()\"\n [disablePaging]=\"disablePaging\"\n (pageChange)=\"onPageChange($event)\"\n (actionClick)=\"onAction($event)\"\n (cellChange)=\"onCellChange($event)\"\n ></app-ui-table>\n</section>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiTableComponent, selector: "app-ui-table", inputs: ["pageSizeOptions", "columns", "isLoading", "data", "disablePaging", "rowClickable", "imageResolver"], outputs: ["pageChange", "rowClick", "actionClick", "cellChange"] }] });
935
934
  }
936
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: TableComponent, decorators: [{
935
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: TableComponent, decorators: [{
937
936
  type: Component,
938
937
  args: [{ selector: 'app-card-table', standalone: true, imports: [CommonModule, UiTableComponent], template: "<section class=\"space-y-4\">\n @if (headerActions().length) {\n <div class=\"flex justify-end gap-2\">\n @for (action of headerActions(); track action.id) {\n <button type=\"button\" class=\"rounded-lg border border-slate-200 px-3 py-1.5 text-sm\" (click)=\"onHeaderAction(action)\">\n {{ action.label }}\n </button>\n }\n </div>\n }\n\n <app-ui-table\n class=\"flex min-h-0 max-h-[80dvh] flex-col overflow-hidden\"\n [data]=\"tableData()\"\n [columns]=\"columns()\"\n [pageSizeOptions]=\"pageSizeOptionsSignal()\"\n [isLoading]=\"isLoading()\"\n [disablePaging]=\"disablePaging\"\n (pageChange)=\"onPageChange($event)\"\n (actionClick)=\"onAction($event)\"\n (cellChange)=\"onCellChange($event)\"\n ></app-ui-table>\n</section>\n" }]
939
938
  }], ctorParameters: () => [], propDecorators: { config: [{
@@ -1022,10 +1021,10 @@ class UiCardPanelsLayoutComponent {
1022
1021
  return { tab };
1023
1022
  return found.resolveInputs(tab, this.data());
1024
1023
  }
1025
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCardPanelsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1026
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiCardPanelsLayoutComponent, isStandalone: true, selector: "app-ui-card-panels-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-12\">\n @for (tab of tabs(); track tab.id) {\n <section\n [class.rounded-3xl]=\"!embedded()\"\n [class.border]=\"!embedded()\"\n [class.border-slate-200]=\"!embedded()\"\n [class.bg-white]=\"!embedded()\"\n [class.p-6]=\"!embedded()\"\n [class.min-w-0]=\"embedded()\"\n [ngClass]=\"getColSpanClass(tab)\"\n [attr.data-card-panel-id]=\"tab.id\"\n >\n @if (shouldShowPanelHeader(tab)) {\n <app-card-section-header\n [data]=\"data()\"\n [title]=\"tab.title\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (getNestedCardConfig(tab); as nestedCard) {\n <app-card [tabs]=\"nestedCard.tabs\" [data]=\"data()\" [layout]=\"nestedCard.layout\"></app-card>\n } @else if (getNestedPanels(tab); as nestedPanels) {\n <app-card [tabs]=\"nestedPanels\" [data]=\"data()\" layout=\"panels\" [embedded]=\"true\"></app-card>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'images') {\n <app-images [config]=\"tab\" [data]=\"data()\"></app-images>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
1024
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardPanelsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1025
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: UiCardPanelsLayoutComponent, isStandalone: true, selector: "app-ui-card-panels-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-12\">\n @for (tab of tabs(); track tab.id) {\n <section\n [class.rounded-3xl]=\"!embedded()\"\n [class.border]=\"!embedded()\"\n [class.border-slate-200]=\"!embedded()\"\n [class.bg-white]=\"!embedded()\"\n [class.p-6]=\"!embedded()\"\n [class.min-w-0]=\"embedded()\"\n [ngClass]=\"getColSpanClass(tab)\"\n [attr.data-card-panel-id]=\"tab.id\"\n >\n @if (shouldShowPanelHeader(tab)) {\n <app-card-section-header\n [data]=\"data()\"\n [title]=\"tab.title\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (getNestedCardConfig(tab); as nestedCard) {\n <app-card [tabs]=\"nestedCard.tabs\" [data]=\"data()\" [layout]=\"nestedCard.layout\"></app-card>\n } @else if (getNestedPanels(tab); as nestedPanels) {\n <app-card [tabs]=\"nestedPanels\" [data]=\"data()\" layout=\"panels\" [embedded]=\"true\"></app-card>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'images') {\n <app-images [config]=\"tab\" [data]=\"data()\"></app-images>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(() => i1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
1027
1026
  }
1028
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCardPanelsLayoutComponent, decorators: [{
1027
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardPanelsLayoutComponent, decorators: [{
1029
1028
  type: Component,
1030
1029
  args: [{ selector: 'app-ui-card-panels-layout', standalone: true, imports: [CommonModule, forwardRef(() => CardComponent), CardSectionHeaderComponent, CardHtmlTabComponent, DetailsGridComponent, ImagesComponent, TableComponent], template: "@if (tabs().length) {\n <div class=\"grid grid-cols-1 gap-4 md:grid-cols-12\">\n @for (tab of tabs(); track tab.id) {\n <section\n [class.rounded-3xl]=\"!embedded()\"\n [class.border]=\"!embedded()\"\n [class.border-slate-200]=\"!embedded()\"\n [class.bg-white]=\"!embedded()\"\n [class.p-6]=\"!embedded()\"\n [class.min-w-0]=\"embedded()\"\n [ngClass]=\"getColSpanClass(tab)\"\n [attr.data-card-panel-id]=\"tab.id\"\n >\n @if (shouldShowPanelHeader(tab)) {\n <app-card-section-header\n [data]=\"data()\"\n [title]=\"tab.title\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (getNestedCardConfig(tab); as nestedCard) {\n <app-card [tabs]=\"nestedCard.tabs\" [data]=\"data()\" [layout]=\"nestedCard.layout\"></app-card>\n } @else if (getNestedPanels(tab); as nestedPanels) {\n <app-card [tabs]=\"nestedPanels\" [data]=\"data()\" layout=\"panels\" [embedded]=\"true\"></app-card>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'images') {\n <app-images [config]=\"tab\" [data]=\"data()\"></app-images>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </div>\n}\n" }]
1031
1030
  }], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }] } });
@@ -1092,10 +1091,10 @@ class UiCardTabsLayoutComponent {
1092
1091
  return { tab };
1093
1092
  return found.resolveInputs(tab, this.data());
1094
1093
  }
1095
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCardTabsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1096
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: UiCardTabsLayoutComponent, isStandalone: true, selector: "app-ui-card-tabs-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <section class=\"space-y-4\">\n <nav class=\"flex flex-wrap gap-2\" aria-label=\"Card tabs\">\n @for (tab of tabs(); track tab.id) {\n <button\n type=\"button\"\n class=\"rounded-xl border px-4 py-2 text-sm font-medium transition\"\n [class.border-slate-900]=\"activeTab()?.id === tab.id\"\n [class.bg-slate-900]=\"activeTab()?.id === tab.id\"\n [class.text-white]=\"activeTab()?.id === tab.id\"\n [class.border-slate-200]=\"activeTab()?.id !== tab.id\"\n [class.bg-white]=\"activeTab()?.id !== tab.id\"\n [class.text-slate-700]=\"activeTab()?.id !== tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n >\n {{ tab.title }}\n </button>\n }\n </nav>\n\n @if (activeTab(); as tab) {\n <section\n [attr.data-card-tab-id]=\"tab.id\"\n >\n @if (getVisibleActions(tab).length) {\n <app-card-section-header\n variant=\"tabs\"\n [data]=\"data()\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (tab.tabs?.length) {\n <app-card [tabs]=\"tab.tabs || []\" [data]=\"data()\" [layout]=\"tab.layout || 'panels'\"></app-card>\n } @else if (tab.component === 'images') {\n <app-images\n [config]=\"tab\"\n [data]=\"data()\"\n ></app-images>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </section>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1$1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
1094
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardTabsLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1095
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: UiCardTabsLayoutComponent, isStandalone: true, selector: "app-ui-card-tabs-layout", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (tabs().length) {\n <section class=\"space-y-4\">\n <nav class=\"flex flex-wrap gap-2\" aria-label=\"Card tabs\">\n @for (tab of tabs(); track tab.id) {\n <button\n type=\"button\"\n class=\"rounded-xl border px-4 py-2 text-sm font-medium transition\"\n [class.border-slate-900]=\"activeTab()?.id === tab.id\"\n [class.bg-slate-900]=\"activeTab()?.id === tab.id\"\n [class.text-white]=\"activeTab()?.id === tab.id\"\n [class.border-slate-200]=\"activeTab()?.id !== tab.id\"\n [class.bg-white]=\"activeTab()?.id !== tab.id\"\n [class.text-slate-700]=\"activeTab()?.id !== tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n >\n {{ tab.title }}\n </button>\n }\n </nav>\n\n @if (activeTab(); as tab) {\n <section\n [attr.data-card-tab-id]=\"tab.id\"\n >\n @if (getVisibleActions(tab).length) {\n <app-card-section-header\n variant=\"tabs\"\n [data]=\"data()\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (tab.tabs?.length) {\n <app-card [tabs]=\"tab.tabs || []\" [data]=\"data()\" [layout]=\"tab.layout || 'panels'\"></app-card>\n } @else if (tab.component === 'images') {\n <app-images\n [config]=\"tab\"\n [data]=\"data()\"\n ></app-images>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </section>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "directive", type: i0.forwardRef(() => i1.NgComponentOutlet), selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletEnvironmentInjector", "ngComponentOutletContent", "ngComponentOutletNgModule"], exportAs: ["ngComponentOutlet"] }, { kind: "component", type: i0.forwardRef(() => CardComponent), selector: "app-card", inputs: ["tabs", "data", "layout", "embedded"] }, { kind: "component", type: i0.forwardRef(() => CardSectionHeaderComponent), selector: "app-card-section-header", inputs: ["variant", "title", "actions", "data"] }, { kind: "component", type: i0.forwardRef(() => CardHtmlTabComponent), selector: "app-card-html-tab", inputs: ["html"] }, { kind: "component", type: i0.forwardRef(() => ImagesComponent), selector: "app-images", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => DetailsGridComponent), selector: "app-details-grid", inputs: ["config", "data"] }, { kind: "component", type: i0.forwardRef(() => TableComponent), selector: "app-card-table", inputs: ["config", "data"] }] });
1097
1096
  }
1098
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiCardTabsLayoutComponent, decorators: [{
1097
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiCardTabsLayoutComponent, decorators: [{
1099
1098
  type: Component,
1100
1099
  args: [{ selector: 'app-ui-card-tabs-layout', standalone: true, imports: [CommonModule, forwardRef(() => CardComponent), CardSectionHeaderComponent, CardHtmlTabComponent, ImagesComponent, DetailsGridComponent, TableComponent], template: "@if (tabs().length) {\n <section class=\"space-y-4\">\n <nav class=\"flex flex-wrap gap-2\" aria-label=\"Card tabs\">\n @for (tab of tabs(); track tab.id) {\n <button\n type=\"button\"\n class=\"rounded-xl border px-4 py-2 text-sm font-medium transition\"\n [class.border-slate-900]=\"activeTab()?.id === tab.id\"\n [class.bg-slate-900]=\"activeTab()?.id === tab.id\"\n [class.text-white]=\"activeTab()?.id === tab.id\"\n [class.border-slate-200]=\"activeTab()?.id !== tab.id\"\n [class.bg-white]=\"activeTab()?.id !== tab.id\"\n [class.text-slate-700]=\"activeTab()?.id !== tab.id\"\n (click)=\"setActiveTab(tab.id)\"\n >\n {{ tab.title }}\n </button>\n }\n </nav>\n\n @if (activeTab(); as tab) {\n <section\n [attr.data-card-tab-id]=\"tab.id\"\n >\n @if (getVisibleActions(tab).length) {\n <app-card-section-header\n variant=\"tabs\"\n [data]=\"data()\"\n [actions]=\"getVisibleActions(tab)\"\n ></app-card-section-header>\n }\n\n @if (tab.tabs?.length) {\n <app-card [tabs]=\"tab.tabs || []\" [data]=\"data()\" [layout]=\"tab.layout || 'panels'\"></app-card>\n } @else if (tab.component === 'images') {\n <app-images\n [config]=\"tab\"\n [data]=\"data()\"\n ></app-images>\n } @else if (tab.component === 'detailsGrid') {\n <app-details-grid [config]=\"tab\" [data]=\"data()\"></app-details-grid>\n } @else if (tab.component === 'table') {\n <app-card-table [config]=\"tab\" [data]=\"data()\"></app-card-table>\n } @else if (tab.component === 'html') {\n <app-card-html-tab [html]=\"tab.html || ''\"></app-card-html-tab>\n } @else if (getRegisteredComponent(tab); as customComponent) {\n <ng-container *ngComponentOutlet=\"customComponent; inputs: getRegisteredInputs(tab)\"></ng-container>\n }\n </section>\n }\n </section>\n}\n" }]
1101
1100
  }], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] } });
@@ -1105,10 +1104,10 @@ class CardComponent {
1105
1104
  data = input(null, ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
1106
1105
  layout = input('panels', ...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
1107
1106
  embedded = input(false, ...(ngDevMode ? [{ debugName: "embedded" }] : /* istanbul ignore next */ []));
1108
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1109
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: CardComponent, isStandalone: true, selector: "app-card", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (layout() === 'panels') {\n <app-ui-card-panels-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n [embedded]=\"embedded()\"\n ></app-ui-card-panels-layout>\n} @else {\n <app-ui-card-tabs-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n ></app-ui-card-tabs-layout>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "component", type: i0.forwardRef(() => UiCardTabsLayoutComponent), selector: "app-ui-card-tabs-layout", inputs: ["tabs", "data"] }, { kind: "component", type: i0.forwardRef(() => UiCardPanelsLayoutComponent), selector: "app-ui-card-panels-layout", inputs: ["tabs", "data", "embedded"] }] });
1107
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1108
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: CardComponent, isStandalone: true, selector: "app-card", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, layout: { classPropertyName: "layout", publicName: "layout", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (layout() === 'panels') {\n <app-ui-card-panels-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n [embedded]=\"embedded()\"\n ></app-ui-card-panels-layout>\n} @else {\n <app-ui-card-tabs-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n ></app-ui-card-tabs-layout>\n}\n", dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => CommonModule) }, { kind: "component", type: i0.forwardRef(() => UiCardTabsLayoutComponent), selector: "app-ui-card-tabs-layout", inputs: ["tabs", "data"] }, { kind: "component", type: i0.forwardRef(() => UiCardPanelsLayoutComponent), selector: "app-ui-card-panels-layout", inputs: ["tabs", "data", "embedded"] }] });
1110
1109
  }
1111
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardComponent, decorators: [{
1110
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardComponent, decorators: [{
1112
1111
  type: Component,
1113
1112
  args: [{ selector: 'app-card', standalone: true, imports: [CommonModule, forwardRef(() => UiCardTabsLayoutComponent), forwardRef(() => UiCardPanelsLayoutComponent)], template: "@if (layout() === 'panels') {\n <app-ui-card-panels-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n [embedded]=\"embedded()\"\n ></app-ui-card-panels-layout>\n} @else {\n <app-ui-card-tabs-layout\n [tabs]=\"tabs()\"\n [data]=\"data()\"\n ></app-ui-card-tabs-layout>\n}\n" }]
1114
1113
  }], propDecorators: { tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], layout: [{ type: i0.Input, args: [{ isSignal: true, alias: "layout", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }] } });
@@ -1123,10 +1122,10 @@ class CardDictionaryService {
1123
1122
  getSuggestByName(name) {
1124
1123
  return this.http.get(apiUrl(this.baseUrl, `/api/suggest/${encodeURIComponent(name)}`));
1125
1124
  }
1126
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardDictionaryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1127
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardDictionaryService, providedIn: 'root' });
1125
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1126
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, providedIn: 'root' });
1128
1127
  }
1129
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardDictionaryService, decorators: [{
1128
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardDictionaryService, decorators: [{
1130
1129
  type: Injectable,
1131
1130
  args: [{ providedIn: 'root' }]
1132
1131
  }] });
@@ -1135,10 +1134,10 @@ class CardCurrentUserService {
1135
1134
  baseUrl = inject(UI_CARD_API_BASE_URL);
1136
1135
  user$ = this.http.get(apiUrl(this.baseUrl, '/api/users/me'), { withCredentials: true }).pipe(shareReplay(1));
1137
1136
  getCurrentUser() { return this.user$; }
1138
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardCurrentUserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1139
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardCurrentUserService, providedIn: 'root' });
1137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1138
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, providedIn: 'root' });
1140
1139
  }
1141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardCurrentUserService, decorators: [{
1140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardCurrentUserService, decorators: [{
1142
1141
  type: Injectable,
1143
1142
  args: [{ providedIn: 'root' }]
1144
1143
  }] });
@@ -1147,10 +1146,10 @@ class CardImageService {
1147
1146
  getPhotoLink(id) {
1148
1147
  return id ? apiUrl(this.baseUrl, `/api/files/${encodeURIComponent(id)}/preview?scale=25`) : undefined;
1149
1148
  }
1150
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1151
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardImageService, providedIn: 'root' });
1149
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1150
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, providedIn: 'root' });
1152
1151
  }
1153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: CardImageService, decorators: [{
1152
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: CardImageService, decorators: [{
1154
1153
  type: Injectable,
1155
1154
  args: [{ providedIn: 'root' }]
1156
1155
  }] });
@@ -1188,10 +1187,10 @@ class UiEntityDocumentsService {
1188
1187
  resolveDownloadUrl(fileId) {
1189
1188
  return cardApiResourceUrl(this.baseUrl, `/api/files/${encodeURIComponent(fileId)}`);
1190
1189
  }
1191
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiEntityDocumentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1192
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiEntityDocumentsService, providedIn: 'root' });
1190
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1191
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, providedIn: 'root' });
1193
1192
  }
1194
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: UiEntityDocumentsService, decorators: [{
1193
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: UiEntityDocumentsService, decorators: [{
1195
1194
  type: Injectable,
1196
1195
  args: [{ providedIn: 'root' }]
1197
1196
  }] });
@@ -1265,12 +1264,12 @@ class DocumentsUploadModalComponent {
1265
1264
  this.uploadFileInput.nativeElement.value = '';
1266
1265
  }
1267
1266
  }
1268
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsUploadModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1269
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DocumentsUploadModalComponent, isStandalone: true, selector: "app-documents-upload-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "uploadFileInput", first: true, predicate: ["uploadFileInput"], descendants: true }], ngImport: i0, template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [fullWidth]=\"true\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }, { kind: "component", type: InputSelectComponent, selector: "input-select", inputs: ["label", "placeholder", "name", "data", "required", "fullWidth", "disabled", "multiple", "includeBlankOption", "blankOptionLabel", "emptyStateLabel", "searchable", "remoteSearch", "searchPlaceholder", "options", "error", "hint", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }] });
1267
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsUploadModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1268
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsUploadModalComponent, isStandalone: true, selector: "app-documents-upload-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", saved: "saved" }, viewQueries: [{ propertyName: "uploadFileInput", first: true, predicate: ["uploadFileInput"], descendants: true }], ngImport: i0, template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }, { kind: "component", type: InputSelectComponent, selector: "input-select", inputs: ["label", "hint", "error", "placeholder", "name", "data", "dataParams", "required", "disabled", "multiple", "emptyStateLabel", "searchable", "options", "triggerClass", "panelClass"], outputs: ["valueChange", "searchChange"] }] });
1270
1269
  }
1271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsUploadModalComponent, decorators: [{
1270
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsUploadModalComponent, decorators: [{
1272
1271
  type: Component,
1273
- args: [{ selector: 'app-documents-upload-modal', standalone: true, imports: [CommonModule, FormsModule, LucideAngularModule, UiButtonComponent, UiModalComponent, InputSelectComponent], template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [fullWidth]=\"true\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n" }]
1272
+ args: [{ selector: 'app-documents-upload-modal', standalone: true, imports: [CommonModule, FormsModule, LucideDynamicIcon, UiButtonComponent, UiModalComponent, InputSelectComponent], template: "<core-modal\n title=\"\u0414\u043E\u0434\u0430\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-4\">\n <input-select\n [data]=\"'doc_type'\"\n name=\"uploadDocumentTypeId\"\n label=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n hint=\"\u041D\u0435\u043E\u0431\u043E\u0432'\u044F\u0437\u043A\u043E\u0432\u043E\"\n [ngModel]=\"documentTypeId()\"\n (ngModelChange)=\"onDocumentTypeChange($event)\"\n placeholder=\"\u0422\u0438\u043F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\"\n [searchable]=\"true\"\n ></input-select>\n\n <div class=\"space-y-2\">\n <label class=\"block text-sm font-medium text-slate-700\" for=\"document-files\">\u0424\u0430\u0439\u043B\u0438</label>\n <input\n #uploadFileInput\n id=\"document-files\"\n type=\"file\"\n class=\"block w-full rounded-xl border border-slate-200 bg-white px-3 py-2.5 text-sm text-slate-900 outline-none transition file:mr-3 file:rounded-lg file:border-0 file:bg-slate-900 file:px-3 file:py-2 file:text-sm file:font-medium file:text-white focus:border-slate-400 focus:ring-2 focus:ring-slate-200\"\n multiple\n (change)=\"onFilesSelected($event)\"\n />\n @if (fileNames().length) {\n <div class=\"rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-sm text-slate-600\">\n @for (fileName of fileNames(); track fileName) {\n <div class=\"truncate\">{{ fileName }}</div>\n }\n </div>\n } @else {\n <p class=\"text-xs text-slate-500\">\u041C\u043E\u0436\u043D\u0430 \u043E\u0431\u0440\u0430\u0442\u0438 \u043E\u0434\u0438\u043D \u0430\u0431\u043E \u0434\u0435\u043A\u0456\u043B\u044C\u043A\u0430 \u0444\u0430\u0439\u043B\u0456\u0432.</p>\n }\n </div>\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"ghost\" [disabled]=\"isUploading()\" (click)=\"close()\">\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438</ui-button>\n <ui-button variant=\"primary\" [disabled]=\"isUploading()\" (click)=\"submitUpload()\">\n {{ isUploading() ? '\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F...' : '\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438' }}\n </ui-button>\n </div>\n</core-modal>\n" }]
1274
1273
  }], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], saved: [{ type: i0.Output, args: ["saved"] }], uploadFileInput: [{
1275
1274
  type: ViewChild,
1276
1275
  args: ['uploadFileInput']
@@ -1314,10 +1313,10 @@ class DocumentsTextModalComponent {
1314
1313
  .replace(/"/g, '&quot;')
1315
1314
  .replace(/'/g, '&#39;');
1316
1315
  }
1317
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsTextModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1318
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DocumentsTextModalComponent, isStandalone: true, selector: "app-documents-text-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", recognizeRequested: "recognizeRequested" }, ngImport: i0, template: "<core-modal\n title=\"\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456 \u0434\u0430\u043D\u0456\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-3\">\n @if (hasDocumentHtml()) {\n <div\n class=\"max-h-[32rem] overflow-auto rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-900\"\n [innerHTML]=\"getDocumentHtml()\"\n ></div>\n } @else {\n <div class=\"rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-sm text-slate-500\">\n \u0414\u0430\u043D\u0456 \u0449\u0435 \u043D\u0435 \u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456. \u041D\u0430\u0442\u0438\u0441\u043D\u0438 \u201C\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456\u201D.\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n @if (isImage()) {\n <ui-button variant=\"secondary\" (click)=\"requestRecognize()\">\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0449\u0435 \u0440\u0430\u0437</ui-button>\n }\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
1316
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsTextModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1317
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsTextModalComponent, isStandalone: true, selector: "app-documents-text-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", recognizeRequested: "recognizeRequested" }, ngImport: i0, template: "<core-modal\n title=\"\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456 \u0434\u0430\u043D\u0456\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-3\">\n @if (hasDocumentHtml()) {\n <div\n class=\"max-h-[32rem] overflow-auto rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-900\"\n [innerHTML]=\"getDocumentHtml()\"\n ></div>\n } @else {\n <div class=\"rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-sm text-slate-500\">\n \u0414\u0430\u043D\u0456 \u0449\u0435 \u043D\u0435 \u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456. \u041D\u0430\u0442\u0438\u0441\u043D\u0438 \u201C\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456\u201D.\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n @if (isImage()) {\n <ui-button variant=\"secondary\" (click)=\"requestRecognize()\">\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0449\u0435 \u0440\u0430\u0437</ui-button>\n }\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
1319
1318
  }
1320
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsTextModalComponent, decorators: [{
1319
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsTextModalComponent, decorators: [{
1321
1320
  type: Component,
1322
1321
  args: [{ selector: 'app-documents-text-modal', standalone: true, imports: [CommonModule, UiButtonComponent, UiModalComponent], template: "<core-modal\n title=\"\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456 \u0434\u0430\u043D\u0456\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n <div class=\"space-y-3\">\n @if (hasDocumentHtml()) {\n <div\n class=\"max-h-[32rem] overflow-auto rounded-xl border border-slate-200 bg-slate-50 px-4 py-4 text-sm text-slate-900\"\n [innerHTML]=\"getDocumentHtml()\"\n ></div>\n } @else {\n <div class=\"rounded-xl border border-dashed border-slate-200 bg-slate-50 px-4 py-6 text-sm text-slate-500\">\n \u0414\u0430\u043D\u0456 \u0449\u0435 \u043D\u0435 \u0440\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u043D\u0456. \u041D\u0430\u0442\u0438\u0441\u043D\u0438 \u201C\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456\u201D.\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n @if (isImage()) {\n <ui-button variant=\"secondary\" (click)=\"requestRecognize()\">\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0449\u0435 \u0440\u0430\u0437</ui-button>\n }\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n" }]
1323
1322
  }], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }], recognizeRequested: [{ type: i0.Output, args: ["recognizeRequested"] }] } });
@@ -1333,10 +1332,10 @@ class DocumentsImagePreviewModalComponent {
1333
1332
  const match = String(url || '').match(/^(.*\/api\/files\/[^/?#]+)(?:\?.*)?$/i);
1334
1333
  return match ? `${match[1]}/preview?scale=25` : url;
1335
1334
  }
1336
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsImagePreviewModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1337
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DocumentsImagePreviewModalComponent, isStandalone: true, selector: "app-documents-image-preview-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "<core-modal\n [title]=\"document()?.name || '\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430'\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n @if (document()) {\n <div class=\"overflow-hidden rounded-2xl bg-slate-100\">\n <img\n [src]=\"getPreviewUrl(document()!.downloadUrl)\"\n [alt]=\"document()!.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\"\n decoding=\"async\"\n class=\"max-h-[75vh] w-full object-contain\"\n >\n </div>\n }\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
1335
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsImagePreviewModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1336
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsImagePreviewModalComponent, isStandalone: true, selector: "app-documents-image-preview-modal", inputs: { isOpen: { classPropertyName: "isOpen", publicName: "isOpen", isSignal: true, isRequired: false, transformFunction: null }, document: { classPropertyName: "document", publicName: "document", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed" }, ngImport: i0, template: "<core-modal\n [title]=\"document()?.name || '\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430'\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n @if (document()) {\n <div class=\"overflow-hidden rounded-2xl bg-slate-100\">\n <img\n [src]=\"getPreviewUrl(document()!.downloadUrl)\"\n [alt]=\"document()!.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\"\n decoding=\"async\"\n class=\"max-h-[75vh] w-full object-contain\"\n >\n </div>\n }\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: UiModalComponent, selector: "core-modal", inputs: ["isOpen", "title", "size", "position", "closable", "closeOnBackdrop", "closeOnEscape"], outputs: ["closed"] }] });
1338
1337
  }
1339
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsImagePreviewModalComponent, decorators: [{
1338
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsImagePreviewModalComponent, decorators: [{
1340
1339
  type: Component,
1341
1340
  args: [{ selector: 'app-documents-image-preview-modal', standalone: true, imports: [CommonModule, UiButtonComponent, UiModalComponent], template: "<core-modal\n [title]=\"document()?.name || '\u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430'\"\n size=\"lg\"\n [isOpen]=\"isOpen()\"\n (closed)=\"close()\"\n>\n @if (document()) {\n <div class=\"overflow-hidden rounded-2xl bg-slate-100\">\n <img\n [src]=\"getPreviewUrl(document()!.downloadUrl)\"\n [alt]=\"document()!.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\"\n decoding=\"async\"\n class=\"max-h-[75vh] w-full object-contain\"\n >\n </div>\n }\n\n <div slot=\"footer\" class=\"flex justify-end gap-2\">\n <ui-button variant=\"primary\" (click)=\"close()\">\u0417\u0430\u043A\u0440\u0438\u0442\u0438</ui-button>\n </div>\n</core-modal>\n" }]
1342
1341
  }], propDecorators: { isOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "isOpen", required: false }] }], document: [{ type: i0.Input, args: [{ isSignal: true, alias: "document", required: false }] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
@@ -1357,11 +1356,11 @@ class DocumentsComponent {
1357
1356
  textTarget = signal(null, ...(ngDevMode ? [{ debugName: "textTarget" }] : /* istanbul ignore next */ []));
1358
1357
  imagePreviewTarget = signal(null, ...(ngDevMode ? [{ debugName: "imagePreviewTarget" }] : /* istanbul ignore next */ []));
1359
1358
  deletingDocumentId = signal(null, ...(ngDevMode ? [{ debugName: "deletingDocumentId" }] : /* istanbul ignore next */ []));
1360
- eyeIcon = Eye;
1361
- fileIcon = FileText;
1362
- plusIcon = Plus;
1363
- sparkleIcon = Sparkles;
1364
- deleteIcon = Trash;
1359
+ eyeIcon = LucideEye;
1360
+ fileIcon = LucideFileText;
1361
+ plusIcon = LucidePlus;
1362
+ sparkleIcon = LucideSparkles;
1363
+ deleteIcon = LucideTrash;
1365
1364
  isAdmin = toSignal(inject(CardCurrentUserService).getCurrentUser().pipe(map$1((user) => String(user.role || '').trim().toUpperCase() === 'ADMIN')), { initialValue: false });
1366
1365
  documentsService = inject(UiEntityDocumentsService);
1367
1366
  dictionaryService = inject(CardDictionaryService);
@@ -1613,19 +1612,19 @@ class DocumentsComponent {
1613
1612
  }))
1614
1613
  .subscribe();
1615
1614
  }
1616
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1617
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: DocumentsComponent, isStandalone: true, selector: "app-documents", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <lucide-icon [img]=\"eyeIcon\"></lucide-icon>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <lucide-icon [img]=\"sparkleIcon\"></lucide-icon>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <lucide-icon [img]=\"deleteIcon\"></lucide-icon>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <lucide-icon [img]=\"plusIcon\"></lucide-icon>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: LucideAngularModule }, { kind: "component", type: i1.LucideAngularComponent, selector: "lucide-angular, lucide-icon, i-lucide, span-lucide", inputs: ["class", "name", "img", "color", "absoluteStrokeWidth", "size", "strokeWidth"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: DocumentsUploadModalComponent, selector: "app-documents-upload-modal", inputs: ["isOpen", "entity", "id"], outputs: ["closed", "saved"] }, { kind: "component", type: DocumentsTextModalComponent, selector: "app-documents-text-modal", inputs: ["isOpen", "document"], outputs: ["closed", "recognizeRequested"] }, { kind: "component", type: DocumentsImagePreviewModalComponent, selector: "app-documents-image-preview-modal", inputs: ["isOpen", "document"], outputs: ["closed"] }] });
1615
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1616
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: DocumentsComponent, isStandalone: true, selector: "app-documents", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <svg [lucideIcon]=\"eyeIcon\"></svg>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <svg [lucideIcon]=\"sparkleIcon\"></svg>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <svg [lucideIcon]=\"deleteIcon\"></svg>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <svg [lucideIcon]=\"plusIcon\"></svg>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }, { kind: "component", type: UiButtonComponent, selector: "ui-button", inputs: ["variant", "size", "disabled", "fullWidth", "type", "withShadow", "icon", "iconOnly", "ariaLabel"] }, { kind: "component", type: DocumentsUploadModalComponent, selector: "app-documents-upload-modal", inputs: ["isOpen", "entity", "id"], outputs: ["closed", "saved"] }, { kind: "component", type: DocumentsTextModalComponent, selector: "app-documents-text-modal", inputs: ["isOpen", "document"], outputs: ["closed", "recognizeRequested"] }, { kind: "component", type: DocumentsImagePreviewModalComponent, selector: "app-documents-image-preview-modal", inputs: ["isOpen", "document"], outputs: ["closed"] }] });
1618
1617
  }
1619
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: DocumentsComponent, decorators: [{
1618
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: DocumentsComponent, decorators: [{
1620
1619
  type: Component,
1621
1620
  args: [{ selector: 'app-documents', standalone: true, imports: [
1622
1621
  CommonModule,
1623
- LucideAngularModule,
1622
+ LucideDynamicIcon,
1624
1623
  UiButtonComponent,
1625
1624
  DocumentsUploadModalComponent,
1626
1625
  DocumentsTextModalComponent,
1627
1626
  DocumentsImagePreviewModalComponent,
1628
- ], template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <lucide-icon [img]=\"fileIcon\"></lucide-icon>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <lucide-icon [img]=\"eyeIcon\"></lucide-icon>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <lucide-icon [img]=\"sparkleIcon\"></lucide-icon>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <lucide-icon [img]=\"deleteIcon\"></lucide-icon>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <lucide-icon [img]=\"plusIcon\"></lucide-icon>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n" }]
1627
+ ], template: "<div class=\"space-y-4\">\n <div>\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432...\n </div>\n } @else if (documents().length === 0) {\n <div class=\"rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-8 text-center text-sm text-slate-500\">\n \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0438 \u0432\u0456\u0434\u0441\u0443\u0442\u043D\u0456\n </div>\n } @else {\n <div class=\"grid gap-3\">\n @for (document of documents(); track trackDocument($index, document)) {\n <article class=\"flex flex-col gap-4 rounded-2xl border border-slate-200 bg-white p-4 shadow-sm sm:flex-row sm:items-center sm:justify-between\">\n @if (isImage(document)) {\n <button\n type=\"button\"\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100 h-28 w-40\"\n (click)=\"openImagePreview(document)\"\n >\n <img [src]=\"getImagePreviewUrl(document)\" [alt]=\"document.name || '\u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442'\" loading=\"lazy\" decoding=\"async\" class=\"h-full w-full object-cover\">\n </button>\n } @else {\n <a\n class=\"block shrink-0 overflow-hidden rounded-2xl border border-slate-200 bg-slate-50 transition hover:border-slate-300 hover:bg-slate-100\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [class.h-28]=\"isPdf(document)\"\n [class.w-40]=\"isPdf(document)\"\n [class.h-20]=\"!isPdf(document)\"\n [class.w-24]=\"!isPdf(document)\"\n >\n @if (isPdf(document)) {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-xs font-semibold uppercase tracking-[0.18em] text-slate-600\">PDF</span>\n </div>\n } @else {\n <div class=\"flex h-full w-full flex-col items-center justify-center gap-2 px-3 py-4 text-slate-700\">\n <div class=\"flex h-11 w-11 items-center justify-center rounded-2xl bg-white text-slate-900 shadow-sm\">\n <svg [lucideIcon]=\"fileIcon\"></svg>\n </div>\n <span class=\"text-[10px] font-semibold uppercase tracking-[0.18em] text-slate-500\">\n {{ getFileBadge(document) }}\n </span>\n </div>\n }\n </a>\n }\n\n <div class=\"min-w-0 flex-1\">\n <div class=\"flex flex-col gap-2 lg:flex-row lg:items-start lg:justify-between\">\n <div class=\"min-w-0\">\n <div class=\"flex flex-wrap items-center gap-2\">\n <h4 class=\"truncate text-sm font-semibold text-slate-900\">\n {{ document.name || '\u0411\u0435\u0437 \u043D\u0430\u0437\u0432\u0438' }}\n </h4>\n @if (getDocumentTypeLabel(document)) {\n <span class=\"inline-flex shrink-0 items-center rounded-full border border-sky-200 bg-sky-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-sky-700\">\n {{ getDocumentTypeLabel(document) }}\n </span>\n }\n </div>\n <p class=\"mt-1 text-xs text-slate-500\">\n {{ formatSize(document.size) }} \u00B7 {{ document.type }}\n </p>\n </div>\n\n <div class=\"flex flex-wrap items-center gap-2\">\n <ui-button variant=\"ghost\" size=\"sm\" (click)=\"openTextModal(document)\">\n <svg [lucideIcon]=\"eyeIcon\"></svg>\n \u041F\u0435\u0440\u0435\u0433\u043B\u044F\u0434\n </ui-button>\n @if (isImage(document)) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"isDocumentRecognizing(document) || isRecognitionPending(document) || isRecognitionCompleted(document)\" (click)=\"recognizeText(document)\">\n <svg [lucideIcon]=\"sparkleIcon\"></svg>\n {{ isDocumentRecognizing(document) ? '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0432\u0430\u043D\u043D\u044F...' : '\u0420\u043E\u0437\u043F\u0456\u0437\u043D\u0430\u0442\u0438 \u0434\u0430\u043D\u0456' }}\n </ui-button>\n }\n @if (isAdmin()) {\n <ui-button variant=\"ghost\" size=\"sm\" [disabled]=\"deletingDocumentId() === document.id\" (click)=\"removeDocument(document)\">\n <svg [lucideIcon]=\"deleteIcon\"></svg>\n {{ deletingDocumentId() === document.id ? '\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043D\u044F...' : '\u0412\u0438\u0434\u0430\u043B\u0438\u0442\u0438' }}\n </ui-button>\n }\n </div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap items-center justify-between gap-2\">\n <a\n class=\"inline-flex items-center rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-700 transition hover:border-slate-300 hover:bg-slate-50\"\n [href]=\"document.downloadUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438\n </a>\n @if (isImage(document) && getRecognitionStatusLabel(document)) {\n <span\n class=\"inline-flex items-center rounded-full border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.12em]\"\n [class.border-amber-200]=\"isRecognitionPending(document)\"\n [class.bg-amber-50]=\"isRecognitionPending(document)\"\n [class.text-amber-700]=\"isRecognitionPending(document)\"\n [class.border-rose-200]=\"document.recognitionStatus === 'FAILED'\"\n [class.bg-rose-50]=\"document.recognitionStatus === 'FAILED'\"\n [class.text-rose-700]=\"document.recognitionStatus === 'FAILED'\"\n [class.border-emerald-200]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.bg-emerald-50]=\"document.recognitionStatus === 'COMPLETED'\"\n [class.text-emerald-700]=\"document.recognitionStatus === 'COMPLETED'\"\n >\n {{ getRecognitionStatusLabel(document) }}\n </span>\n }\n </div>\n </div>\n </article>\n }\n </div>\n }\n </div>\n\n <div class=\"flex flex-col gap-3 rounded-2xl border border-dashed border-slate-200 bg-slate-50 px-4 py-4\">\n <div>\n <h4 class=\"text-sm font-semibold text-slate-900\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0456\u0432 \u0443 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0441\u0445\u043E\u0432\u0438\u0449\u0435</h4>\n <p class=\"mt-1 text-xs text-slate-500\">\u0414\u043E\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u0456 \u0444\u0430\u0439\u043B\u0438 \u0434\u043E \u043A\u0430\u0440\u0442\u043A\u0438 \u0431\u0435\u0437\u043F\u043E\u0441\u0435\u0440\u0435\u0434\u043D\u044C\u043E \u0442\u0443\u0442.</p>\n </div>\n\n <div class=\"flex w-full flex-col gap-2 sm:w-auto\">\n <ui-button variant=\"secondary\" size=\"sm\" (click)=\"openUploadModal()\">\n <svg [lucideIcon]=\"plusIcon\"></svg>\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\n </ui-button>\n </div>\n </div>\n</div>\n\n<app-documents-text-modal\n [isOpen]=\"isTextOpen()\"\n [document]=\"textTarget()\"\n (closed)=\"closeTextModal()\"\n (recognizeRequested)=\"textTarget() && recognizeText(textTarget()!)\"\n></app-documents-text-modal>\n\n<app-documents-upload-modal\n [isOpen]=\"isUploadOpen()\"\n [entity]=\"entity()\"\n [id]=\"id()\"\n (closed)=\"closeUploadModal()\"\n (saved)=\"reloadDocuments()\"\n></app-documents-upload-modal>\n\n<app-documents-image-preview-modal\n [isOpen]=\"isImagePreviewOpen()\"\n [document]=\"imagePreviewTarget()\"\n (closed)=\"closeImagePreview()\"\n></app-documents-image-preview-modal>\n" }]
1629
1628
  }], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
1630
1629
 
1631
1630
  class HistoryTabComponent {
@@ -1711,13 +1710,10 @@ class HistoryTabComponent {
1711
1710
  ...operation,
1712
1711
  changes: await Promise.all((operation.changes || []).map(async (change) => {
1713
1712
  const raw = this.extractRawFields(change.changedFields);
1714
- const fields = this.config().fields || {};
1715
- const visible = Object.keys(fields).length
1716
- ? Object.entries(raw).filter(([field]) => !!this.getFieldConfig(change.entityType, field))
1717
- : Object.entries(raw);
1713
+ const visible = Object.entries(raw);
1718
1714
  const changedFields = {};
1719
1715
  for (const [field, values] of visible) {
1720
- const config = this.getFieldConfig(change.entityType, field) || {};
1716
+ const config = this.getFieldConfig(change, field) || {};
1721
1717
  changedFields[field] = {
1722
1718
  label: config.label || field,
1723
1719
  type: config.type || 'text',
@@ -1739,11 +1735,11 @@ class HistoryTabComponent {
1739
1735
  }];
1740
1736
  }));
1741
1737
  }
1742
- getFieldConfig(entityType, field) {
1743
- const fields = this.config().fields || {};
1738
+ getFieldConfig(change, field) {
1739
+ const fields = { ...(this.config().fields || {}), ...Object.fromEntries(Object.entries(change.fieldMetadata || {}).map(([key, value]) => [`${change.entityType}.${key}`, value])) };
1744
1740
  const candidates = [field, field.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`), field.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())];
1745
1741
  for (const candidate of candidates) {
1746
- const config = fields[`${entityType}.${candidate}`];
1742
+ const config = fields[`${change.entityType}.${candidate}`];
1747
1743
  if (config)
1748
1744
  return config;
1749
1745
  }
@@ -1751,10 +1747,11 @@ class HistoryTabComponent {
1751
1747
  }
1752
1748
  async toDisplayValue(value, config) {
1753
1749
  const display = await this.resolveDisplay(value, config);
1750
+ const structured = config.displayMode === 'structured' ? await this.toStructuredItems(value, config.itemFields) : undefined;
1754
1751
  const result = {
1755
1752
  value: value ?? null,
1756
1753
  display,
1757
- ...(config.displayMode === 'structured' ? { structured: this.toStructuredItems(value, config.itemFields) } : {}),
1754
+ ...(structured ? { structured } : {}),
1758
1755
  };
1759
1756
  if (config.link && value !== null && value !== undefined && value !== '')
1760
1757
  result.url = config.link.replace('{value}', encodeURIComponent(String(value)));
@@ -1780,34 +1777,30 @@ class HistoryTabComponent {
1780
1777
  this.dictionaryCache.set(cacheKey, request);
1781
1778
  return request;
1782
1779
  }
1783
- toStructuredItems(value, itemFields) {
1780
+ async toStructuredItems(value, itemFields) {
1784
1781
  const values = Array.isArray(value) ? value : value && typeof value === 'object' ? [value] : [];
1785
- return values.map((item, index) => {
1782
+ return (await Promise.all(values.map(async (item, index) => {
1786
1783
  if (!item || typeof item !== 'object' || Array.isArray(item)) {
1787
1784
  const display = String(item ?? 'Не задано');
1788
1785
  return { key: `${index}:${display}`, fields: [{ key: 'value', label: 'Значение', value: item, display }] };
1789
1786
  }
1790
1787
  const record = item;
1791
- const entries = itemFields ? Object.entries(itemFields).filter(([key]) => key in record) : Object.entries(record);
1788
+ const entries = itemFields ? Object.entries(itemFields).filter(([key]) => key in record) : Object.entries(record).map(([key]) => [key, {}]);
1792
1789
  const seenLabels = new Set();
1793
1790
  return {
1794
1791
  key: String(record['id'] || record['key'] || index),
1795
- fields: entries.flatMap(([key, rawFieldConfig]) => {
1792
+ fields: (await Promise.all(entries.map(async ([key, rawFieldConfig]) => {
1796
1793
  const fieldConfig = rawFieldConfig;
1797
1794
  const value = record[key];
1798
1795
  const label = fieldConfig.label || key;
1799
1796
  if (value === null || value === undefined || value === '' || seenLabels.has(label))
1800
- return [];
1797
+ return null;
1801
1798
  seenLabels.add(label);
1802
- return [{
1803
- key,
1804
- label,
1805
- value,
1806
- display: typeof value === 'object' ? JSON.stringify(value) : String(value),
1807
- }];
1808
- }),
1799
+ const display = fieldConfig.data ? await this.resolveDictionary(fieldConfig.data, String(value)) : typeof value === 'object' ? JSON.stringify(value) : String(value);
1800
+ return { key, label, value, display };
1801
+ }))).filter((field) => field !== null),
1809
1802
  };
1810
- });
1803
+ }))).filter((item) => item.fields.length > 0);
1811
1804
  }
1812
1805
  toggleOperation(id) {
1813
1806
  const next = new Set(this.expandedOperationIds());
@@ -1820,12 +1813,12 @@ class HistoryTabComponent {
1820
1813
  isExpanded(id) {
1821
1814
  return this.expandedOperationIds().has(id);
1822
1815
  }
1823
- getEntityLabel(entityType) {
1816
+ getEntityLabel(entityType, providedLabel) {
1824
1817
  const labels = {
1825
1818
  entity_files: 'Документ',
1826
1819
  files: 'Файл',
1827
1820
  };
1828
- return this.config().entities?.[entityType] || labels[entityType] || entityType;
1821
+ return providedLabel || this.config().entities?.[entityType] || labels[entityType] || entityType;
1829
1822
  }
1830
1823
  getActionLabel(action) {
1831
1824
  const labels = {
@@ -1873,26 +1866,26 @@ class HistoryTabComponent {
1873
1866
  counts.set(change.entityType, (counts.get(change.entityType) || 0) + 1);
1874
1867
  }
1875
1868
  return [...counts.entries()]
1876
- .map(([type, count]) => `${this.getEntityLabel(type)}: ${count}`)
1869
+ .map(([type, count]) => `${this.getEntityLabel(type, operation.changes.find((change) => change.entityType === type)?.entityLabel)}: ${count}`)
1877
1870
  .join(' · ');
1878
1871
  }
1879
1872
  getPrimaryChanges(operation) {
1880
- const primaryTypes = new Set([this.entity(), this.config().primaryEntity].filter(Boolean));
1873
+ const primaryTypes = new Set([operation.primaryEntity, this.entity(), this.config().primaryEntity].filter(Boolean));
1881
1874
  return (operation.changes || []).filter((change) => primaryTypes.has(change.entityType));
1882
1875
  }
1883
1876
  getRelatedChanges(operation) {
1884
1877
  const primaryChanges = this.getPrimaryChanges(operation);
1885
- const primaryTypes = new Set([this.entity(), this.config().primaryEntity].filter(Boolean));
1878
+ const primaryTypes = new Set([operation.primaryEntity, this.entity(), this.config().primaryEntity].filter(Boolean));
1886
1879
  return primaryChanges.length
1887
1880
  ? (operation.changes || []).filter((change) => !primaryTypes.has(change.entityType))
1888
1881
  : operation.changes || [];
1889
1882
  }
1890
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HistoryTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1891
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: HistoryTabComponent, isStandalone: true, selector: "app-history-tab", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$1.DatePipe, name: "date" }, { kind: "pipe", type: i1$1.KeyValuePipe, name: "keyvalue" }] });
1883
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HistoryTabComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1884
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.24", type: HistoryTabComponent, isStandalone: true, selector: "app-history-tab", inputs: { entity: { classPropertyName: "entity", publicName: "entity", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0414\u043E\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0414\u043E\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: ImagesViewerComponent, selector: "app-images-viewer", inputs: ["urls", "initialIndex"], outputs: ["closed"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1.DatePipe, name: "date" }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }] });
1892
1885
  }
1893
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: HistoryTabComponent, decorators: [{
1886
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.24", ngImport: i0, type: HistoryTabComponent, decorators: [{
1894
1887
  type: Component,
1895
- args: [{ selector: 'app-history-tab', standalone: true, imports: [CommonModule, ImagesViewerComponent, RouterLink], template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n" }]
1888
+ args: [{ selector: 'app-history-tab', standalone: true, imports: [CommonModule, ImagesViewerComponent, RouterLink], template: "<section class=\"space-y-4\">\n @if (isLoading()) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F \u0456\u0441\u0442\u043E\u0440\u0456\u0457\u2026\n </div>\n } @else if (hasError()) {\n <div class=\"rounded-2xl border border-red-200 bg-red-50 p-6 text-sm text-red-700\">\n \u041D\u0435 \u0432\u0434\u0430\u043B\u043E\u0441\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0456\u0441\u0442\u043E\u0440\u0456\u044E \u0437\u043C\u0456\u043D.\n </div>\n } @else if (!operations().length) {\n <div class=\"rounded-2xl border border-slate-200 bg-white p-6 text-sm text-slate-500\">\n \u0406\u0441\u0442\u043E\u0440\u0456\u044F \u0437\u043C\u0456\u043D \u043F\u043E\u043A\u0438 \u043F\u043E\u0440\u043E\u0436\u043D\u044F.\n </div>\n } @else {\n <div class=\"space-y-3\">\n @for (operation of operations(); track operation.id) {\n <article class=\"rounded-2xl border border-slate-200 bg-white p-5 shadow-sm\">\n <div class=\"flex flex-wrap items-start justify-between gap-3\">\n <div>\n <h3 class=\"text-sm font-semibold text-slate-900\">{{ operation.description }}</h3>\n @if (operation.actorName) {\n <p class=\"mt-1 text-sm text-slate-500\">{{ operation.actorName }}</p>\n }\n </div>\n <time class=\"text-xs text-slate-400\" [dateTime]=\"operation.createdAt\">\n {{ operation.createdAt | date: 'dd.MM.yyyy HH:mm' }}\n </time>\n </div>\n\n @if (getPrimaryChanges(operation).length) {\n <div class=\"mt-4 space-y-2 border-t border-slate-100 pt-4\">\n @for (change of getPrimaryChanges(operation); track change.entityId + change.entityType) {\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0414\u043E\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-slate-100\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n }\n </div>\n }\n\n @if (getRelatedChanges(operation).length) {\n <div class=\"mt-4 border-t border-slate-100 pt-4\">\n <button\n type=\"button\"\n class=\"flex w-full items-center justify-between gap-3 text-left text-sm text-slate-600\"\n [attr.aria-expanded]=\"isExpanded(operation.id)\"\n (click)=\"toggleOperation(operation.id)\"\n >\n <span>\n \u0414\u0435\u0442\u0430\u043B\u0456 \u0437\u043C\u0456\u043D:\n <span class=\"font-medium text-slate-900\">{{ getAffectedSummary(operation) }}</span>\n </span>\n <span class=\"text-lg leading-none text-slate-400\">{{ isExpanded(operation.id) ? '\u2212' : '+' }}</span>\n </button>\n\n @if (isExpanded(operation.id)) {\n <div class=\"mt-4 space-y-4\">\n @for (change of getRelatedChanges(operation); track change.entityId + change.entityType) {\n <div class=\"rounded-xl bg-slate-50 p-3\">\n <p class=\"mb-2 text-xs font-semibold uppercase tracking-[0.16em] text-slate-500\">\n {{ getEntityLabel(change.entityType) }} \u00B7 {{ getActionLabel(change.action) }}\n </p>\n @for (field of (change.changedFields | keyvalue); track field.key) {\n <div class=\"flex flex-wrap items-center gap-2 text-sm\">\n <span class=\"font-medium text-slate-700\">{{ field.value.label }}</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.from).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0411\u0443\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.from); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-white px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0414\u043E\u0434\u0430\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.from.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.from.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.from.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u0441\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u0421\u0442\u0430\u0440\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [href]=\"field.value.from.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.from.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-500\" [innerHTML]=\"field.value.from.display\"></div>\n } @else {\n <span class=\"text-slate-400\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.from.url) {\n <a class=\"text-sky-700 underline\" [routerLink]=\"field.value.from.url\">{{ field.value.from.display }}</a>\n } @else {\n <span class=\"text-slate-400\">{{ field.value.from.display }}</span>\n }\n }\n <span class=\"mx-1 shrink-0 text-lg font-semibold text-slate-500\">\u2192</span>\n @if (isStructuredField(field.value)) {\n @if (getStructuredItems(field.value.to).length) {\n <div class=\"min-w-[16rem] flex-1 space-y-1\">\n <div class=\"text-[10px] font-semibold uppercase tracking-[0.16em] text-slate-400\">\u0421\u0442\u0430\u043B\u043E</div>\n @for (item of getStructuredItems(field.value.to); track item.key) {\n <div class=\"rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-xs text-slate-600\">\n @for (itemField of item.fields; track itemField.key) {<span class=\"mr-2\"><span class=\"font-medium\">{{ itemField.label }}:</span> {{ itemField.display }}</span>}\n </div>\n }\n </div>\n } @else { <span class=\"text-slate-400\">\u0412\u0438\u0434\u0430\u043B\u0435\u043D\u043E</span> }\n } @else if (isImageField(field.value)) {\n @if (getImageUrls(field.value.to.value).length) {\n <div class=\"flex flex-wrap items-center gap-2\">\n @for (url of getImageUrls(field.value.to.value); track url; let imageIndex = $index) {\n <button type=\"button\" class=\"h-14 w-14 overflow-hidden rounded-lg border border-slate-200 bg-white\" (click)=\"openImageViewer(getImageUrls(field.value.to.value))\" [attr.aria-label]=\"'\u0412\u0456\u0434\u043A\u0440\u0438\u0442\u0438 \u043D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\">\n <img [src]=\"url\" [alt]=\"'\u041D\u043E\u0432\u0435 \u0444\u043E\u0442\u043E ' + (imageIndex + 1)\" class=\"h-full w-full object-cover\" />\n </button>\n }\n </div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isFileField(field.value)) {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [href]=\"field.value.to.url\" target=\"_blank\" rel=\"noopener noreferrer\">\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 \u0444\u0430\u0439\u043B</a>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else if (isHtmlField(field.value)) {\n @if (field.value.to.display !== '\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E') {\n <div class=\"prose prose-sm max-w-none text-slate-900\" [innerHTML]=\"field.value.to.display\"></div>\n } @else {\n <span class=\"font-medium text-slate-900\">\u041D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E</span>\n }\n } @else {\n @if (field.value.to.url) {\n <a class=\"font-medium text-sky-700 underline\" [routerLink]=\"field.value.to.url\">{{ field.value.to.display }}</a>\n } @else {\n <span class=\"font-medium text-slate-900\">{{ field.value.to.display }}</span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n </article>\n }\n </div>\n }\n</section>\n\n@if (isViewerOpen()) {\n <app-images-viewer [urls]=\"viewerUrls()\" (closed)=\"closeImageViewer()\" />\n}\n" }]
1896
1889
  }], ctorParameters: () => [], propDecorators: { entity: [{ type: i0.Input, args: [{ isSignal: true, alias: "entity", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }] } });
1897
1890
 
1898
1891
  /**