@nettyapps/ntybase 21.0.34 → 21.0.35-beta.2

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,14 +1,13 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, Injectable, inject, NgModule, signal, input, output, computed, effect, ViewChild, model, InjectionToken, Optional, Inject, Input } from '@angular/core';
3
- import * as i1$2 from '@angular/common/http';
2
+ import { Component, Injectable, inject, NgModule, signal, input, computed, output, effect, ViewChild, model, Input, InjectionToken, Optional, Inject } from '@angular/core';
3
+ import * as i1$3 from '@angular/common/http';
4
4
  import { HttpErrorResponse, HttpResponse, HTTP_INTERCEPTORS, HttpClient, HttpHeaders } from '@angular/common/http';
5
- import { of, throwError, lastValueFrom, map, catchError as catchError$1, Subject, finalize, take as take$1, takeUntil } from 'rxjs';
5
+ import { of, throwError, Subject, lastValueFrom, map, catchError as catchError$1, finalize, take as take$1, takeUntil } from 'rxjs';
6
6
  import { catchError, map as map$1, take, finalize as finalize$1 } from 'rxjs/operators';
7
7
  import { Router, ActivatedRoute } from '@angular/router';
8
8
  import * as i2$1 from '@nettyapps/ntycontract';
9
- import { EnvironmentProxy } from '@nettyapps/ntycontract';
9
+ import { EnvironmentProxy, injectNettyStandardProxy, injectNettyStandardLogProxy } from '@nettyapps/ntycontract';
10
10
  import { DatePipe, CommonModule, Location, DecimalPipe } from '@angular/common';
11
- import { toSignal } from '@angular/core/rxjs-interop';
12
11
  import { Buffer } from 'buffer';
13
12
  import * as i1 from '@angular/material/dialog';
14
13
  import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog';
@@ -16,22 +15,23 @@ import * as i3 from '@angular/material/divider';
16
15
  import { MatDividerModule } from '@angular/material/divider';
17
16
  import * as i2 from '@angular/material/icon';
18
17
  import { MatIconModule } from '@angular/material/icon';
19
- import * as i1$1 from '@angular/material/snack-bar';
18
+ import * as i1$2 from '@angular/material/snack-bar';
20
19
  import { MatSnackBarModule } from '@angular/material/snack-bar';
21
- import * as i3$1 from '@ngx-translate/core';
20
+ import * as i1$1 from '@ngx-translate/core';
22
21
  import { TranslateModule, TranslateService } from '@ngx-translate/core';
23
22
  import { Mutex } from 'async-mutex';
24
- import { ModuleRegistry, AllCommunityModule, ClientSideRowModelModule, HighlightChangesModule, themeQuartz } from 'ag-grid-community';
25
- import { StatusBarModule, ClipboardModule, ExcelExportModule, ColumnMenuModule, ContextMenuModule, CellSelectionModule, RowSelectionModule } from 'ag-grid-enterprise';
23
+ import { themeQuartz, StatusBarModule, ClipboardModule, ExcelExportModule, ColumnMenuModule, ContextMenuModule, CellSelectionModule, RowSelectionModule } from 'ag-grid-enterprise';
24
+ import { toSignal } from '@angular/core/rxjs-interop';
25
+ import { ModuleRegistry, AllCommunityModule, ClientSideRowModelModule, HighlightChangesModule } from 'ag-grid-community';
26
26
  import * as i2$2 from '@angular/material/tooltip';
27
27
  import { MatTooltipModule } from '@angular/material/tooltip';
28
28
  import * as i2$3 from '@angular/material/menu';
29
29
  import { MatMenuModule } from '@angular/material/menu';
30
30
  import * as XLSX from 'xlsx';
31
31
  import { I18nService } from '@nettyapps/ntyi18n';
32
- import * as i1$3 from '@angular/forms';
32
+ import * as i1$4 from '@angular/forms';
33
33
  import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
34
- import * as i3$2 from '@angular/material/input';
34
+ import * as i3$1 from '@angular/material/input';
35
35
  import { MatInputModule } from '@angular/material/input';
36
36
  import { MatFormFieldModule } from '@angular/material/form-field';
37
37
 
@@ -310,84 +310,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
310
310
  }]
311
311
  }] });
312
312
 
313
- class NettyHelper {
314
- /**
315
- * Returns null if fields are equal otherwise return second field
316
- * @param firstField
317
- * @param secondField
318
- * @returns
319
- */
320
- static difference(firstField, secondField) {
321
- if (firstField != secondField) {
322
- return secondField;
323
- }
324
- return null;
325
- }
326
- /**
327
- * Returns null if fields are equal otherwise return second field
328
- * @param firstField
329
- * @param secondField
330
- * @param format
331
- * @returns
332
- */
333
- static dateDifference(firstField, secondField, format) {
334
- let culture = localStorage.getItem('languageApiCode') ?? 'tr-TR';
335
- let datePipe = new DatePipe(culture);
336
- if (datePipe.transform(firstField, format) !=
337
- datePipe.transform(secondField, format)) {
338
- return secondField;
339
- }
340
- return null;
341
- }
342
- }
343
-
344
- class CurrentUserPreference {
345
- coid = null;
346
- nettyUserPreferenceGUID = null;
347
- nettyUserGUID = null;
348
- nettyUserName = null;
349
- nettyUserFullName = null;
350
- nettyPreferenceType = null;
351
- nettyPreferenceData = null;
352
- init() {
353
- this.coid = null;
354
- this.nettyUserPreferenceGUID = null;
355
- this.nettyUserGUID = null;
356
- this.nettyUserName = '';
357
- this.nettyUserFullName = '';
358
- this.nettyPreferenceType = '';
359
- this.nettyPreferenceData = '';
360
- }
361
- initParameter(parameters) {
362
- if (parameters == null || parameters == undefined) {
363
- this.init();
364
- return;
365
- }
366
- this.coid = parameters.coid;
367
- this.nettyUserPreferenceGUID = parameters.nettyUserPreferenceGUID;
368
- this.nettyUserGUID = parameters.nettyUserGUID;
369
- this.nettyUserName = parameters.nettyUserName;
370
- this.nettyUserFullName = parameters.nettyUserFullName;
371
- this.nettyPreferenceType = parameters.nettyPreferenceType;
372
- this.nettyPreferenceData = parameters.nettyPreferenceData;
373
- }
374
- compare(record) {
375
- let newRecord = new CurrentUserPreference();
376
- newRecord.init();
377
- newRecord.coid = record.coid;
378
- newRecord.nettyUserPreferenceGUID = record.nettyUserPreferenceGUID;
379
- newRecord.nettyUserGUID = NettyHelper.difference(this.nettyUserGUID, record.nettyUserGUID);
380
- newRecord.nettyPreferenceType = NettyHelper.difference(this.nettyPreferenceType, record.nettyPreferenceType);
381
- newRecord.nettyPreferenceData = NettyHelper.difference(this.nettyPreferenceData, record.nettyPreferenceData);
382
- return newRecord;
383
- }
384
- }
385
-
386
313
  class ConfirmDialog {
387
314
  dialogRef = inject((MatDialogRef));
388
315
  data = inject(MAT_DIALOG_DATA);
389
316
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ConfirmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
390
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ConfirmDialog, isStandalone: true, selector: "ntybase-confirm-dialog", ngImport: i0, template: "<div class=\"dialog-container\">\n <h2 mat-dialog-title class=\"dialog-title\">\n <mat-icon color=\"warn\" class=\"warning-icon\">warning</mat-icon>\n <span>{{data.title}}</span>\n </h2>\n\n <mat-divider class=\"divider\"></mat-divider>\n\n <mat-dialog-content class=\"dialog-content\">\n <p class=\"message\">{{data.message}}</p>\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button mat-stroked-button [mat-dialog-close]=\"false\" class=\"btn-cancel\">\n {{'@btnCancel' | translate}}\n </button>\n <button\n mat-flat-button\n color=\"warn\"\n [mat-dialog-close]=\"true\"\n class=\"btn-ok\"\n >\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{display:flex;flex-direction:column;min-width:400px;max-width:90vw;padding:24px;border-radius:12px!important}.dialog-title{display:flex;align-items:center;margin:0 0 12px;padding:0;color:var(--mat-sys-primary)}.dialog-title span{margin-left:8px}.warning-icon{color:var(--mat-sys-primary);transform:scale(1.2)}.divider{margin:8px 0 16px;border-top-color:var(--mat-sys-primary)}.dialog-content{padding:8px 0 24px;margin:0;color:var(--mat-sys-primary);line-height:1.6}.dialog-content .message{margin:0;white-space:pre-wrap}.dialog-actions{padding:16px 0 0;margin:0;gap:8px}.btn-ok{padding:8px 16px;border-radius:6px;font-weight:500;background-color:var(--mat-sys-primary);color:var(--mat-sys-primary-container)}.btn-cancel{padding:8px 16px;border-radius:6px;color:var(--mat-sys-secondary-container);background-color:var(--mat-sys-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
317
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ConfirmDialog, isStandalone: true, selector: "ntybase-confirm-dialog", ngImport: i0, template: "<div class=\"dialog-container\">\n <h2 mat-dialog-title class=\"dialog-title\">\n <mat-icon color=\"warn\" class=\"warning-icon\">warning</mat-icon>\n <span>{{data.title}}</span>\n </h2>\n\n <mat-divider class=\"divider\"></mat-divider>\n\n <mat-dialog-content class=\"dialog-content\">\n <p class=\"message\">{{data.message}}</p>\n </mat-dialog-content>\n\n <mat-dialog-actions align=\"end\" class=\"dialog-actions\">\n <button mat-stroked-button [mat-dialog-close]=\"false\" class=\"btn-cancel\">\n {{'@btnCancel' | translate}}\n </button>\n <button\n mat-flat-button\n color=\"warn\"\n [mat-dialog-close]=\"true\"\n class=\"btn-ok\"\n >\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".dialog-container{display:flex;flex-direction:column;min-width:400px;max-width:90vw;padding:24px;border-radius:12px!important}.dialog-title{display:flex;align-items:center;margin:0 0 12px;padding:0;color:var(--mat-sys-primary)}.dialog-title span{margin-left:8px}.warning-icon{color:var(--mat-sys-primary);transform:scale(1.2)}.divider{margin:8px 0 16px;border-top-color:var(--mat-sys-primary)}.dialog-content{padding:8px 0 24px;margin:0;color:var(--mat-sys-primary);line-height:1.6}.dialog-content .message{margin:0;white-space:pre-wrap}.dialog-actions{padding:16px 0 0;margin:0;gap:8px}.btn-ok{padding:8px 16px;border-radius:6px;font-weight:500;background-color:var(--mat-sys-primary);color:var(--mat-sys-primary-container)}.btn-cancel{padding:8px 16px;border-radius:6px;color:var(--mat-sys-secondary-container);background-color:var(--mat-sys-secondary)}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
391
318
  }
392
319
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ConfirmDialog, decorators: [{
393
320
  type: Component,
@@ -404,7 +331,7 @@ class ErrorAlert {
404
331
  dialogRef = inject((MatDialogRef));
405
332
  data = inject(MAT_DIALOG_DATA);
406
333
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ErrorAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
407
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ErrorAlert, isStandalone: true, selector: "ntybase-error-alert", ngImport: i0, template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title }}</h2>\n </div>\n\n <div class=\"error-content\">\n <p>{{ data.message }}</p>\n </div>\n\n <mat-dialog-actions class=\"dialog-actions\">\n <button mat-flat-button [mat-dialog-close]=\"true\" class=\"btn-ok\">\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".error-dialog-container{padding:40px 32px;text-align:center;min-width:380px;max-width:450px;background:var(--mat-sys-primary);border-radius:20px;box-shadow:0 15px 35px #00000012}.error-dialog-container .header{display:flex;flex-direction:column;align-items:center;gap:12px}.error-dialog-container .header mat-icon{font-size:52px;width:52px;height:52px;color:var(--mat-sys-inverse-primary);margin-bottom:8px}.error-dialog-container .header .error-title{margin:0;font-size:1.4rem;font-weight:700;color:var(--mat-sys-surface);letter-spacing:-.02em}.error-dialog-container .error-content{margin:24px 0 32px;font-size:1rem;line-height:1.6;color:var(--mat-sys-surface)}.error-dialog-container .dialog-actions{display:flex;justify-content:center;padding:0;margin:0}.error-dialog-container .btn-ok{min-width:120px;padding:12px 24px;font-weight:600;font-size:1rem;border-radius:10px;background:var(--mat-sys-inverse-primary);color:var(--mat-sys-primary);border:none;cursor:pointer;transition:all .2s ease}.error-dialog-container .btn-ok:hover{background:var(--mat-sys-inverse-primary);opacity:.9;box-shadow:0 5px 15px #0000001a}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
334
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ErrorAlert, isStandalone: true, selector: "ntybase-error-alert", ngImport: i0, template: "<div class=\"error-dialog-container\">\n <div class=\"header\">\n <mat-icon color=\"error\">error_outline</mat-icon>\n <h2 class=\"error-title\">{{ data.title }}</h2>\n </div>\n\n <div class=\"error-content\">\n <p>{{ data.message }}</p>\n </div>\n\n <mat-dialog-actions class=\"dialog-actions\">\n <button mat-flat-button [mat-dialog-close]=\"true\" class=\"btn-ok\">\n {{'@btnOK' | translate}}\n </button>\n </mat-dialog-actions>\n</div>\n", styles: [".error-dialog-container{padding:40px 32px;text-align:center;min-width:380px;max-width:450px;background:var(--mat-sys-primary);border-radius:20px;box-shadow:0 15px 35px #00000012}.error-dialog-container .header{display:flex;flex-direction:column;align-items:center;gap:12px}.error-dialog-container .header mat-icon{font-size:52px;width:52px;height:52px;color:var(--mat-sys-inverse-primary);margin-bottom:8px}.error-dialog-container .header .error-title{margin:0;font-size:1.4rem;font-weight:700;color:var(--mat-sys-surface);letter-spacing:-.02em}.error-dialog-container .error-content{margin:24px 0 32px;font-size:1rem;line-height:1.6;color:var(--mat-sys-surface)}.error-dialog-container .dialog-actions{display:flex;justify-content:center;padding:0;margin:0}.error-dialog-container .btn-ok{min-width:120px;padding:12px 24px;font-weight:600;font-size:1rem;border-radius:10px;background:var(--mat-sys-inverse-primary);color:var(--mat-sys-primary);border:none;cursor:pointer;transition:all .2s ease}.error-dialog-container .btn-ok:hover{background:var(--mat-sys-inverse-primary);opacity:.9;box-shadow:0 5px 15px #0000001a}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
408
335
  }
409
336
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ErrorAlert, decorators: [{
410
337
  type: Component,
@@ -484,7 +411,7 @@ class AlertService {
484
411
  });
485
412
  });
486
413
  }
487
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, deps: [{ token: i1$1.MatSnackBar }, { token: i1.MatDialog }, { token: i3$1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
414
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, deps: [{ token: i1$2.MatSnackBar }, { token: i1.MatDialog }, { token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable });
488
415
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, providedIn: 'root' });
489
416
  }
490
417
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, decorators: [{
@@ -492,125 +419,321 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
492
419
  args: [{
493
420
  providedIn: 'root',
494
421
  }]
495
- }], ctorParameters: () => [{ type: i1$1.MatSnackBar }, { type: i1.MatDialog }, { type: i3$1.TranslateService }] });
422
+ }], ctorParameters: () => [{ type: i1$2.MatSnackBar }, { type: i1.MatDialog }, { type: i1$1.TranslateService }] });
496
423
 
497
- class CommonService {
498
- // Services
499
- router = inject(Router);
500
- location = inject(Location);
501
- datePipe = inject(DatePipe);
502
- decimalPipe = inject(DecimalPipe);
424
+ class NettyAppsBase {
425
+ // ---------------------------------
426
+ // --- SERVICES ---
427
+ // ---------------------------------
503
428
  alertService = inject(AlertService);
504
- translate = inject(TranslateService);
505
- dialog = inject(MatDialog);
506
- // Right sidenav
507
- rightSidenavOpen = signal(false, ...(ngDevMode ? [{ debugName: "rightSidenavOpen" }] : []));
508
- toggleRightSidenav(open) {
509
- this.rightSidenavOpen.set(open);
510
- }
429
+ translateService = inject(TranslateService);
430
+ // ---------------------------------
431
+ // --- DOWNLOAD METHODS ---
432
+ // ---------------------------------
511
433
  /**
512
- * Normalizes Turkish text for search and comparison operations by converting
513
- * Turkish special characters to their English equivalents and lowercasing.
434
+ * Download the given base64Encoded data as file
514
435
  *
436
+ * @param base64Data: base64 encoded data
437
+ * @param fileName: filename to download
515
438
  */
516
- normalizeTurkish(text) {
517
- return text
518
- .toLocaleLowerCase('tr-TR')
519
- .replace(/[ıİ]/g, 'i')
520
- .replace(/[ğĞ]/g, 'g')
521
- .replace(/[üÜ]/g, 'u')
522
- .replace(/[şŞ]/g, 's')
523
- .replace(/[öÖ]/g, 'o')
524
- .replace(/[çÇ]/g, 'c');
525
- }
526
- /**
527
- * Gets the clean URL path without fragments or query params
528
- */
529
- getCleanUrlPath() {
530
- const tree = this.router.parseUrl(this.router.url);
531
- const segments = tree.root.children['primary']?.segments || [];
532
- if (segments.length >= 2) {
533
- return segments
534
- .slice(0, 2)
535
- .map((s) => s.path)
536
- .join('/');
439
+ downloadFile(base64Data, fileName) {
440
+ if (base64Data == null) {
441
+ return;
537
442
  }
538
- return '/';
539
- }
540
- /**
541
- * Clears the right sidenav outlet and resets the UI state.
542
- * Removes the right sidenav route while keeping the main content and query parameters.
543
- * Also collapses the sidenav and closes any open dialogs.
544
- */
545
- clearOutlet() {
546
- const currentUrl = this.router.parseUrl(this.router.url);
547
- const primaryOutlet = currentUrl.root.children['primary'];
548
- const rightSidenavOutlet = currentUrl.root.children['rightSidenav'];
549
- if (rightSidenavOutlet ||
550
- currentUrl.queryParams['parameters'] ||
551
- currentUrl.queryParams['type']) {
552
- this.router.navigate([
553
- {
554
- outlets: {
555
- rightSidenav: null,
556
- primary: primaryOutlet ? primaryOutlet.toString() : null,
557
- },
558
- },
559
- ], {
560
- queryParams: {},
561
- queryParamsHandling: '',
562
- replaceUrl: true,
563
- });
443
+ if (fileName == null) {
444
+ return;
564
445
  }
565
- this.toggleRightSidenav(false);
566
- this.dialog.closeAll();
567
- }
568
- ngOnDestroy() {
569
- this.clearOutlet();
446
+ // Check if header is present
447
+ if (!base64Data.startsWith('data:')) {
448
+ console.error('Provided data is not in base64 format (missing header)');
449
+ return;
450
+ }
451
+ const contentType = base64Data.split(';')[0].split(':')[1];
452
+ const byteCharacters = atob(base64Data.split(',')[1]);
453
+ const byteArrays = [];
454
+ for (let i = 0; i < byteCharacters.length; i++) {
455
+ const byteArray = byteCharacters.charCodeAt(i);
456
+ byteArrays.push(byteArray);
457
+ }
458
+ const byteArray = new Uint8Array(byteArrays);
459
+ const blob = new Blob([byteArray], { type: contentType });
460
+ const link = document.createElement('a');
461
+ link.href = URL.createObjectURL(blob);
462
+ link.download = fileName;
463
+ link.click();
570
464
  }
571
- /** Merge columns with the given seperator
465
+ /** Download the given base64Endoced data as text file
572
466
  *
573
- * @param columns string array to merge
574
- * @param seperator seperator for the array. space if null
575
- * @returns merged string
467
+ * @param base64EncodedFileData
468
+ * @param fileName
576
469
  */
577
- mergeColumns(columns, seperator = ' ') {
578
- console.log('mergeColumns', columns);
579
- let result = '';
580
- columns.forEach((column) => {
581
- if (!(column == undefined || column == null)) {
582
- if (result.length > 0) {
583
- result += seperator;
584
- }
585
- result += column.trim();
586
- }
587
- });
588
- return result.trim();
470
+ downloadTextFile(base64EncodedFileData, fileName) {
471
+ // Check if the data has a prefix like "data:application/pdf;base64,"
472
+ if (base64EncodedFileData == null) {
473
+ return;
474
+ }
475
+ if (fileName == null) {
476
+ return;
477
+ }
478
+ let _data = base64EncodedFileData;
479
+ const prefix = 'data:';
480
+ if (_data.startsWith(prefix)) {
481
+ // Remove the prefix
482
+ _data = _data.slice(_data.indexOf(',') + 1);
483
+ }
484
+ // Convert the base64 data to a Uint8Array
485
+ const textData = Buffer.from(_data ?? '', 'base64').toString();
486
+ this.downloadTextFileNotEncoded(textData, fileName);
589
487
  }
590
- /** Go back to the last page or close the tab
488
+ /** Save the given text as a text file
591
489
  *
490
+ * @param fileData
491
+ * @param fileName
592
492
  */
593
- goBack() {
594
- if (!document.referrer) {
595
- this.location.back();
493
+ downloadTextFileNotEncoded(fileData, fileName) {
494
+ if (fileData == null) {
495
+ return;
596
496
  }
597
- else {
598
- window.close();
497
+ if (fileName == null) {
498
+ return;
599
499
  }
500
+ // Create a Blob from the Text
501
+ const blob = new Blob([fileData], { type: 'text/plain' });
502
+ // Create a download link
503
+ const url = window.URL.createObjectURL(blob);
504
+ const a = document.createElement('a');
505
+ document.body.appendChild(a);
506
+ a.style.display = 'none';
507
+ a.href = url;
508
+ a.download = fileName ?? 'filename';
509
+ // Trigger the download
510
+ a.click();
511
+ // Clean up
512
+ window.URL.revokeObjectURL(url);
513
+ document.body.removeChild(a);
600
514
  }
601
- // General Functions
602
- //--------------------------------------
603
- /** Delay for the given duration
604
- *
605
- * @param ms wait duration in ms
606
- * @returns promise that waits for the duration
515
+ /**
516
+ * Download file where the data is provided as blob
517
+ * @param data - Array Buffer data
518
+ * @param type - type of the document.
607
519
  */
608
- delay(ms) {
609
- return new Promise((resolve) => setTimeout(resolve, ms));
610
- }
611
- // Base64 Functions
612
- //--------------------------------------
613
- /** Convert string to base64
520
+ downloadBlobFile(data, type, fileName) {
521
+ let blob = new Blob([data], { type: type });
522
+ let downloadLink = document.createElement('a');
523
+ downloadLink.href = window.URL.createObjectURL(blob);
524
+ downloadLink.setAttribute('download', fileName);
525
+ document.body.appendChild(downloadLink);
526
+ downloadLink.click();
527
+ downloadLink.parentNode?.removeChild(downloadLink);
528
+ }
529
+ // ---------------------------------
530
+ // --- INTERFACE IMPLEMENTATIONS ---
531
+ // ---------------------------------
532
+ onDestroy$ = new Subject();
533
+ ngOnDestroy() {
534
+ //Called once, before the instance is destroyed.
535
+ //Add 'implements OnDestroy' to the class.
536
+ this.onDestroy$.next();
537
+ this.onDestroy$.complete();
538
+ }
539
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
540
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: NettyAppsBase, isStandalone: true, selector: "ntybase-netty-apps-base", ngImport: i0, template: ``, isInline: true });
541
+ }
542
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, decorators: [{
543
+ type: Component,
544
+ args: [{ selector: 'ntybase-netty-apps-base', imports: [], template: `` }]
545
+ }] });
546
+
547
+ class NettyHelper {
548
+ /**
549
+ * Returns null if fields are equal otherwise return second field
550
+ * @param firstField
551
+ * @param secondField
552
+ * @returns
553
+ */
554
+ static difference(firstField, secondField) {
555
+ if (firstField != secondField) {
556
+ return secondField;
557
+ }
558
+ return null;
559
+ }
560
+ /**
561
+ * Returns null if fields are equal otherwise return second field
562
+ * @param firstField
563
+ * @param secondField
564
+ * @param format
565
+ * @returns
566
+ */
567
+ static dateDifference(firstField, secondField, format) {
568
+ let culture = localStorage.getItem('languageApiCode') ?? 'tr-TR';
569
+ let datePipe = new DatePipe(culture);
570
+ if (datePipe.transform(firstField, format) !=
571
+ datePipe.transform(secondField, format)) {
572
+ return secondField;
573
+ }
574
+ return null;
575
+ }
576
+ }
577
+
578
+ class CurrentUserPreference {
579
+ coid = null;
580
+ nettyUserPreferenceGUID = null;
581
+ nettyUserGUID = null;
582
+ nettyUserName = null;
583
+ nettyUserFullName = null;
584
+ nettyPreferenceType = null;
585
+ nettyPreferenceData = null;
586
+ init() {
587
+ this.coid = null;
588
+ this.nettyUserPreferenceGUID = null;
589
+ this.nettyUserGUID = null;
590
+ this.nettyUserName = '';
591
+ this.nettyUserFullName = '';
592
+ this.nettyPreferenceType = '';
593
+ this.nettyPreferenceData = '';
594
+ }
595
+ initParameter(parameters) {
596
+ if (parameters == null || parameters == undefined) {
597
+ this.init();
598
+ return;
599
+ }
600
+ this.coid = parameters.coid;
601
+ this.nettyUserPreferenceGUID = parameters.nettyUserPreferenceGUID;
602
+ this.nettyUserGUID = parameters.nettyUserGUID;
603
+ this.nettyUserName = parameters.nettyUserName;
604
+ this.nettyUserFullName = parameters.nettyUserFullName;
605
+ this.nettyPreferenceType = parameters.nettyPreferenceType;
606
+ this.nettyPreferenceData = parameters.nettyPreferenceData;
607
+ }
608
+ compare(record) {
609
+ let newRecord = new CurrentUserPreference();
610
+ newRecord.init();
611
+ newRecord.coid = record.coid;
612
+ newRecord.nettyUserPreferenceGUID = record.nettyUserPreferenceGUID;
613
+ newRecord.nettyUserGUID = NettyHelper.difference(this.nettyUserGUID, record.nettyUserGUID);
614
+ newRecord.nettyPreferenceType = NettyHelper.difference(this.nettyPreferenceType, record.nettyPreferenceType);
615
+ newRecord.nettyPreferenceData = NettyHelper.difference(this.nettyPreferenceData, record.nettyPreferenceData);
616
+ return newRecord;
617
+ }
618
+ }
619
+
620
+ class CommonService {
621
+ // Services
622
+ router = inject(Router);
623
+ location = inject(Location);
624
+ datePipe = inject(DatePipe);
625
+ decimalPipe = inject(DecimalPipe);
626
+ alertService = inject(AlertService);
627
+ translate = inject(TranslateService);
628
+ dialog = inject(MatDialog);
629
+ // Right sidenav
630
+ rightSidenavOpen = signal(false, ...(ngDevMode ? [{ debugName: "rightSidenavOpen" }] : []));
631
+ toggleRightSidenav(open) {
632
+ this.rightSidenavOpen.set(open);
633
+ }
634
+ /**
635
+ * Normalizes Turkish text for search and comparison operations by converting
636
+ * Turkish special characters to their English equivalents and lowercasing.
637
+ *
638
+ */
639
+ normalizeTurkish(text) {
640
+ return text
641
+ .toLocaleLowerCase('tr-TR')
642
+ .replace(/[ıİ]/g, 'i')
643
+ .replace(/[ğĞ]/g, 'g')
644
+ .replace(/[üÜ]/g, 'u')
645
+ .replace(/[şŞ]/g, 's')
646
+ .replace(/[öÖ]/g, 'o')
647
+ .replace(/[çÇ]/g, 'c');
648
+ }
649
+ /**
650
+ * Gets the clean URL path without fragments or query params
651
+ */
652
+ getCleanUrlPath() {
653
+ const tree = this.router.parseUrl(this.router.url);
654
+ const segments = tree.root.children['primary']?.segments || [];
655
+ if (segments.length >= 2) {
656
+ return segments
657
+ .slice(0, 2)
658
+ .map((s) => s.path)
659
+ .join('/');
660
+ }
661
+ return '/';
662
+ }
663
+ /**
664
+ * Clears the right sidenav outlet and resets the UI state.
665
+ * Removes the right sidenav route while keeping the main content and query parameters.
666
+ * Also collapses the sidenav and closes any open dialogs.
667
+ */
668
+ clearOutlet() {
669
+ const currentUrl = this.router.parseUrl(this.router.url);
670
+ const primaryOutlet = currentUrl.root.children['primary'];
671
+ const rightSidenavOutlet = currentUrl.root.children['rightSidenav'];
672
+ if (rightSidenavOutlet ||
673
+ currentUrl.queryParams['parameters'] ||
674
+ currentUrl.queryParams['type']) {
675
+ this.router.navigate([
676
+ {
677
+ outlets: {
678
+ rightSidenav: null,
679
+ primary: primaryOutlet ? primaryOutlet.toString() : null,
680
+ },
681
+ },
682
+ ], {
683
+ queryParams: {},
684
+ queryParamsHandling: '',
685
+ replaceUrl: true,
686
+ });
687
+ }
688
+ this.toggleRightSidenav(false);
689
+ this.dialog.closeAll();
690
+ }
691
+ ngOnDestroy() {
692
+ this.clearOutlet();
693
+ }
694
+ /** Merge columns with the given seperator
695
+ *
696
+ * @param columns string array to merge
697
+ * @param seperator seperator for the array. space if null
698
+ * @returns merged string
699
+ */
700
+ mergeColumns(columns, seperator = ' ') {
701
+ console.log('mergeColumns', columns);
702
+ let result = '';
703
+ columns.forEach((column) => {
704
+ if (!(column == undefined || column == null)) {
705
+ if (result.length > 0) {
706
+ result += seperator;
707
+ }
708
+ result += column.trim();
709
+ }
710
+ });
711
+ return result.trim();
712
+ }
713
+ /** Go back to the last page or close the tab
714
+ *
715
+ */
716
+ goBack() {
717
+ if (!document.referrer) {
718
+ this.location.back();
719
+ }
720
+ else {
721
+ window.close();
722
+ }
723
+ }
724
+ // General Functions
725
+ //--------------------------------------
726
+ /** Delay for the given duration
727
+ *
728
+ * @param ms wait duration in ms
729
+ * @returns promise that waits for the duration
730
+ */
731
+ delay(ms) {
732
+ return new Promise((resolve) => setTimeout(resolve, ms));
733
+ }
734
+ // Base64 Functions
735
+ //--------------------------------------
736
+ /** Convert string to base64
614
737
  *
615
738
  * @param stringForConversion
616
739
  * @returns
@@ -751,6 +874,7 @@ class NettyAgGridService {
751
874
  nettyAlertService = inject(AlertService);
752
875
  environmentProxy = inject(EnvironmentProxy);
753
876
  commonService = inject(CommonService);
877
+ translateService = inject(TranslateService);
754
878
  constructor() {
755
879
  this.userPreferenceLock = new Mutex();
756
880
  }
@@ -976,447 +1100,384 @@ class NettyAgGridService {
976
1100
  },
977
1101
  ];
978
1102
  }
979
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
980
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, providedIn: 'root' });
981
- }
982
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, decorators: [{
983
- type: Injectable,
984
- args: [{
985
- providedIn: 'root',
986
- }]
987
- }], ctorParameters: () => [] });
988
-
989
- class SecurityDto {
990
- coid = null;
991
- userGUID = null;
992
- application = '';
993
- formCode = '';
994
- }
995
-
996
- class SysfunctionProxy {
997
- http;
998
- environmentProxy;
999
- constructor(http, environmentProxy) {
1000
- this.http = http;
1001
- this.environmentProxy = environmentProxy;
1002
- }
1003
- /** Get the authentication list for the given form
1004
- *
1005
- * @param formCode
1006
- * @returns
1007
- */
1008
- getAuthentication(formCode) {
1009
- let sysFunctionsURL = this.environmentProxy.getAdminLink('getAuthentication');
1010
- let securityDto = new SecurityDto();
1011
- securityDto.formCode = formCode;
1012
- securityDto.application = this.environmentProxy.getApplicationName();
1013
- let call$ = this.http.post(sysFunctionsURL, securityDto);
1014
- return call$.pipe(map((result) => result), catchError$1((error) => {
1015
- let errorMessage = error.message; //.error.title;
1016
- return throwError(() => new Error(errorMessage ?? ''));
1017
- }));
1018
- }
1019
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, deps: [{ token: i1$2.HttpClient }, { token: i2$1.EnvironmentProxy }], target: i0.ɵɵFactoryTarget.Injectable });
1020
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, providedIn: 'root' });
1103
+ setAgGridTranslations(gridApi) {
1104
+ if (gridApi) {
1105
+ gridApi.setGridOption('localeText', {
1106
+ // Status panel translate
1107
+ totalRows: this.translateService.instant('AG_GRID.TOTAL_ROWS'),
1108
+ filteredRows: this.translateService.instant('AG_GRID.FILTERED_ROWS'),
1109
+ selectedRows: this.translateService.instant('AG_GRID.SELECTED_ROWS'),
1110
+ noRowsToShow: this.translateService.instant('AG_GRID.NO_ROWS_TO_SHOW'),
1111
+ loadingOoo: this.translateService.instant('AG_GRID.LOADING'),
1112
+ // Context menu translations
1113
+ copy: this.translateService.instant('AG_GRID.COPY'),
1114
+ copyWithHeaders: this.translateService.instant('AG_GRID.COPY_WITH_HEADERS'),
1115
+ copyWithGroupHeaders: this.translateService.instant('AG_GRID.COPY_WITH_GROUP_HEADERS'),
1116
+ paste: this.translateService.instant('AG_GRID.PASTE'),
1117
+ export: this.translateService.instant('AG_GRID.EXPORT'),
1118
+ csvExport: this.translateService.instant('AG_GRID.CSV_EXPORT'),
1119
+ excelExport: this.translateService.instant('AG_GRID.EXCEL_EXPORT'),
1120
+ pinColumn: this.translateService.instant('AG_GRID.PIN_COLUMN'),
1121
+ pinLeft: this.translateService.instant('AG_GRID.PIN_LEFT'),
1122
+ pinRight: this.translateService.instant('AG_GRID.PIN_RIGHT'),
1123
+ noPin: this.translateService.instant('AG_GRID.NO_PIN'),
1124
+ sortAscending: this.translateService.instant('AG_GRID.SORT_ASCENDING'),
1125
+ sortDescending: this.translateService.instant('AG_GRID.SORT_DESCENDING'),
1126
+ autosizeThisColumn: this.translateService.instant('AG_GRID.AUTOSIZE_THIS_COLUMN'),
1127
+ autosizeAllColumns: this.translateService.instant('AG_GRID.AUTOSIZE_ALL_COLUMNS'),
1128
+ resetColumns: this.translateService.instant('AG_GRID.RESET_COLUMNS'),
1129
+ expandAll: this.translateService.instant('AG_GRID.EXPAND_ALL'),
1130
+ collapseAll: this.translateService.instant('AG_GRID.COLLAPSE_ALL'),
1131
+ exportToExcel: this.translateService.instant('AG_GRID.EXPORT_TO_EXCEL'),
1132
+ sheetName: this.translateService.instant('AG_GRID.SHEET_NAME'),
1133
+ exportAsExcelTable: this.translateService.instant('AG_GRID.EXPORT_AS_EXCEL_TABLE'),
1134
+ rangeSelectTo: this.translateService.instant('AG_GRID.RANGE_SELECT_TO'),
1135
+ rangeSelectFrom: this.translateService.instant('AG_GRID.RANGE_SELECT_FROM'),
1136
+ rangeSelectCopy: this.translateService.instant('AG_GRID.RANGE_SELECT_COPY'),
1137
+ rangeSelectChart: this.translateService.instant('AG_GRID.RANGE_SELECT_CHART'),
1138
+ pasteAll: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE'),
1139
+ pasteWithoutHeader: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE_WITHOUT_HEADER'),
1140
+ copyAll: this.translateService.instant('AG_GRID.CLIPBOARD_COPY'),
1141
+ cut: this.translateService.instant('AG_GRID.CLIPBOARD_CUT'),
1142
+ // Pagination translations
1143
+ page: this.translateService.instant('AG_GRID.PAGE'),
1144
+ more: this.translateService.instant('AG_GRID.MORE'),
1145
+ to: this.translateService.instant('AG_GRID.TO'),
1146
+ of: this.translateService.instant('AG_GRID.OF'),
1147
+ next: this.translateService.instant('AG_GRID.NEXT'),
1148
+ last: this.translateService.instant('AG_GRID.LAST'),
1149
+ first: this.translateService.instant('AG_GRID.FIRST'),
1150
+ previous: this.translateService.instant('AG_GRID.PREVIOUS'),
1151
+ pageSizeSelectorLabel: this.translateService.instant('AG_GRID.PAGE_SIZE_SELECTOR_LABEL'),
1152
+ // Set Filter
1153
+ selectAll: this.translateService.instant('AG_GRID.SELECT_ALL'),
1154
+ selectAllSearchResults: this.translateService.instant('AG_GRID.SELECT_ALL_SEARCH_RESULTS'),
1155
+ searchOoo: this.translateService.instant('AG_GRID.SEARCH_OOO'),
1156
+ blanks: this.translateService.instant('AG_GRID.BLANKS'),
1157
+ noMatches: this.translateService.instant('AG_GRID.NO_MATCHES'),
1158
+ // Number Filter & Text Filter
1159
+ filterOoo: this.translateService.instant('AG_GRID.FILTER_OOO'),
1160
+ equals: this.translateService.instant('AG_GRID.EQUALS'),
1161
+ notEqual: this.translateService.instant('AG_GRID.NOT_EQUAL'),
1162
+ blank: this.translateService.instant('AG_GRID.BLANK'),
1163
+ notBlank: this.translateService.instant('AG_GRID.NOT_BLANK'),
1164
+ empty: this.translateService.instant('AG_GRID.EMPTY'),
1165
+ // Number Filter
1166
+ lessThan: this.translateService.instant('AG_GRID.LESS_THAN'),
1167
+ greaterThan: this.translateService.instant('AG_GRID.GREATER_THAN'),
1168
+ lessThanOrEqual: this.translateService.instant('AG_GRID.LESS_THAN_OR_EQUAL'),
1169
+ greaterThanOrEqual: this.translateService.instant('AG_GRID.GREATER_THAN_OR_EQUAL'),
1170
+ inRange: this.translateService.instant('AG_GRID.IN_RANGE'),
1171
+ inRangeStart: this.translateService.instant('AG_GRID.IN_RANGE_START'),
1172
+ inRangeEnd: this.translateService.instant('AG_GRID.IN_RANGE_END'),
1173
+ // Text Filter
1174
+ contains: this.translateService.instant('AG_GRID.CONTAINS'),
1175
+ notContains: this.translateService.instant('AG_GRID.NOT_CONTAINS'),
1176
+ startsWith: this.translateService.instant('AG_GRID.STARTS_WITH'),
1177
+ endsWith: this.translateService.instant('AG_GRID.ENDS_WITH'),
1178
+ // Date Filter
1179
+ dateFormatOoo: this.translateService.instant('AG_GRID.DATE_FORMAT_OOO'),
1180
+ // Filter Conditions
1181
+ andCondition: this.translateService.instant('AG_GRID.AND_CONDITION'),
1182
+ orCondition: this.translateService.instant('AG_GRID.OR_CONDITION'),
1183
+ // Filter Buttons
1184
+ applyFilter: this.translateService.instant('AG_GRID.APPLY_FILTER'),
1185
+ resetFilter: this.translateService.instant('AG_GRID.RESET_FILTER'),
1186
+ clearFilter: this.translateService.instant('AG_GRID.CLEAR_FILTER'),
1187
+ cancelFilter: this.translateService.instant('AG_GRID.CANCEL_FILTER'),
1188
+ // Filter Titles
1189
+ textFilter: this.translateService.instant('AG_GRID.TEXT_FILTER'),
1190
+ numberFilter: this.translateService.instant('AG_GRID.NUMBER_FILTER'),
1191
+ dateFilter: this.translateService.instant('AG_GRID.DATE_FILTER'),
1192
+ setFilter: this.translateService.instant('AG_GRID.SET_FILTER'),
1193
+ });
1194
+ }
1195
+ }
1196
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1197
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, providedIn: 'root' });
1021
1198
  }
1022
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, decorators: [{
1199
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, decorators: [{
1023
1200
  type: Injectable,
1024
1201
  args: [{
1025
1202
  providedIn: 'root',
1026
1203
  }]
1027
- }], ctorParameters: () => [{ type: i1$2.HttpClient }, { type: i2$1.EnvironmentProxy }] });
1204
+ }], ctorParameters: () => [] });
1028
1205
 
1029
- class ButtonRenderer {
1030
- params = null;
1031
- label = '';
1032
- type = '';
1033
- toggleValue = null;
1034
- editValid = false;
1035
- historyValid = false;
1036
- lineValid = false;
1037
- popupSelectValid = false;
1038
- popupEditValid = false;
1039
- toggleValid = false;
1040
- toggle_icon = '';
1041
- none = false;
1042
- addValid = false;
1043
- deleteValid = false;
1044
- agInit(params) {
1045
- this.params = params;
1046
- this.type = this.params.type || null;
1047
- this.label = this.params.label || null;
1048
- this.toggleValue = this.params.value || null;
1049
- switch (this.toggleValue) {
1050
- case true:
1051
- this.toggle_icon = 'select_check_box';
1052
- break;
1053
- case false:
1054
- this.toggle_icon = 'check_box_outline_blank';
1055
- break;
1056
- default:
1057
- this.toggle_icon = '';
1058
- break;
1059
- }
1060
- this.resetValids();
1061
- switch (this.type.toLowerCase().trim()) {
1062
- case 'edit':
1063
- this.editValid = true;
1064
- break;
1065
- case 'log':
1066
- this.historyValid = true;
1067
- break;
1068
- case 'line':
1069
- this.lineValid = true;
1070
- break;
1071
- case 'popupselect':
1072
- this.popupSelectValid = true;
1073
- break;
1074
- case 'toggle':
1075
- this.toggleValid = true;
1076
- break;
1077
- case 'none':
1078
- this.none = true;
1079
- break;
1080
- case 'add':
1081
- this.addValid = true;
1082
- break;
1083
- case 'delete':
1084
- this.deleteValid = true;
1085
- break;
1086
- default:
1087
- this.popupEditValid = true;
1088
- break;
1089
- }
1206
+ class SecurityDto {
1207
+ coid = null;
1208
+ userGUID = null;
1209
+ application = '';
1210
+ formCode = '';
1211
+ }
1212
+
1213
+ class SysfunctionProxy {
1214
+ http;
1215
+ environmentProxy;
1216
+ constructor(http, environmentProxy) {
1217
+ this.http = http;
1218
+ this.environmentProxy = environmentProxy;
1090
1219
  }
1091
- /** Refresh the display
1220
+ /** Get the authentication list for the given form
1092
1221
  *
1093
- * @param params
1222
+ * @param formCode
1094
1223
  * @returns
1095
1224
  */
1096
- refresh(params) {
1097
- return false;
1098
- }
1099
- resetValids() {
1100
- this.editValid = false;
1101
- this.historyValid = false;
1102
- this.lineValid = false;
1103
- this.popupSelectValid = false;
1104
- this.popupEditValid = false;
1105
- this.toggleValid = false;
1106
- }
1107
- onClick(event) {
1108
- if (this.params.onClick instanceof Function) {
1109
- // put anything into params u want pass into parents component
1110
- const params = {
1111
- event: event,
1112
- rowData: this.params.node.data,
1113
- type: this.type,
1114
- // ...something
1115
- };
1116
- this.params.onClick(params);
1117
- }
1225
+ getAuthentication(formCode) {
1226
+ let sysFunctionsURL = this.environmentProxy.getAdminLink('getAuthentication');
1227
+ let securityDto = new SecurityDto();
1228
+ securityDto.formCode = formCode;
1229
+ securityDto.application = this.environmentProxy.getApplicationName();
1230
+ let call$ = this.http.post(sysFunctionsURL, securityDto);
1231
+ return call$.pipe(map((result) => result), catchError$1((error) => {
1232
+ let errorMessage = error.message; //.error.title;
1233
+ return throwError(() => new Error(errorMessage ?? ''));
1234
+ }));
1118
1235
  }
1119
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1120
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ButtonRenderer, isStandalone: true, selector: "ntybase-button-renderer", host: { attributes: { "ntybase-id": "ButtonRenderer" } }, ngImport: i0, template: "@if (editValid || popupEditValid) {\n<mat-icon\n class=\"cursor center edit\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"4000\"\n >edit</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center-log\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >log</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >history</mat-icon\n>\n} @if (lineValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (popupSelectValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >content_copy</mat-icon\n>\n} @if (toggleValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >{{toggleValue ? 'check_box' : 'check_box_outline_blank'}}</mat-icon\n>\n} @if (none) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (addValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >playlist_add</mat-icon\n>\n} @if (deleteValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >delete_outline</mat-icon\n>\n}\n", styles: [".cursor{cursor:pointer}.center{display:flex;justify-content:center;align-items:center;width:100%}.center-log{display:flex;justify-content:center;align-items:center;margin-bottom:-12px}.edit{margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }] });
1236
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, deps: [{ token: i1$3.HttpClient }, { token: i2$1.EnvironmentProxy }], target: i0.ɵɵFactoryTarget.Injectable });
1237
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, providedIn: 'root' });
1121
1238
  }
1122
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, decorators: [{
1123
- type: Component,
1124
- args: [{ selector: 'ntybase-button-renderer', imports: [MatIconModule, MatTooltipModule, MatMenuModule], host: { 'ntybase-id': 'ButtonRenderer' }, template: "@if (editValid || popupEditValid) {\n<mat-icon\n class=\"cursor center edit\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"4000\"\n >edit</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center-log\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >log</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >history</mat-icon\n>\n} @if (lineValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (popupSelectValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >content_copy</mat-icon\n>\n} @if (toggleValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >{{toggleValue ? 'check_box' : 'check_box_outline_blank'}}</mat-icon\n>\n} @if (none) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (addValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >playlist_add</mat-icon\n>\n} @if (deleteValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >delete_outline</mat-icon\n>\n}\n", styles: [".cursor{cursor:pointer}.center{display:flex;justify-content:center;align-items:center;width:100%}.center-log{display:flex;justify-content:center;align-items:center;margin-bottom:-12px}.edit{margin-top:8px}\n"] }]
1125
- }] });
1239
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, decorators: [{
1240
+ type: Injectable,
1241
+ args: [{
1242
+ providedIn: 'root',
1243
+ }]
1244
+ }], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: i2$1.EnvironmentProxy }] });
1126
1245
 
1127
- class CheckboxRenderer {
1128
- params = null;
1129
- label = '';
1130
- type = '';
1131
- supportClick = false;
1132
- checked = null;
1133
- agInit(params) {
1134
- this.onProcess(params);
1135
- }
1136
- refresh(params) {
1137
- if (params != null) {
1138
- this.onProcess(params);
1246
+ class NettyAgGridBase extends NettyAppsBase {
1247
+ FILTER_MODE_KEY = 'nettyapps_filter_mode';
1248
+ // AgGrid Dark Mode Row Style
1249
+ myTheme = themeQuartz.withParams({
1250
+ backgroundColor: 'black',
1251
+ browserColorScheme: 'dark',
1252
+ }, 'dark');
1253
+ // ********************************************
1254
+ // *** INPUTS ***
1255
+ // ********************************************
1256
+ readOnly = signal(true, ...(ngDevMode ? [{ debugName: "readOnly" }] : [])); // Is the form in readonly mode
1257
+ popupFilterValid = input(false, ...(ngDevMode ? [{ debugName: "popupFilterValid" }] : [])); // Is the popup filter valid
1258
+ popupValid = input(false, ...(ngDevMode ? [{ debugName: "popupValid" }] : [])); // Is the form in popup mode
1259
+ isEmbedded = input(false, ...(ngDevMode ? [{ debugName: "isEmbedded" }] : [])); // Is the form embedded to an other component
1260
+ // Component identifiers
1261
+ componentName = signal('Invalid', ...(ngDevMode ? [{ debugName: "componentName" }] : []));
1262
+ searchValueName = signal('Invalid_searchValue', ...(ngDevMode ? [{ debugName: "searchValueName" }] : []));
1263
+ preferenceType = signal('Invalid_columnState', ...(ngDevMode ? [{ debugName: "preferenceType" }] : []));
1264
+ searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
1265
+ // Query Parameters can be provide as parameters
1266
+ parameterGUID = signal('', ...(ngDevMode ? [{ debugName: "parameterGUID" }] : []));
1267
+ parameterType = signal('', ...(ngDevMode ? [{ debugName: "parameterType" }] : []));
1268
+ // Services
1269
+ nettyAgGridService = inject(NettyAgGridService);
1270
+ commonService = inject(CommonService);
1271
+ sysFunctionProxy = inject(SysfunctionProxy);
1272
+ environment = inject(EnvironmentProxy);
1273
+ // Authentication
1274
+ authenticationList = [];
1275
+ // User access writes
1276
+ accessRightsProcessed = signal(false, ...(ngDevMode ? [{ debugName: "accessRightsProcessed" }] : []));
1277
+ allowAdd = signal(false, ...(ngDevMode ? [{ debugName: "allowAdd" }] : []));
1278
+ allowEdit = signal(false, ...(ngDevMode ? [{ debugName: "allowEdit" }] : []));
1279
+ allowDelete = signal(false, ...(ngDevMode ? [{ debugName: "allowDelete" }] : []));
1280
+ allowLog = signal(false, ...(ngDevMode ? [{ debugName: "allowLog" }] : []));
1281
+ allowRead = signal(true, ...(ngDevMode ? [{ debugName: "allowRead" }] : []));
1282
+ // ---------------------------------------------------
1283
+ // --- RECORD LIST ---
1284
+ // ---------------------------------------------------
1285
+ recordList = signal([], ...(ngDevMode ? [{ debugName: "recordList" }] : []));
1286
+ record = null;
1287
+ /**
1288
+ * Component initialization lifecycle hook Overide for custom initialization
1289
+ */
1290
+ async AfterOnInit() { }
1291
+ /** Set data into the grid */
1292
+ setData(data) {
1293
+ this.recordList.set(data);
1294
+ if (this.columnDefs() == null || this.columnDefs().length == 0) {
1295
+ this.initAgGrid();
1296
+ }
1297
+ if (this.searchValue() && this.gridApi) {
1298
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1299
+ if (this.recordList == undefined || this.recordList.length == 0) {
1300
+ if (this.isEmbedded()) {
1301
+ this.alertService.showWarning('@recordNotFoundSearch');
1302
+ }
1303
+ }
1139
1304
  }
1140
- return true;
1141
1305
  }
1142
- onProcess(params) {
1143
- this.params = params;
1144
- this.checked = this.params.value ?? false;
1145
- this.type = this.params.type || null;
1146
- this.label = this.params.label || null;
1147
- if (this.type != null) {
1148
- if (this.type.toLowerCase().trim() == 'click') {
1149
- this.supportClick = true;
1306
+ async setAccessRights() {
1307
+ this.authenticationList = await lastValueFrom(this.sysFunctionProxy.getAuthentication(this.componentName())).catch((e) => {
1308
+ return throwError(() => new Error(e));
1309
+ });
1310
+ try {
1311
+ this.allowRead.set(this.authenticationList.find((f) => f.action == 'read')?.allow ?? false);
1312
+ if (this.allowRead() == false) {
1313
+ this.commonService.userNotAllowedToRead();
1314
+ return false;
1150
1315
  }
1316
+ this.allowAdd.set(false);
1317
+ this.allowEdit.set(false);
1318
+ this.allowDelete.set(false);
1319
+ this.allowLog.set(false);
1151
1320
  }
1152
- }
1153
- onClick(event) {
1154
- this.checked = !this.checked;
1155
- if (this.params.onClick instanceof Function) {
1156
- // put anything into params u want pass into parents component
1157
- const params = {
1158
- event: event,
1159
- rowData: this.params.node.data,
1160
- type: this.type,
1161
- checked: this.checked,
1162
- // ...something
1163
- };
1164
- this.params.onClick(params);
1321
+ catch (error) {
1322
+ this.allowAdd.set(false);
1323
+ this.allowEdit.set(false);
1324
+ this.allowDelete.set(false);
1325
+ this.allowLog.set(false);
1326
+ return false;
1165
1327
  }
1328
+ this.accessRightsProcessed.set(true);
1329
+ return true;
1166
1330
  }
1167
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1168
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CheckboxRenderer, isStandalone: true, selector: "ntybase-checkbox-renderer", host: { attributes: { "ntybase-id": "CheckboxRenderer" } }, ngImport: i0, template: "@if (supportClick) {\n<input\n id=\"checkbox\"\n type=\"checkbox\"\n [checked]=\"checked\"\n (click)=\"onClick($event)\"\n/>\n} @if (!supportClick) {\n<input id=\"checkbox\" type=\"checkbox\" [checked]=\"params.value\" disabled />\n}\n\n<label for=\"checkbox\">{{label}}</label>\n", styles: [""] });
1169
- }
1170
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, decorators: [{
1171
- type: Component,
1172
- args: [{ selector: 'ntybase-checkbox-renderer', imports: [], host: { 'ntybase-id': 'CheckboxRenderer' }, template: "@if (supportClick) {\n<input\n id=\"checkbox\"\n type=\"checkbox\"\n [checked]=\"checked\"\n (click)=\"onClick($event)\"\n/>\n} @if (!supportClick) {\n<input id=\"checkbox\" type=\"checkbox\" [checked]=\"params.value\" disabled />\n}\n\n<label for=\"checkbox\">{{label}}</label>\n" }]
1173
- }] });
1174
-
1175
- class NettyAppsBase {
1176
- // ---------------------------------
1177
- // --- SERVICES ---
1178
- // ---------------------------------
1179
- alertService = inject(AlertService);
1180
- translateService = inject(TranslateService);
1181
- // ---------------------------------
1182
- // --- DOWNLOAD METHODS ---
1183
- // ---------------------------------
1184
1331
  /**
1185
- * Download the given base64Encoded data as file
1186
- *
1187
- * @param base64Data: base64 encoded data
1188
- * @param fileName: filename to download
1189
- */
1190
- downloadFile(base64Data, fileName) {
1191
- if (base64Data == null) {
1192
- return;
1193
- }
1194
- if (fileName == null) {
1195
- return;
1332
+ * Get stored filter mode from local storage
1333
+ * @returns boolean
1334
+ */
1335
+ getStoredFilterMode() {
1336
+ try {
1337
+ const stored = localStorage.getItem(this.FILTER_MODE_KEY);
1338
+ return stored !== null ? JSON.parse(stored) : true;
1196
1339
  }
1197
- // Check if header is present
1198
- if (!base64Data.startsWith('data:')) {
1199
- console.error('Provided data is not in base64 format (missing header)');
1200
- return;
1340
+ catch {
1341
+ return true;
1201
1342
  }
1202
- const contentType = base64Data.split(';')[0].split(':')[1];
1203
- const byteCharacters = atob(base64Data.split(',')[1]);
1204
- const byteArrays = [];
1205
- for (let i = 0; i < byteCharacters.length; i++) {
1206
- const byteArray = byteCharacters.charCodeAt(i);
1207
- byteArrays.push(byteArray);
1343
+ }
1344
+ // *********************************************************
1345
+ // *** AG Grid Management ***
1346
+ // *********************************************************
1347
+ // Component inputs
1348
+ agGridSelectionMode = input('multiRow', ...(ngDevMode ? [{ debugName: "agGridSelectionMode" }] : []));
1349
+ // AG-Grid theme setting (dark mode)
1350
+ theme = this.myTheme;
1351
+ // Grid references
1352
+ gridApi;
1353
+ userGridApi;
1354
+ excelStyles = null;
1355
+ // Column definitions
1356
+ columnDefs = signal(null, ...(ngDevMode ? [{ debugName: "columnDefs" }] : []));
1357
+ userColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "userColumnDefs" }] : []));
1358
+ groupMembersColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "groupMembersColumnDefs" }] : []));
1359
+ gridColumnsVisible = signal(true, ...(ngDevMode ? [{ debugName: "gridColumnsVisible" }] : []));
1360
+ gridExpanded = signal(false, ...(ngDevMode ? [{ debugName: "gridExpanded" }] : []));
1361
+ // Framework components
1362
+ frameworkComponents = null;
1363
+ // Selection management
1364
+ selectedRows = signal([], ...(ngDevMode ? [{ debugName: "selectedRows" }] : [])); // Selected rows in the grid
1365
+ isSingleRowSelected = computed(() => this.selectedRows().length === 1, ...(ngDevMode ? [{ debugName: "isSingleRowSelected" }] : [])); // True if only one row is selected
1366
+ isMultipleRowSelected = computed(() => this.selectedRows().length > 0, ...(ngDevMode ? [{ debugName: "isMultipleRowSelected" }] : [])); // True if multiple rows are selected
1367
+ // Services
1368
+ // AG Grid Filter
1369
+ customFilters = signal(this.getStoredFilterMode(), ...(ngDevMode ? [{ debugName: "customFilters" }] : []));
1370
+ // ---------------------------------------------
1371
+ // --- AG Grid Configuration ---
1372
+ // ---------------------------------------------
1373
+ // Grid configuration options
1374
+ gridOptions = {
1375
+ rowSelection: {
1376
+ mode: this.agGridSelectionMode(), checkboxes: true, headerCheckbox: true,
1377
+ selectAll: 'filtered', hideDisabledCheckboxes: true, suppressRowClickSelection: false,
1378
+ enableCellChangeFlash: true,
1379
+ },
1380
+ };
1381
+ // Statusbar
1382
+ statusBar = {
1383
+ statusPanels: [
1384
+ { statusPanel: 'agTotalRowCountComponent', align: 'left', key: 'rowCount' },
1385
+ { statusPanel: 'agFilteredRowCountComponent' },
1386
+ { statusPanel: 'agSelectedRowCountComponent' },
1387
+ { statusPanel: 'agAggregationComponent' },
1388
+ ],
1389
+ };
1390
+ // ---------------------------------------------
1391
+ // --- AG Grid Functions ---
1392
+ // ---------------------------------------------
1393
+ // Common grid ready handler
1394
+ onGridReady(params) {
1395
+ this.gridApi = params.api;
1396
+ this.setAgGridTranslations();
1397
+ this.gridApi.addEventListener('selectionChanged', () => {
1398
+ // Null-safe approach
1399
+ const selectedNodes = this.gridApi?.getSelectedNodes?.() || [];
1400
+ this.selectedRows.set(selectedNodes.map((node) => node.data));
1401
+ });
1402
+ if (this.searchValue()) {
1403
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1208
1404
  }
1209
- const byteArray = new Uint8Array(byteArrays);
1210
- const blob = new Blob([byteArray], { type: contentType });
1211
- const link = document.createElement('a');
1212
- link.href = URL.createObjectURL(blob);
1213
- link.download = fileName;
1214
- link.click();
1215
1405
  }
1216
- /** Download the given base64Endoced data as text file
1217
- *
1218
- * @param base64EncodedFileData
1219
- * @param fileName
1220
- */
1221
- downloadTextFile(base64EncodedFileData, fileName) {
1222
- // Check if the data has a prefix like "data:application/pdf;base64,"
1223
- if (base64EncodedFileData == null) {
1224
- return;
1406
+ onFirstDataRendered(params) {
1407
+ //TODO: Fix this
1408
+ try {
1409
+ this.nettyAgGridService.loadGridUserPreference(this.preferenceType(), this.gridApi);
1410
+ this.expandCollapse();
1225
1411
  }
1226
- if (fileName == null) {
1227
- return;
1412
+ catch (error) {
1413
+ console.log('OnFirstDataRendered error:', error);
1228
1414
  }
1229
- let _data = base64EncodedFileData;
1230
- const prefix = 'data:';
1231
- if (_data.startsWith(prefix)) {
1232
- // Remove the prefix
1233
- _data = _data.slice(_data.indexOf(',') + 1);
1415
+ }
1416
+ // Save the user parameters
1417
+ saveGrid(params) {
1418
+ const gridState = {
1419
+ columnState: this.gridApi.getColumnState(),
1420
+ };
1421
+ this.nettyAgGridService.saveGridUserPreference(this.preferenceType(), this.gridApi, JSON.stringify(gridState));
1422
+ }
1423
+ // Grid utilities
1424
+ expandCollapse() {
1425
+ this.gridExpanded.set(this.nettyAgGridService.expandCollapseGrid(this.gridApi, this.gridExpanded()));
1426
+ }
1427
+ quickSearch(searchStr = '') {
1428
+ this.searchValue.set(searchStr);
1429
+ if (this.gridApi) {
1430
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1234
1431
  }
1235
- // Convert the base64 data to a Uint8Array
1236
- const textData = Buffer.from(_data ?? '', 'base64').toString();
1237
- this.downloadTextFileNotEncoded(textData, fileName);
1432
+ sessionStorage.setItem(this.searchValueName(), this.searchValue());
1238
1433
  }
1239
- /** Save the given text as a text file
1240
- *
1241
- * @param fileData
1242
- * @param fileName
1434
+ /**
1435
+ * Update a single row in the grid
1436
+ * @param rowData The updated row data
1437
+ * @param idField The field name that serves as unique identifier (default: 'id')
1243
1438
  */
1244
- downloadTextFileNotEncoded(fileData, fileName) {
1245
- if (fileData == null) {
1246
- return;
1439
+ updateRowInGrid(rowData, idField = 'id') {
1440
+ const rowNode = this.gridApi.getRowNode(rowData[idField]);
1441
+ if (rowNode) {
1442
+ rowNode.setData(rowData);
1443
+ const params = { rowNodes: [rowNode], force: true, suppressFlash: false, };
1444
+ this.gridApi.refreshCells(params);
1247
1445
  }
1248
- if (fileName == null) {
1249
- return;
1446
+ else {
1447
+ this.loadData(); // Reload all data if row not found
1250
1448
  }
1251
- // Create a Blob from the Text
1252
- const blob = new Blob([fileData], { type: 'text/plain' });
1253
- // Create a download link
1254
- const url = window.URL.createObjectURL(blob);
1255
- const a = document.createElement('a');
1256
- document.body.appendChild(a);
1257
- a.style.display = 'none';
1258
- a.href = url;
1259
- a.download = fileName ?? 'filename';
1260
- // Trigger the download
1261
- a.click();
1262
- // Clean up
1263
- window.URL.revokeObjectURL(url);
1264
- document.body.removeChild(a);
1265
1449
  }
1266
1450
  /**
1267
- * Download file where the data is provided as blob
1268
- * @param data - Array Buffer data
1269
- * @param type - type of the document.
1451
+ * Filter mode change
1270
1452
  */
1271
- downloadBlobFile(data, type, fileName) {
1272
- let blob = new Blob([data], { type: type });
1273
- let downloadLink = document.createElement('a');
1274
- downloadLink.href = window.URL.createObjectURL(blob);
1275
- downloadLink.setAttribute('download', fileName);
1276
- document.body.appendChild(downloadLink);
1277
- downloadLink.click();
1278
- downloadLink.parentNode?.removeChild(downloadLink);
1453
+ toggleFilterMode() {
1454
+ const newMode = !this.customFilters();
1455
+ this.customFilters.set(newMode);
1456
+ localStorage.setItem(this.FILTER_MODE_KEY, JSON.stringify(newMode));
1457
+ this.initAgGrid();
1458
+ if (this.gridApi) {
1459
+ this.gridApi.refreshHeader();
1460
+ this.gridApi.setFilterModel(null);
1461
+ const message = this.customFilters()
1462
+ ? '@customFilterModeEnabled'
1463
+ : '@defaultFilterModeEnabled';
1464
+ this.alertService.showAlert(this.translateService.instant(message));
1465
+ }
1279
1466
  }
1280
- // ---------------------------------
1281
- // --- INTERFACE IMPLEMENTATIONS ---
1282
- // ---------------------------------
1283
- onDestroy$ = new Subject();
1284
- ngOnDestroy() {
1285
- //Called once, before the instance is destroyed.
1286
- //Add 'implements OnDestroy' to the class.
1287
- this.onDestroy$.next();
1288
- this.onDestroy$.complete();
1467
+ setAgGridTranslations() {
1468
+ this.nettyAgGridService.setAgGridTranslations(this.gridApi);
1289
1469
  }
1290
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
1291
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: NettyAppsBase, isStandalone: true, selector: "ntybase-netty-apps-base", ngImport: i0, template: "", styles: [""] });
1292
- }
1293
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, decorators: [{
1294
- type: Component,
1295
- args: [{ selector: 'ntybase-netty-apps-base', imports: [], template: "" }]
1296
- }] });
1297
-
1298
- ModuleRegistry.registerModules([
1299
- AllCommunityModule,
1300
- StatusBarModule,
1301
- ClientSideRowModelModule,
1302
- ClipboardModule,
1303
- ExcelExportModule,
1304
- ColumnMenuModule,
1305
- ContextMenuModule,
1306
- CellSelectionModule,
1307
- HighlightChangesModule,
1308
- RowSelectionModule,
1309
- ]);
1310
- // AgGrid Dark Mode Row Style
1311
- const myTheme = themeQuartz.withParams({
1312
- backgroundColor: 'black',
1313
- browserColorScheme: 'dark',
1314
- }, 'dark');
1315
- const FILTER_MODE_KEY = 'nettyapps_filter_mode';
1316
- class NettyAgGridBase extends NettyAppsBase {
1317
- // Input signals
1318
- readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : []));
1319
- popupFilterValid = input(false, ...(ngDevMode ? [{ debugName: "popupFilterValid" }] : []));
1320
- popupValid = input(false, ...(ngDevMode ? [{ debugName: "popupValid" }] : []));
1321
- isEmbedded = input(false, ...(ngDevMode ? [{ debugName: "isEmbedded" }] : []));
1322
- // Parameters pass when the component is embeded into an other
1323
- componantParameterGUID = input('', ...(ngDevMode ? [{ debugName: "componantParameterGUID" }] : []));
1324
- componantParameterType = input('', ...(ngDevMode ? [{ debugName: "componantParameterType" }] : []));
1325
- // Events
1326
- /*
1327
- Selected records event
1328
- @param records: Array of selected records
1329
- */
1330
- onElementSelect = output();
1331
- // AG Grid Filter
1332
- customFilters = signal(this.getStoredFilterMode(), ...(ngDevMode ? [{ debugName: "customFilters" }] : []));
1333
- // Filter section
1334
- isFilterValid = signal(true, ...(ngDevMode ? [{ debugName: "isFilterValid" }] : []));
1335
- isFilterExpanded = signal(true, ...(ngDevMode ? [{ debugName: "isFilterExpanded" }] : []));
1336
- // Authentication
1337
- authenticationList = [];
1338
- // User access writes
1339
- accessRightsProcessed = signal(false, ...(ngDevMode ? [{ debugName: "accessRightsProcessed" }] : []));
1340
- allowAdd = signal(false, ...(ngDevMode ? [{ debugName: "allowAdd" }] : []));
1341
- allowEdit = signal(false, ...(ngDevMode ? [{ debugName: "allowEdit" }] : []));
1342
- allowDelete = signal(false, ...(ngDevMode ? [{ debugName: "allowDelete" }] : []));
1343
- allowLog = signal(false, ...(ngDevMode ? [{ debugName: "allowLog" }] : []));
1344
- allowRead = signal(true, ...(ngDevMode ? [{ debugName: "allowRead" }] : []));
1345
- // Button action management variables
1346
- menuValid = signal(true, ...(ngDevMode ? [{ debugName: "menuValid" }] : []));
1347
- deleteValid = signal(false, ...(ngDevMode ? [{ debugName: "deleteValid" }] : []));
1348
- selectionValid = signal(false, ...(ngDevMode ? [{ debugName: "selectionValid" }] : []));
1349
- refreshButtonValid = signal(false, ...(ngDevMode ? [{ debugName: "refreshButtonValid" }] : []));
1350
- // Parameters for embeded components
1351
- selectedElement = output();
1352
- // AG-Grid theme setting (dark mode)
1353
- theme = myTheme;
1354
- // Grid references
1355
- gridApi;
1356
- userGridApi;
1357
- excelStyles = null;
1358
- // Column definitions
1359
- columnDefs = signal(null, ...(ngDevMode ? [{ debugName: "columnDefs" }] : []));
1360
- userColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "userColumnDefs" }] : []));
1361
- groupMembersColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "groupMembersColumnDefs" }] : []));
1362
- gridColumnsVisible = signal(true, ...(ngDevMode ? [{ debugName: "gridColumnsVisible" }] : []));
1363
- // Framework components
1364
- frameworkComponents = null;
1365
- // Selection management
1366
- selectedRows = signal([], ...(ngDevMode ? [{ debugName: "selectedRows" }] : []));
1367
- isSingleRowSelected = computed(() => this.selectedRows().length === 1, ...(ngDevMode ? [{ debugName: "isSingleRowSelected" }] : []));
1368
- isMultipleRowSelected = computed(() => this.selectedRows().length > 0, ...(ngDevMode ? [{ debugName: "isMultipleRowSelected" }] : []));
1369
- // Component identifiers
1370
- gridExpanded = signal(false, ...(ngDevMode ? [{ debugName: "gridExpanded" }] : []));
1371
- componentName = signal('Invalid', ...(ngDevMode ? [{ debugName: "componentName" }] : []));
1372
- searchValueName = signal('Invalid_searchValue', ...(ngDevMode ? [{ debugName: "searchValueName" }] : []));
1373
- preferenceType = signal('Invalid_columnState', ...(ngDevMode ? [{ debugName: "preferenceType" }] : []));
1374
- searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
1375
- // Open component management
1376
- openInPopup = signal(false, ...(ngDevMode ? [{ debugName: "openInPopup" }] : []));
1377
- // Services
1378
- nettyAgGridService = inject(NettyAgGridService);
1379
- commonService = inject(CommonService);
1380
- router = inject(Router);
1381
- routerActive = inject(ActivatedRoute);
1382
- dialog = inject(MatDialog);
1383
- sysFunctionProxy = inject(SysfunctionProxy);
1384
- environment = inject(EnvironmentProxy);
1385
- // Parse query parameters
1386
- queryParameterGUID = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('parameters')), map((value) => this.parseOrReturnValue(value))), {
1387
- initialValue: null, // set initial value to null
1388
- });
1389
- queryParameterType = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('type')), map((value) => this.parseOrReturnValue(value))), {
1390
- initialValue: null, // set initial value to null
1391
- });
1392
- // Query Parameters can be provide as parameters
1393
- parameterGUID = signal('', ...(ngDevMode ? [{ debugName: "parameterGUID" }] : []));
1394
- parameterType = signal('', ...(ngDevMode ? [{ debugName: "parameterType" }] : []));
1395
1470
  initAgGrid_extension() {
1396
1471
  if (this.allowEdit() == false && (this.popupValid() ?? false) == false) {
1397
1472
  this.columnDefs().pop();
1398
1473
  this.columnDefs().shift();
1399
1474
  this.columnDefs().unshift({
1400
- headerName: '',
1401
- headerCheckboxSelection: true,
1402
- sortable: true,
1403
- resizable: true,
1404
- filter: true,
1405
- minWidth: 60,
1406
- maxWidth: 60,
1407
- suppressSizeToFit: true,
1408
- colId: 'editColumn',
1475
+ headerName: '', headerCheckboxSelection: true, sortable: true, resizable: true,
1476
+ filter: true, minWidth: 60, maxWidth: 60, suppressSizeToFit: true, colId: 'editColumn',
1409
1477
  cellRenderer: 'buttonRenderer',
1410
- cellRendererParams: {
1411
- //onClick: this.onBtnClick.bind(this),
1412
- label: '1',
1413
- type: 'edit',
1414
- },
1415
- });
1416
- this.gridApi.setGridOption('rowSelection', {
1417
- mode: 'multiRow',
1418
- checkboxes: true,
1478
+ cellRendererParams: { label: '1', type: 'edit' },
1419
1479
  });
1480
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true });
1420
1481
  }
1421
1482
  if (this.popupValid() == true) {
1422
1483
  this.columnDefs().pop();
@@ -1424,155 +1485,304 @@ class NettyAgGridBase extends NettyAppsBase {
1424
1485
  if (this.popupFilterValid() == true) {
1425
1486
  if (this.allowEdit()) {
1426
1487
  this.columnDefs().unshift({
1427
- headerName: '',
1428
- sortable: false,
1429
- resizable: false,
1430
- filter: false,
1431
- minWidth: 50,
1432
- maxWidth: 50,
1433
- suppressSizeToFit: true,
1434
- cellRenderer: 'buttonRenderer',
1488
+ headerName: '', sortable: false, resizable: false, filter: false,
1489
+ minWidth: 50, maxWidth: 50, suppressSizeToFit: true, cellRenderer: 'buttonRenderer',
1435
1490
  cellRendererParams: {
1436
1491
  onClick: this.onBtnClick?.bind(this),
1437
1492
  label: this.translateService.instant('@Update'),
1438
1493
  type: 'popupEdit',
1439
1494
  },
1440
1495
  });
1441
- this.gridApi.setGridOption('rowSelection', {
1442
- mode: 'multiRow',
1443
- checkboxes: true,
1444
- });
1496
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true, });
1445
1497
  }
1446
1498
  else {
1447
1499
  this.columnDefs().unshift({
1448
- headerName: '',
1449
- sortable: false,
1450
- resizable: false,
1451
- filter: false,
1452
- minWidth: 50,
1453
- maxWidth: 50,
1454
- suppressSizeToFit: true,
1455
- cellStyle: { 'padding-top': '5px' },
1456
- });
1457
- this.gridApi.setGridOption('rowSelection', {
1458
- mode: 'multiRow',
1459
- checkboxes: true,
1500
+ headerName: '', sortable: false, resizable: false, filter: false,
1501
+ minWidth: 50, maxWidth: 50, suppressSizeToFit: true, cellStyle: { 'padding-top': '5px' }
1460
1502
  });
1503
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true });
1461
1504
  }
1462
1505
  }
1463
1506
  else {
1464
1507
  if (this.allowEdit() == false) {
1465
1508
  this.columnDefs().unshift({
1466
- headerName: '',
1467
- sortable: false,
1468
- resizable: false,
1469
- filter: false,
1470
- minWidth: 50,
1471
- maxWidth: 50,
1472
- suppressSizeToFit: true,
1473
- cellRenderer: 'buttonRenderer',
1509
+ headerName: '', sortable: false, resizable: false, filter: false, minWidth: 50,
1510
+ maxWidth: 50, suppressSizeToFit: true, cellRenderer: 'buttonRenderer',
1474
1511
  cellRendererParams: {
1475
1512
  onClick: this.onBtnClick?.bind(this),
1476
1513
  label: this.translateService.instant('@Update'),
1477
1514
  type: 'popupEdit',
1478
1515
  },
1479
1516
  });
1480
- this.gridApi.setGridOption('rowSelection', {
1481
- mode: 'singleRow',
1482
- checkboxes: false,
1483
- });
1517
+ this.gridApi.setGridOption('rowSelection', { mode: 'singleRow', checkboxes: false });
1484
1518
  }
1485
1519
  if (!this.readOnly()) {
1486
1520
  this.columnDefs().unshift({
1487
- headerName: this.translateService.instant('@select'),
1488
- sortable: false,
1489
- resizable: false,
1490
- filter: false,
1491
- minWidth: 80,
1492
- maxWidth: 80,
1493
- suppressSizeToFit: true,
1494
- cellRenderer: 'buttonRenderer',
1495
- cellStyle: { 'margin-top': '8px' },
1521
+ headerName: this.translateService.instant('@select'), sortable: false, resizable: false,
1522
+ filter: false, minWidth: 80, maxWidth: 80, suppressSizeToFit: true,
1523
+ cellRenderer: 'buttonRenderer', cellStyle: { 'margin-top': '8px' },
1496
1524
  cellRendererParams: {
1497
1525
  onClick: this.onBtnClick?.bind(this),
1498
1526
  label: this.translateService.instant('@select'),
1499
1527
  type: 'popupSelect',
1500
1528
  },
1501
1529
  });
1502
- this.gridApi.setGridOption('rowSelection', {
1503
- mode: 'singleRow',
1504
- checkboxes: false,
1505
- });
1530
+ this.gridApi.setGridOption('rowSelection', { mode: 'singleRow', checkboxes: false });
1506
1531
  }
1507
1532
  }
1508
1533
  }
1509
1534
  }
1510
- // Grid configuration options
1511
- gridOptions = {
1512
- rowSelection: {
1513
- mode: 'multiRow',
1514
- checkboxes: true,
1515
- headerCheckbox: true,
1516
- selectAll: 'filtered',
1517
- hideDisabledCheckboxes: true,
1518
- suppressRowClickSelection: false,
1519
- enableCellChangeFlash: true,
1520
- },
1521
- };
1522
- // Statusbar
1523
- statusBar = {
1524
- statusPanels: [
1525
- {
1526
- statusPanel: 'agTotalRowCountComponent',
1527
- align: 'left',
1528
- key: 'rowCount',
1529
- },
1530
- { statusPanel: 'agFilteredRowCountComponent' },
1531
- { statusPanel: 'agSelectedRowCountComponent' },
1532
- { statusPanel: 'agAggregationComponent' },
1533
- ],
1534
- };
1535
- /**
1536
- * Filter mode change
1535
+ // ---------------------------------------------
1536
+ // --- Functions to Show / Hide Grid Columns ---
1537
+ // ---------------------------------------------
1538
+ onShowHideColumns() {
1539
+ this.gridColumnsVisible.update((a) => !a);
1540
+ this.showHideColumnsAsync();
1541
+ }
1542
+ showHideColumnsAsync() {
1543
+ setTimeout(() => this.showHideColumns(), 400);
1544
+ }
1545
+ showHideColumns() {
1546
+ var fields = this.columnDefs()
1547
+ .filter((columnDef) => columnDef.ntyHide === 'x')
1548
+ .map((columnDef) => columnDef.field);
1549
+ this.gridApi?.setColumnsVisible(fields, this.gridColumnsVisible());
1550
+ }
1551
+ showHideEmbeddedColumnsAsync() {
1552
+ setTimeout(() => this.showHideEmbeddedColumns(), 100);
1553
+ }
1554
+ showHideEmbeddedColumns() {
1555
+ if (this.columnDefs() == undefined || this.columnDefs() == null) {
1556
+ return;
1557
+ }
1558
+ var fields = this.columnDefs()
1559
+ .filter((columnDef) => columnDef.ntyEmbeddedHide == 'x')
1560
+ .map((columnDef) => columnDef.field);
1561
+ this.gridApi?.setColumnsVisible(fields, !this.isEmbedded());
1562
+ }
1563
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
1564
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridBase, isStandalone: true, selector: "ntybase-ag-grid-base", inputs: { popupFilterValid: { classPropertyName: "popupFilterValid", publicName: "popupFilterValid", isSignal: true, isRequired: false, transformFunction: null }, popupValid: { classPropertyName: "popupValid", publicName: "popupValid", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null }, agGridSelectionMode: { classPropertyName: "agGridSelectionMode", publicName: "agGridSelectionMode", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ntybase-id": "NettyAgGridBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
1565
+ }
1566
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, decorators: [{
1567
+ type: Component,
1568
+ args: [{ selector: 'ntybase-ag-grid-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridBase' } }]
1569
+ }], propDecorators: { popupFilterValid: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupFilterValid", required: false }] }], popupValid: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupValid", required: false }] }], isEmbedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEmbedded", required: false }] }], agGridSelectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "agGridSelectionMode", required: false }] }] } });
1570
+
1571
+ class ButtonRenderer {
1572
+ params = null;
1573
+ label = '';
1574
+ type = '';
1575
+ toggleValue = null;
1576
+ editValid = false;
1577
+ historyValid = false;
1578
+ lineValid = false;
1579
+ popupSelectValid = false;
1580
+ popupEditValid = false;
1581
+ toggleValid = false;
1582
+ toggle_icon = '';
1583
+ none = false;
1584
+ addValid = false;
1585
+ deleteValid = false;
1586
+ agInit(params) {
1587
+ this.params = params;
1588
+ this.type = this.params.type || null;
1589
+ this.label = this.params.label || null;
1590
+ this.toggleValue = this.params.value || null;
1591
+ switch (this.toggleValue) {
1592
+ case true:
1593
+ this.toggle_icon = 'select_check_box';
1594
+ break;
1595
+ case false:
1596
+ this.toggle_icon = 'check_box_outline_blank';
1597
+ break;
1598
+ default:
1599
+ this.toggle_icon = '';
1600
+ break;
1601
+ }
1602
+ this.resetValids();
1603
+ switch (this.type.toLowerCase().trim()) {
1604
+ case 'edit':
1605
+ this.editValid = true;
1606
+ break;
1607
+ case 'log':
1608
+ this.historyValid = true;
1609
+ break;
1610
+ case 'line':
1611
+ this.lineValid = true;
1612
+ break;
1613
+ case 'popupselect':
1614
+ this.popupSelectValid = true;
1615
+ break;
1616
+ case 'toggle':
1617
+ this.toggleValid = true;
1618
+ break;
1619
+ case 'none':
1620
+ this.none = true;
1621
+ break;
1622
+ case 'add':
1623
+ this.addValid = true;
1624
+ break;
1625
+ case 'delete':
1626
+ this.deleteValid = true;
1627
+ break;
1628
+ default:
1629
+ this.popupEditValid = true;
1630
+ break;
1631
+ }
1632
+ }
1633
+ /** Refresh the display
1634
+ *
1635
+ * @param params
1636
+ * @returns
1537
1637
  */
1538
- toggleFilterMode() {
1539
- const newMode = !this.customFilters();
1540
- this.customFilters.set(newMode);
1541
- localStorage.setItem(FILTER_MODE_KEY, JSON.stringify(newMode));
1542
- this.initAgGrid();
1543
- if (this.gridApi) {
1544
- this.gridApi.refreshHeader();
1545
- this.gridApi.setFilterModel(null);
1546
- const message = this.customFilters()
1547
- ? '@customFilterModeEnabled'
1548
- : '@defaultFilterModeEnabled';
1549
- this.alertService.showAlert(this.translateService.instant(message));
1638
+ refresh(params) {
1639
+ return false;
1640
+ }
1641
+ resetValids() {
1642
+ this.editValid = false;
1643
+ this.historyValid = false;
1644
+ this.lineValid = false;
1645
+ this.popupSelectValid = false;
1646
+ this.popupEditValid = false;
1647
+ this.toggleValid = false;
1648
+ }
1649
+ onClick(event) {
1650
+ if (this.params.onClick instanceof Function) {
1651
+ // put anything into params u want pass into parents component
1652
+ const params = {
1653
+ event: event,
1654
+ rowData: this.params.node.data,
1655
+ type: this.type,
1656
+ // ...something
1657
+ };
1658
+ this.params.onClick(params);
1659
+ }
1660
+ }
1661
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1662
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ButtonRenderer, isStandalone: true, selector: "ntybase-button-renderer", host: { attributes: { "ntybase-id": "ButtonRenderer" } }, ngImport: i0, template: "@if (editValid || popupEditValid) {\n<mat-icon\n class=\"cursor center edit\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"4000\"\n >edit</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center-log\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >log</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >history</mat-icon\n>\n} @if (lineValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (popupSelectValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >content_copy</mat-icon\n>\n} @if (toggleValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >{{toggleValue ? 'check_box' : 'check_box_outline_blank'}}</mat-icon\n>\n} @if (none) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (addValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >playlist_add</mat-icon\n>\n} @if (deleteValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >delete_outline</mat-icon\n>\n}\n", styles: [".cursor{cursor:pointer}.center{display:flex;justify-content:center;align-items:center;width:100%}.center-log{display:flex;justify-content:center;align-items:center;margin-bottom:-12px}.edit{margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2$2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatMenuModule }] });
1663
+ }
1664
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, decorators: [{
1665
+ type: Component,
1666
+ args: [{ selector: 'ntybase-button-renderer', imports: [MatIconModule, MatTooltipModule, MatMenuModule], host: { 'ntybase-id': 'ButtonRenderer' }, template: "@if (editValid || popupEditValid) {\n<mat-icon\n class=\"cursor center edit\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"4000\"\n >edit</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center-log\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >log</mat-icon\n>\n} @if (historyValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >history</mat-icon\n>\n} @if (lineValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (popupSelectValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >content_copy</mat-icon\n>\n} @if (toggleValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >{{toggleValue ? 'check_box' : 'check_box_outline_blank'}}</mat-icon\n>\n} @if (none) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n [matTooltipShowDelay]=\"3000\"\n >menu_open</mat-icon\n>\n} @if (addValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >playlist_add</mat-icon\n>\n} @if (deleteValid) {\n<mat-icon\n class=\"cursor center\"\n matTooltip=\"{{label}}\"\n (click)=\"onClick($event)\"\n [matTooltipShowDelay]=\"3000\"\n >delete_outline</mat-icon\n>\n}\n", styles: [".cursor{cursor:pointer}.center{display:flex;justify-content:center;align-items:center;width:100%}.center-log{display:flex;justify-content:center;align-items:center;margin-bottom:-12px}.edit{margin-top:8px}\n"] }]
1667
+ }] });
1668
+
1669
+ class CheckboxRenderer {
1670
+ params = null;
1671
+ label = '';
1672
+ type = '';
1673
+ supportClick = false;
1674
+ checked = null;
1675
+ agInit(params) {
1676
+ this.onProcess(params);
1677
+ }
1678
+ refresh(params) {
1679
+ if (params != null) {
1680
+ this.onProcess(params);
1550
1681
  }
1682
+ return true;
1551
1683
  }
1552
- getStoredFilterMode() {
1553
- try {
1554
- const stored = localStorage.getItem(FILTER_MODE_KEY);
1555
- return stored !== null ? JSON.parse(stored) : true;
1684
+ onProcess(params) {
1685
+ this.params = params;
1686
+ this.checked = this.params.value ?? false;
1687
+ this.type = this.params.type || null;
1688
+ this.label = this.params.label || null;
1689
+ if (this.type != null) {
1690
+ if (this.type.toLowerCase().trim() == 'click') {
1691
+ this.supportClick = true;
1692
+ }
1556
1693
  }
1557
- catch {
1558
- return true;
1694
+ }
1695
+ onClick(event) {
1696
+ this.checked = !this.checked;
1697
+ if (this.params.onClick instanceof Function) {
1698
+ // put anything into params u want pass into parents component
1699
+ const params = {
1700
+ event: event,
1701
+ rowData: this.params.node.data,
1702
+ type: this.type,
1703
+ checked: this.checked,
1704
+ // ...something
1705
+ };
1706
+ this.params.onClick(params);
1559
1707
  }
1560
1708
  }
1709
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1710
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: CheckboxRenderer, isStandalone: true, selector: "ntybase-checkbox-renderer", host: { attributes: { "ntybase-id": "CheckboxRenderer" } }, ngImport: i0, template: "@if (supportClick) {\n<input\n id=\"checkbox\"\n type=\"checkbox\"\n [checked]=\"checked\"\n (click)=\"onClick($event)\"\n/>\n} @if (!supportClick) {\n<input id=\"checkbox\" type=\"checkbox\" [checked]=\"params.value\" disabled />\n}\n\n<label for=\"checkbox\">{{label}}</label>\n", styles: [""] });
1711
+ }
1712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, decorators: [{
1713
+ type: Component,
1714
+ args: [{ selector: 'ntybase-checkbox-renderer', imports: [], host: { 'ntybase-id': 'CheckboxRenderer' }, template: "@if (supportClick) {\n<input\n id=\"checkbox\"\n type=\"checkbox\"\n [checked]=\"checked\"\n (click)=\"onClick($event)\"\n/>\n} @if (!supportClick) {\n<input id=\"checkbox\" type=\"checkbox\" [checked]=\"params.value\" disabled />\n}\n\n<label for=\"checkbox\">{{label}}</label>\n" }]
1715
+ }] });
1716
+
1717
+ ModuleRegistry.registerModules([AllCommunityModule, StatusBarModule, ClientSideRowModelModule, ClipboardModule, ExcelExportModule, ColumnMenuModule,
1718
+ ContextMenuModule, CellSelectionModule, HighlightChangesModule, RowSelectionModule,]);
1719
+ // AgGrid Dark Mode Row Style
1720
+ class NettyAgGridListBase extends NettyAgGridBase {
1721
+ // ********************************************
1722
+ // *** INPUTS ***
1723
+ // ********************************************
1724
+ // Parameters passed when the component is embeded into an other
1725
+ componantParameterGUID = input('', ...(ngDevMode ? [{ debugName: "componantParameterGUID" }] : [])); // GUID of the parameter
1726
+ componantParameterType = input('', ...(ngDevMode ? [{ debugName: "componantParameterType" }] : [])); // Type of the parameter (Field Name)
1727
+ // ********************************************
1728
+ // *** EVENTS ***
1729
+ // ********************************************
1730
+ /*
1731
+ Selected records event
1732
+ @param records: Array of selected records
1733
+ */
1734
+ onElementSelect = output(); // Emit selected records when updated
1735
+ // Parameters for embeded components
1736
+ selectedElement = output(); // Selected element in popup mode
1737
+ // ********************************************
1738
+ // Filter section
1739
+ hasFilter = input(false, ...(ngDevMode ? [{ debugName: "hasFilter" }] : [])); // Does the component have a filter
1740
+ isFilterValid = signal(true, ...(ngDevMode ? [{ debugName: "isFilterValid" }] : [])); // Can the filter be used
1741
+ isFilterExpanded = computed(() => {
1742
+ if (this.isEmbedded()) {
1743
+ return false;
1744
+ }
1745
+ if (!this.hasFilter()) {
1746
+ return false;
1747
+ }
1748
+ return this.isFilterValid();
1749
+ }, ...(ngDevMode ? [{ debugName: "isFilterExpanded" }] : []));
1750
+ // Button action management variables
1751
+ menuValid = signal(true, ...(ngDevMode ? [{ debugName: "menuValid" }] : [])); // true: Filter editbox is not visible so the menus are visible
1752
+ refreshButtonValid = signal(false, ...(ngDevMode ? [{ debugName: "refreshButtonValid" }] : [])); // true: Refresh button is enabled
1753
+ // Open component management
1754
+ openEditComponentInPopup = signal(false, ...(ngDevMode ? [{ debugName: "openEditComponentInPopup" }] : []));
1755
+ // Services
1756
+ router = inject(Router);
1757
+ routerActive = inject(ActivatedRoute);
1758
+ dialog = inject(MatDialog);
1759
+ // Parse query parameters
1760
+ queryParameterGUID = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('parameters')), map((value) => this.parseOrReturnValue(value))), {
1761
+ initialValue: null, // set initial value to null
1762
+ });
1763
+ queryParameterType = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('type')), map((value) => this.parseOrReturnValue(value))), {
1764
+ initialValue: null, // set initial value to null
1765
+ });
1766
+ // ---------------------------------------------------
1767
+ // --- RECORD LIST ---
1768
+ // ---------------------------------------------------
1769
+ nettyAppsProxy = injectNettyStandardProxy(this.componentName());
1561
1770
  /**
1562
1771
  * Component initialization lifecycle hook
1563
1772
  */
1564
1773
  async ngOnInit() {
1774
+ this.nettyAppsProxy = injectNettyStandardProxy(this.componentName());
1565
1775
  await this.setAccessRights();
1566
1776
  const savedSearchValue = sessionStorage.getItem(this.searchValueName());
1567
1777
  if (savedSearchValue) {
1568
1778
  this.searchValue.set(savedSearchValue);
1569
- this.loadData(savedSearchValue);
1570
1779
  }
1571
- else {
1780
+ if (!this.hasFilter()) {
1572
1781
  this.loadData();
1573
1782
  }
1574
1783
  // Load user grid preferences
1575
1784
  await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
1785
+ await this.AfterOnInit();
1576
1786
  }
1577
1787
  parseOrReturnValue(value) {
1578
1788
  if (value) {
@@ -1585,47 +1795,6 @@ class NettyAgGridBase extends NettyAppsBase {
1585
1795
  }
1586
1796
  return null;
1587
1797
  }
1588
- // Common grid ready handler
1589
- onGridReady(params) {
1590
- this.gridApi = params.api;
1591
- this.setAgGridTranslations();
1592
- this.gridApi.addEventListener('selectionChanged', () => {
1593
- // Null-safe approach
1594
- const selectedNodes = this.gridApi?.getSelectedNodes?.() || [];
1595
- this.selectedRows.set(selectedNodes.map((node) => node.data));
1596
- });
1597
- if (this.searchValue()) {
1598
- this.gridApi.setGridOption('quickFilterText', this.searchValue());
1599
- }
1600
- }
1601
- onFirstDataRendered(params) {
1602
- //TODO: Fix this
1603
- try {
1604
- this.nettyAgGridService.loadGridUserPreference(this.preferenceType(), this.gridApi);
1605
- this.expandCollapse();
1606
- }
1607
- catch (error) {
1608
- console.log('OnFirstDataRendered error:', error);
1609
- }
1610
- }
1611
- // Save the user parameters
1612
- saveGrid(params) {
1613
- const gridState = {
1614
- columnState: this.gridApi.getColumnState(),
1615
- };
1616
- this.nettyAgGridService.saveGridUserPreference(this.preferenceType(), this.gridApi, JSON.stringify(gridState));
1617
- }
1618
- // Grid utilities
1619
- expandCollapse() {
1620
- this.gridExpanded.set(this.nettyAgGridService.expandCollapseGrid(this.gridApi, this.gridExpanded()));
1621
- }
1622
- quickSearch(searchStr = '') {
1623
- this.searchValue.set(searchStr);
1624
- if (this.gridApi) {
1625
- this.gridApi.setGridOption('quickFilterText', this.searchValue());
1626
- }
1627
- sessionStorage.setItem(this.searchValueName(), this.searchValue());
1628
- }
1629
1798
  /**
1630
1799
  * Handle back button click
1631
1800
  */
@@ -1705,8 +1874,8 @@ class NettyAgGridBase extends NettyAppsBase {
1705
1874
  ]);
1706
1875
  }
1707
1876
  toggleOpenMode() {
1708
- const newMode = !this.openInPopup();
1709
- this.openInPopup.set(newMode);
1877
+ const newMode = !this.openEditComponentInPopup();
1878
+ this.openEditComponentInPopup.set(newMode);
1710
1879
  localStorage.setItem('openInPopup', JSON.stringify(newMode));
1711
1880
  const message = newMode ? '@openInPopup' : '@openInSidenav';
1712
1881
  this.alertService.showSuccess(message);
@@ -1727,7 +1896,7 @@ class NettyAgGridBase extends NettyAppsBase {
1727
1896
  };
1728
1897
  const savedMode = localStorage.getItem('openInPopup');
1729
1898
  if (savedMode !== null) {
1730
- this.openInPopup.set(JSON.parse(savedMode) === true);
1899
+ this.openEditComponentInPopup.set(JSON.parse(savedMode) === true);
1731
1900
  }
1732
1901
  this.translateService.onLangChange.subscribe(() => {
1733
1902
  this.setAgGridTranslations();
@@ -1742,179 +1911,77 @@ class NettyAgGridBase extends NettyAppsBase {
1742
1911
  if (this.hasValidValue(this.componantParameterType())) {
1743
1912
  this.parameterType.set(this.componantParameterType());
1744
1913
  }
1745
- else if (this.hasValidValue(this.queryParameterType())) {
1746
- this.parameterType.set(this.queryParameterType());
1747
- }
1748
- if (this.hasValidValue(this.parameterGUID)) {
1749
- this.setFilter();
1750
- this.loadData();
1751
- }
1752
- else {
1753
- // Clear right side nav if parameterGUID is not provided
1754
- this.commonService.clearOutlet();
1755
- }
1756
- });
1757
- effect(() => {
1758
- const update = this.commonService.updates();
1759
- if (!update || !this.gridApi)
1760
- return;
1761
- if (update.type === this.getEntityType?.()) {
1762
- switch (update.action) {
1763
- case 'add':
1764
- case 'update':
1765
- this.updateRowInGrid(update.data);
1766
- break;
1767
- }
1768
- }
1769
- });
1770
- effect(() => {
1771
- this.onElementSelect.emit(this.selectedRows());
1772
- });
1773
- // Manage filter expanded state
1774
- effect(() => {
1775
- if (this.isEmbedded()) {
1776
- this.isFilterExpanded.set(false);
1777
- }
1778
- else {
1779
- this.isFilterExpanded.set(this.isFilterValid());
1780
- }
1781
- this.showHideEmbeddedColumnsAsync();
1782
- });
1783
- }
1784
- onReverseIsFilterValid() {
1785
- if (this.isEmbedded()) {
1786
- this.isFilterExpanded.set(false);
1787
- }
1788
- else {
1789
- this.isFilterValid.update((a) => !a);
1790
- }
1791
- }
1792
- /**
1793
- * Validates if the given value is equal to null,undefined or ''
1794
- * @param value
1795
- * @returns true if has a valid value
1796
- */
1797
- hasValidValue(value) {
1798
- if (value == null || value == undefined) {
1799
- return false;
1800
- }
1801
- if (value == '') {
1802
- return false;
1803
- }
1804
- return true;
1805
- }
1806
- setAgGridTranslations() {
1807
- if (this.gridApi) {
1808
- this.gridApi.setGridOption('localeText', {
1809
- // Status panel translate
1810
- totalRows: this.translateService.instant('AG_GRID.TOTAL_ROWS'),
1811
- filteredRows: this.translateService.instant('AG_GRID.FILTERED_ROWS'),
1812
- selectedRows: this.translateService.instant('AG_GRID.SELECTED_ROWS'),
1813
- noRowsToShow: this.translateService.instant('AG_GRID.NO_ROWS_TO_SHOW'),
1814
- loadingOoo: this.translateService.instant('AG_GRID.LOADING'),
1815
- // Context menu translations
1816
- copy: this.translateService.instant('AG_GRID.COPY'),
1817
- copyWithHeaders: this.translateService.instant('AG_GRID.COPY_WITH_HEADERS'),
1818
- copyWithGroupHeaders: this.translateService.instant('AG_GRID.COPY_WITH_GROUP_HEADERS'),
1819
- paste: this.translateService.instant('AG_GRID.PASTE'),
1820
- export: this.translateService.instant('AG_GRID.EXPORT'),
1821
- csvExport: this.translateService.instant('AG_GRID.CSV_EXPORT'),
1822
- excelExport: this.translateService.instant('AG_GRID.EXCEL_EXPORT'),
1823
- pinColumn: this.translateService.instant('AG_GRID.PIN_COLUMN'),
1824
- pinLeft: this.translateService.instant('AG_GRID.PIN_LEFT'),
1825
- pinRight: this.translateService.instant('AG_GRID.PIN_RIGHT'),
1826
- noPin: this.translateService.instant('AG_GRID.NO_PIN'),
1827
- sortAscending: this.translateService.instant('AG_GRID.SORT_ASCENDING'),
1828
- sortDescending: this.translateService.instant('AG_GRID.SORT_DESCENDING'),
1829
- autosizeThisColumn: this.translateService.instant('AG_GRID.AUTOSIZE_THIS_COLUMN'),
1830
- autosizeAllColumns: this.translateService.instant('AG_GRID.AUTOSIZE_ALL_COLUMNS'),
1831
- resetColumns: this.translateService.instant('AG_GRID.RESET_COLUMNS'),
1832
- expandAll: this.translateService.instant('AG_GRID.EXPAND_ALL'),
1833
- collapseAll: this.translateService.instant('AG_GRID.COLLAPSE_ALL'),
1834
- exportToExcel: this.translateService.instant('AG_GRID.EXPORT_TO_EXCEL'),
1835
- sheetName: this.translateService.instant('AG_GRID.SHEET_NAME'),
1836
- exportAsExcelTable: this.translateService.instant('AG_GRID.EXPORT_AS_EXCEL_TABLE'),
1837
- rangeSelectTo: this.translateService.instant('AG_GRID.RANGE_SELECT_TO'),
1838
- rangeSelectFrom: this.translateService.instant('AG_GRID.RANGE_SELECT_FROM'),
1839
- rangeSelectCopy: this.translateService.instant('AG_GRID.RANGE_SELECT_COPY'),
1840
- rangeSelectChart: this.translateService.instant('AG_GRID.RANGE_SELECT_CHART'),
1841
- pasteAll: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE'),
1842
- pasteWithoutHeader: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE_WITHOUT_HEADER'),
1843
- copyAll: this.translateService.instant('AG_GRID.CLIPBOARD_COPY'),
1844
- cut: this.translateService.instant('AG_GRID.CLIPBOARD_CUT'),
1845
- // Pagination translations
1846
- page: this.translateService.instant('AG_GRID.PAGE'),
1847
- more: this.translateService.instant('AG_GRID.MORE'),
1848
- to: this.translateService.instant('AG_GRID.TO'),
1849
- of: this.translateService.instant('AG_GRID.OF'),
1850
- next: this.translateService.instant('AG_GRID.NEXT'),
1851
- last: this.translateService.instant('AG_GRID.LAST'),
1852
- first: this.translateService.instant('AG_GRID.FIRST'),
1853
- previous: this.translateService.instant('AG_GRID.PREVIOUS'),
1854
- pageSizeSelectorLabel: this.translateService.instant('AG_GRID.PAGE_SIZE_SELECTOR_LABEL'),
1855
- // Set Filter
1856
- selectAll: this.translateService.instant('AG_GRID.SELECT_ALL'),
1857
- selectAllSearchResults: this.translateService.instant('AG_GRID.SELECT_ALL_SEARCH_RESULTS'),
1858
- searchOoo: this.translateService.instant('AG_GRID.SEARCH_OOO'),
1859
- blanks: this.translateService.instant('AG_GRID.BLANKS'),
1860
- noMatches: this.translateService.instant('AG_GRID.NO_MATCHES'),
1861
- // Number Filter & Text Filter
1862
- filterOoo: this.translateService.instant('AG_GRID.FILTER_OOO'),
1863
- equals: this.translateService.instant('AG_GRID.EQUALS'),
1864
- notEqual: this.translateService.instant('AG_GRID.NOT_EQUAL'),
1865
- blank: this.translateService.instant('AG_GRID.BLANK'),
1866
- notBlank: this.translateService.instant('AG_GRID.NOT_BLANK'),
1867
- empty: this.translateService.instant('AG_GRID.EMPTY'),
1868
- // Number Filter
1869
- lessThan: this.translateService.instant('AG_GRID.LESS_THAN'),
1870
- greaterThan: this.translateService.instant('AG_GRID.GREATER_THAN'),
1871
- lessThanOrEqual: this.translateService.instant('AG_GRID.LESS_THAN_OR_EQUAL'),
1872
- greaterThanOrEqual: this.translateService.instant('AG_GRID.GREATER_THAN_OR_EQUAL'),
1873
- inRange: this.translateService.instant('AG_GRID.IN_RANGE'),
1874
- inRangeStart: this.translateService.instant('AG_GRID.IN_RANGE_START'),
1875
- inRangeEnd: this.translateService.instant('AG_GRID.IN_RANGE_END'),
1876
- // Text Filter
1877
- contains: this.translateService.instant('AG_GRID.CONTAINS'),
1878
- notContains: this.translateService.instant('AG_GRID.NOT_CONTAINS'),
1879
- startsWith: this.translateService.instant('AG_GRID.STARTS_WITH'),
1880
- endsWith: this.translateService.instant('AG_GRID.ENDS_WITH'),
1881
- // Date Filter
1882
- dateFormatOoo: this.translateService.instant('AG_GRID.DATE_FORMAT_OOO'),
1883
- // Filter Conditions
1884
- andCondition: this.translateService.instant('AG_GRID.AND_CONDITION'),
1885
- orCondition: this.translateService.instant('AG_GRID.OR_CONDITION'),
1886
- // Filter Buttons
1887
- applyFilter: this.translateService.instant('AG_GRID.APPLY_FILTER'),
1888
- resetFilter: this.translateService.instant('AG_GRID.RESET_FILTER'),
1889
- clearFilter: this.translateService.instant('AG_GRID.CLEAR_FILTER'),
1890
- cancelFilter: this.translateService.instant('AG_GRID.CANCEL_FILTER'),
1891
- // Filter Titles
1892
- textFilter: this.translateService.instant('AG_GRID.TEXT_FILTER'),
1893
- numberFilter: this.translateService.instant('AG_GRID.NUMBER_FILTER'),
1894
- dateFilter: this.translateService.instant('AG_GRID.DATE_FILTER'),
1895
- setFilter: this.translateService.instant('AG_GRID.SET_FILTER'),
1896
- });
1897
- }
1914
+ else if (this.hasValidValue(this.queryParameterType())) {
1915
+ this.parameterType.set(this.queryParameterType());
1916
+ }
1917
+ if (this.hasValidValue(this.parameterGUID)) {
1918
+ this.isFilterValid.set(false);
1919
+ this.setFilter();
1920
+ this.loadData();
1921
+ }
1922
+ else {
1923
+ // Clear right side nav if parameterGUID is not provided
1924
+ this.commonService.clearOutlet();
1925
+ }
1926
+ });
1927
+ effect(() => {
1928
+ const update = this.commonService.updates();
1929
+ if (!update || !this.gridApi)
1930
+ return;
1931
+ if (update.type === this.getEntityType?.()) {
1932
+ switch (update.action) {
1933
+ case 'add':
1934
+ case 'update':
1935
+ this.updateRowInGrid(update.data);
1936
+ break;
1937
+ }
1938
+ }
1939
+ });
1940
+ effect(() => { this.onElementSelect.emit(this.selectedRows()); });
1941
+ // Manage filter expanded state
1942
+ effect(() => {
1943
+ this.isEmbedded();
1944
+ this.showHideEmbeddedColumnsAsync();
1945
+ });
1946
+ }
1947
+ onReverseIsFilterValid() {
1948
+ this.isFilterValid.update((a) => !a);
1898
1949
  }
1899
1950
  /**
1900
- * Update a single row in the grid
1901
- * @param rowData The updated row data
1902
- * @param idField The field name that serves as unique identifier (default: 'id')
1951
+ * Validates if the given value is equal to null,undefined or ''
1952
+ * @param value
1953
+ * @returns true if has a valid value
1903
1954
  */
1904
- updateRowInGrid(rowData, idField = 'id') {
1905
- const rowNode = this.gridApi.getRowNode(rowData[idField]);
1906
- if (rowNode) {
1907
- rowNode.setData(rowData);
1908
- const params = {
1909
- rowNodes: [rowNode],
1910
- force: true,
1911
- suppressFlash: false,
1912
- };
1913
- this.gridApi.refreshCells(params);
1955
+ hasValidValue(value) {
1956
+ if (value == null || value == undefined) {
1957
+ return false;
1914
1958
  }
1915
- else {
1916
- this.loadData(); // Reload all data if row not found
1959
+ if (value == '') {
1960
+ return false;
1961
+ }
1962
+ return true;
1963
+ }
1964
+ onFilterTextBoxVisibilityChange(isOpen) {
1965
+ this.menuValid.set(!isOpen);
1966
+ }
1967
+ setFilter() { } //override this to set a filter
1968
+ popupClose() {
1969
+ this.selectedElement.emit(null);
1970
+ }
1971
+ // *********************************************************
1972
+ // *** Data Management Functions ***
1973
+ // *********************************************************
1974
+ loadData() {
1975
+ if (this.hasFilter()) {
1976
+ this.setData([]);
1977
+ return;
1917
1978
  }
1979
+ this.nettyAppsProxy.select(this.record).subscribe({
1980
+ next: (data) => {
1981
+ this.setData(data);
1982
+ },
1983
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
1984
+ });
1918
1985
  }
1919
1986
  async deleteSelected() {
1920
1987
  if (!this.gridApi)
@@ -1927,7 +1994,7 @@ class NettyAgGridBase extends NettyAppsBase {
1927
1994
  const confirmed = await this.alertService.showConfirm('@confirmDeleteSelectedRecords');
1928
1995
  if (confirmed) {
1929
1996
  const selectedRows = selectedNodes.map((node) => node.data);
1930
- this.deleteRows?.(selectedRows);
1997
+ this.deleteRows(selectedRows);
1931
1998
  }
1932
1999
  }
1933
2000
  async refreshData() {
@@ -1939,84 +2006,58 @@ class NettyAgGridBase extends NettyAppsBase {
1939
2006
  this.alertService.showError(err);
1940
2007
  }
1941
2008
  }
1942
- async setAccessRights() {
1943
- this.authenticationList = await lastValueFrom(this.sysFunctionProxy.getAuthentication(this.componentName())).catch((e) => {
1944
- return throwError(() => new Error(e));
2009
+ deleteRows(rows) {
2010
+ this.nettyAppsProxy.deleteList(rows).subscribe({
2011
+ next: () => {
2012
+ this.gridApi.applyTransaction({ remove: rows });
2013
+ this.alertService.showSuccess('@recordDeletedSuccessfully');
2014
+ },
2015
+ error: (err) => this.alertService.showError(err),
1945
2016
  });
1946
- try {
1947
- this.allowRead.set(this.authenticationList.find((f) => f.action == 'read')?.allow ?? false);
1948
- if (this.allowRead() == false) {
1949
- this.commonService.userNotAllowedToRead();
1950
- return false;
1951
- }
1952
- if (this.allowRead() == true && !this.readOnly()) {
1953
- this.allowAdd.set(this.authenticationList.find((f) => f.action == 'add')?.allow ?? false);
1954
- this.allowEdit.set(this.authenticationList.find((f) => f.action == 'edit')?.allow ??
1955
- false);
1956
- this.allowDelete.set(this.authenticationList.find((f) => f.action == 'delete')?.allow ??
1957
- false);
1958
- this.allowLog.set(this.authenticationList.find((f) => f.action == 'logAccess')?.allow ??
1959
- false);
1960
- }
1961
- else {
1962
- this.allowAdd.set(false);
1963
- this.allowEdit.set(false);
1964
- this.allowDelete.set(false);
1965
- this.allowLog.set(false);
1966
- }
1967
- }
1968
- catch (error) {
1969
- this.allowAdd.set(false);
1970
- this.allowEdit.set(false);
1971
- this.allowDelete.set(false);
1972
- this.allowLog.set(false);
1973
- return false;
1974
- }
1975
- this.accessRightsProcessed.set(true);
1976
- return true;
1977
- }
1978
- onFilterTextBoxVisibilityChange(isOpen) {
1979
- this.menuValid.set(!isOpen);
1980
- }
1981
- setFilter() { } //override this to set a filter
1982
- popupClose() {
1983
- this.selectedElement.emit(null);
1984
- }
1985
- // ---------------------------------------------
1986
- // --- Functions to Show / Hide Grid Columns ---
1987
- // ---------------------------------------------
1988
- onShowHideColumns() {
1989
- this.gridColumnsVisible.update((a) => !a);
1990
- this.showHideColumnsAsync();
1991
- }
1992
- showHideColumnsAsync() {
1993
- setTimeout(() => this.showHideColumns(), 400);
1994
- }
1995
- showHideColumns() {
1996
- var fields = this.columnDefs()
1997
- .filter((columnDef) => columnDef.ntyHide === 'x')
1998
- .map((columnDef) => columnDef.field);
1999
- this.gridApi?.setColumnsVisible(fields, this.gridColumnsVisible());
2000
- }
2001
- showHideEmbeddedColumnsAsync() {
2002
- setTimeout(() => this.showHideEmbeddedColumns(), 100);
2003
2017
  }
2004
- showHideEmbeddedColumns() {
2005
- if (this.columnDefs() == undefined || this.columnDefs() == null) {
2006
- return;
2018
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridListBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2019
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridListBase, isStandalone: true, selector: "ntybase-ag-grid-list-base", inputs: { componantParameterGUID: { classPropertyName: "componantParameterGUID", publicName: "componantParameterGUID", isSignal: true, isRequired: false, transformFunction: null }, componantParameterType: { classPropertyName: "componantParameterType", publicName: "componantParameterType", isSignal: true, isRequired: false, transformFunction: null }, hasFilter: { classPropertyName: "hasFilter", publicName: "hasFilter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onElementSelect: "onElementSelect", selectedElement: "selectedElement" }, host: { attributes: { "ntybase-id": "NettyAgGridListBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2020
+ }
2021
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridListBase, decorators: [{
2022
+ type: Component,
2023
+ args: [{ selector: 'ntybase-ag-grid-list-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridListBase' } }]
2024
+ }], ctorParameters: () => [], propDecorators: { componantParameterGUID: [{ type: i0.Input, args: [{ isSignal: true, alias: "componantParameterGUID", required: false }] }], componantParameterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "componantParameterType", required: false }] }], onElementSelect: [{ type: i0.Output, args: ["onElementSelect"] }], selectedElement: [{ type: i0.Output, args: ["selectedElement"] }], hasFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasFilter", required: false }] }] } });
2025
+
2026
+ class NettyAgGridLogBase extends NettyAgGridBase {
2027
+ // ---------------------------------------------------
2028
+ // --- RECORD LIST ---
2029
+ // ---------------------------------------------------
2030
+ nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
2031
+ /**
2032
+ * Component initialization lifecycle hook
2033
+ */
2034
+ async ngOnInit() {
2035
+ this.nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
2036
+ await this.setAccessRights();
2037
+ const savedSearchValue = sessionStorage.getItem(this.searchValueName());
2038
+ if (savedSearchValue) {
2039
+ this.searchValue.set(savedSearchValue);
2007
2040
  }
2008
- var fields = this.columnDefs()
2009
- .filter((columnDef) => columnDef.ntyEmbeddedHide == 'x')
2010
- .map((columnDef) => columnDef.field);
2011
- this.gridApi?.setColumnsVisible(fields, !this.isEmbedded());
2041
+ this.loadData();
2042
+ // Load user grid preferences
2043
+ await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
2044
+ await this.AfterOnInit();
2045
+ }
2046
+ loadData() {
2047
+ this.nettyAppsProxy.selectLog(this.record).subscribe({
2048
+ next: (data) => {
2049
+ this.setData(data);
2050
+ },
2051
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
2052
+ });
2012
2053
  }
2013
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2014
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridBase, isStandalone: true, selector: "ntybase-ag-grid-base", inputs: { readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, popupFilterValid: { classPropertyName: "popupFilterValid", publicName: "popupFilterValid", isSignal: true, isRequired: false, transformFunction: null }, popupValid: { classPropertyName: "popupValid", publicName: "popupValid", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null }, componantParameterGUID: { classPropertyName: "componantParameterGUID", publicName: "componantParameterGUID", isSignal: true, isRequired: false, transformFunction: null }, componantParameterType: { classPropertyName: "componantParameterType", publicName: "componantParameterType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onElementSelect: "onElementSelect", selectedElement: "selectedElement" }, host: { attributes: { "ntybase-id": "NettyAgGridBase" } }, usesInheritance: true, ngImport: i0, template: "<p>ag-grid-base works!</p>\n", styles: [""] });
2054
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridLogBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2055
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: NettyAgGridLogBase, isStandalone: true, selector: "ntybase-ag-grid-log-base", host: { attributes: { "ntybase-id": "NettyAgGridLogBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2015
2056
  }
2016
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, decorators: [{
2057
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridLogBase, decorators: [{
2017
2058
  type: Component,
2018
- args: [{ selector: 'ntybase-ag-grid-base', imports: [], host: { 'ntybase-id': 'NettyAgGridBase' }, template: "<p>ag-grid-base works!</p>\n" }]
2019
- }], ctorParameters: () => [], propDecorators: { readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], popupFilterValid: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupFilterValid", required: false }] }], popupValid: [{ type: i0.Input, args: [{ isSignal: true, alias: "popupValid", required: false }] }], isEmbedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEmbedded", required: false }] }], componantParameterGUID: [{ type: i0.Input, args: [{ isSignal: true, alias: "componantParameterGUID", required: false }] }], componantParameterType: [{ type: i0.Input, args: [{ isSignal: true, alias: "componantParameterType", required: false }] }], onElementSelect: [{ type: i0.Output, args: ["onElementSelect"] }], selectedElement: [{ type: i0.Output, args: ["selectedElement"] }] } });
2059
+ args: [{ selector: 'ntybase-ag-grid-log-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridLogBase' } }]
2060
+ }] });
2020
2061
 
2021
2062
  class NettyAgGridSaveBase extends NettyAppsBase {
2022
2063
  // Services
@@ -2030,6 +2071,11 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2030
2071
  parameters = input('', ...(ngDevMode ? [{ debugName: "parameters" }] : []));
2031
2072
  embedded = input(false, ...(ngDevMode ? [{ debugName: "embedded" }] : []));
2032
2073
  isEmbedded = input(false, ...(ngDevMode ? [{ debugName: "isEmbedded" }] : []));
2074
+ // ---------------------------------------------------
2075
+ // --- RECORD LIST ---
2076
+ // ---------------------------------------------------
2077
+ nettyAppsProxy = injectNettyStandardProxy('');
2078
+ recordType = signal('', ...(ngDevMode ? [{ debugName: "recordType" }] : []));
2033
2079
  currentItem = signal({}, ...(ngDevMode ? [{ debugName: "currentItem" }] : []));
2034
2080
  initialItem = {};
2035
2081
  // Form tracking
@@ -2038,12 +2084,29 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2038
2084
  // Dialog related properties
2039
2085
  dialogRef = inject((MatDialogRef), { optional: true });
2040
2086
  dialogData = inject(MAT_DIALOG_DATA, { optional: true });
2087
+ constructor() {
2088
+ super();
2089
+ effect(() => {
2090
+ this.parameters();
2091
+ this.loadDetailData();
2092
+ });
2093
+ }
2094
+ async ngOnInit() {
2095
+ this.loadDetailData();
2096
+ }
2041
2097
  // Controls the visibility of additional editable fields (e.g., password, extra settings)
2042
2098
  // When true, certain input fields become visible for editing
2043
2099
  updateValid = signal(false, ...(ngDevMode ? [{ debugName: "updateValid" }] : []));
2044
2100
  setUpdateValid(value) {
2045
2101
  this.updateValid.set(value);
2046
2102
  }
2103
+ /**
2104
+ * Initialize parameters. This method is called in ngOnInit or constructor
2105
+ */
2106
+ initParameters(urlPath) {
2107
+ this.nettyAppsProxy = injectNettyStandardProxy(urlPath);
2108
+ this.recordType.set(urlPath);
2109
+ }
2047
2110
  /**
2048
2111
  * Determine view mode based on current route
2049
2112
  */
@@ -2058,9 +2121,6 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2058
2121
  this.viewMode.set('fullscreen');
2059
2122
  }
2060
2123
  }
2061
- ngOnInit() {
2062
- this.loadDetailData();
2063
- }
2064
2124
  /**
2065
2125
  * Set data to the form while preserving any unsaved changes
2066
2126
  * @param item - Data object of type T to populate the form
@@ -2081,8 +2141,9 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2081
2141
  * @param data - Data to populate the new instance
2082
2142
  */
2083
2143
  createItemInstance(data) {
2084
- // Default implementation - child classes can override this
2085
- return { ...data };
2144
+ const instance = this.createNewRecord();
2145
+ Object.assign(instance, data);
2146
+ return instance;
2086
2147
  }
2087
2148
  /**
2088
2149
  * Check for form changes
@@ -2120,11 +2181,6 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2120
2181
  }
2121
2182
  return '';
2122
2183
  }
2123
- ngOnChanges(changes) {
2124
- if (changes['parameters']) {
2125
- this.loadDetailData();
2126
- }
2127
- }
2128
2184
  /**
2129
2185
  * Close sidenav or navigate back
2130
2186
  */
@@ -2178,6 +2234,103 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2178
2234
  }
2179
2235
  return true;
2180
2236
  }
2237
+ /**
2238
+ * Save data to API
2239
+ * Handles both create and update operations based on record existence
2240
+ */
2241
+ saveRecord() {
2242
+ if (!this.validateSaveRecord(this.currentItem().getPK())) {
2243
+ return;
2244
+ }
2245
+ if (this.currentItem().getPK()) {
2246
+ this.updateRecord();
2247
+ return;
2248
+ }
2249
+ this.insertRecord();
2250
+ }
2251
+ /**
2252
+ * Create new record
2253
+ */
2254
+ insertRecord() {
2255
+ const createData = {};
2256
+ const currentItem = this.currentItem();
2257
+ Object.keys(currentItem).forEach((key) => {
2258
+ if (currentItem[key] !== undefined && currentItem[key] !== null && currentItem[key] !== '') {
2259
+ createData[key] = currentItem[key];
2260
+ }
2261
+ });
2262
+ this.nettyAppsProxy.insert(createData).subscribe({
2263
+ next: (newRecord) => {
2264
+ this.initializeFormData(newRecord);
2265
+ this.commonService.notifyUpdate(this.recordType(), 'add', newRecord);
2266
+ this.closeSidenav();
2267
+ this.alertService.showSuccess('@recordCreatedSuccessfully');
2268
+ },
2269
+ error: (err) => console.error('@creationFailed:', err),
2270
+ });
2271
+ }
2272
+ /**
2273
+ * Update record
2274
+ */
2275
+ updateRecord() {
2276
+ const changes = this.initialItem.compare(this.currentItem());
2277
+ const updateData = this.createNewRecord();
2278
+ Object.assign(updateData, changes);
2279
+ updateData.setPK(this.currentItem().getPK());
2280
+ this.nettyAppsProxy.update(updateData).subscribe({
2281
+ next: (updatedRecord) => {
2282
+ this.initializeFormData(updatedRecord);
2283
+ this.commonService.notifyUpdate('Item', 'update', updatedRecord);
2284
+ this.closeSidenav();
2285
+ this.alertService.showSuccess('@recordUpdatedSuccessfully');
2286
+ },
2287
+ error: (err) => this.alertService.showError('@updateFailed', err),
2288
+ });
2289
+ }
2290
+ /**
2291
+ * Load data from API based on GUID
2292
+ * Handles both new record creation and existing record editing
2293
+ * guid - Unique identifier of the record
2294
+ */
2295
+ loadDetailData() {
2296
+ const guid = this.getGuidFromParameters();
2297
+ if (!guid) {
2298
+ // If no GUID provided, initialize a new record
2299
+ const newRecord = this.createNewRecord();
2300
+ this.initializeFormData(newRecord);
2301
+ this.updateValid.set(true);
2302
+ return;
2303
+ }
2304
+ // Fetch existing record from API
2305
+ this.nettyAppsProxy.selectGUID(guid).subscribe({
2306
+ next: (record) => {
2307
+ if (!record || !record.getPK()) {
2308
+ this.alertService.showError('@recordNotFound');
2309
+ const cleanPath = this.commonService.getCleanUrlPath();
2310
+ this.router.navigate([cleanPath]);
2311
+ return;
2312
+ }
2313
+ this.initializeFormData(record);
2314
+ this.alertService.showSuccess('@dataLoadSuccess');
2315
+ // Ensure sidenav is visible when in sidenav mode
2316
+ if (this.viewMode() === 'sidenav') {
2317
+ this.commonService.toggleRightSidenav(true);
2318
+ }
2319
+ },
2320
+ error: (err) => {
2321
+ this.alertService.showError('@dataLoadFailed');
2322
+ this.commonService.toggleRightSidenav(false);
2323
+ // Redirect to user list on error in fullscreen mode
2324
+ if (this.viewMode() === 'fullscreen') {
2325
+ const cleanPath = this.commonService.getCleanUrlPath();
2326
+ this.router.navigate([cleanPath]);
2327
+ }
2328
+ },
2329
+ });
2330
+ }
2331
+ // ***************************************************
2332
+ // *** gotoURL Methods ***
2333
+ // ***************************************************
2181
2334
  gotoURL(routePrefix, rightSidenav = [], parameters, type, dialogComponent = null, isNewTab = false, isPopup = this.isEmbedded()) {
2182
2335
  const baseHref = this.environment.getBaseHref().endsWith('/')
2183
2336
  ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
@@ -2250,18 +2403,18 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2250
2403
  },
2251
2404
  ]);
2252
2405
  }
2253
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridSaveBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2254
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridSaveBase, isStandalone: true, selector: "ntybase-ag-grid-save-base", inputs: { parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "saveForm", first: true, predicate: ["saveForm"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<p>ag-grid-save-base works!</p>\n", styles: [""] });
2406
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridSaveBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2407
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridSaveBase, isStandalone: true, selector: "ntybase-ag-grid-save-base", inputs: { parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null }, embedded: { classPropertyName: "embedded", publicName: "embedded", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "saveForm", first: true, predicate: ["saveForm"], descendants: true }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2255
2408
  }
2256
2409
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridSaveBase, decorators: [{
2257
2410
  type: Component,
2258
- args: [{ selector: 'ntybase-ag-grid-save-base', imports: [], template: "<p>ag-grid-save-base works!</p>\n" }]
2259
- }], propDecorators: { parameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameters", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], isEmbedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEmbedded", required: false }] }], saveForm: [{
2411
+ args: [{ selector: 'ntybase-ag-grid-save-base', imports: [], template: `` }]
2412
+ }], ctorParameters: () => [], propDecorators: { parameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameters", required: false }] }], embedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "embedded", required: false }] }], isEmbedded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isEmbedded", required: false }] }], saveForm: [{
2260
2413
  type: ViewChild,
2261
2414
  args: ['saveForm']
2262
2415
  }] } });
2263
2416
 
2264
- class ExcelImportBase extends NettyAgGridBase {
2417
+ class ExcelImportBase extends NettyAgGridListBase {
2265
2418
  dataList = [];
2266
2419
  wopts = { bookType: 'xlsx', type: 'array' };
2267
2420
  fileName = 'PayrollJournalTrans.xlsx';
@@ -2290,11 +2443,11 @@ class ExcelImportBase extends NettyAgGridBase {
2290
2443
  reader.readAsBinaryString(target.files[0]);
2291
2444
  }
2292
2445
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ExcelImportBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2293
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ExcelImportBase, isStandalone: true, selector: "ntybase-excel-import-base", usesInheritance: true, ngImport: i0, template: "<p>excel-import-base works!</p>\n", styles: [""] });
2446
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ExcelImportBase, isStandalone: true, selector: "ntybase-excel-import-base", usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2294
2447
  }
2295
2448
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ExcelImportBase, decorators: [{
2296
2449
  type: Component,
2297
- args: [{ selector: 'ntybase-excel-import-base', imports: [], template: "<p>excel-import-base works!</p>\n" }]
2450
+ args: [{ selector: 'ntybase-excel-import-base', imports: [], template: `` }]
2298
2451
  }] });
2299
2452
 
2300
2453
  class RangeDateTimeFilter {
@@ -2589,7 +2742,7 @@ class RangeDateTimeFilter {
2589
2742
  }
2590
2743
  }
2591
2744
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeDateTimeFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2592
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeDateTimeFilter, isStandalone: true, selector: "ntybase-range-date-time-filter", host: { attributes: { "ntybase-id": "RangeDateTimeFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
2745
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeDateTimeFilter, isStandalone: true, selector: "ntybase-range-date-time-filter", host: { attributes: { "ntybase-id": "RangeDateTimeFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
2593
2746
  }
2594
2747
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeDateTimeFilter, decorators: [{
2595
2748
  type: Component,
@@ -2788,7 +2941,7 @@ class RangeNumberFilter {
2788
2941
  }
2789
2942
  }
2790
2943
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeNumberFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2791
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeNumberFilter, isStandalone: true, selector: "ntybase-range-number-filter", host: { attributes: { "ntybase-id": "RangeNumberFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
2944
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeNumberFilter, isStandalone: true, selector: "ntybase-range-number-filter", host: { attributes: { "ntybase-id": "RangeNumberFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
2792
2945
  }
2793
2946
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeNumberFilter, decorators: [{
2794
2947
  type: Component,
@@ -3041,7 +3194,7 @@ class RangeStringFilter {
3041
3194
  }
3042
3195
  }
3043
3196
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeStringFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3044
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeStringFilter, isStandalone: true, selector: "ntybase-range-string-filter", host: { attributes: { "ntybase-id": "RangeStringFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
3197
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RangeStringFilter, isStandalone: true, selector: "ntybase-range-string-filter", host: { attributes: { "ntybase-id": "RangeStringFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3045
3198
  }
3046
3199
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeStringFilter, decorators: [{
3047
3200
  type: Component,
@@ -3558,7 +3711,7 @@ class Login extends AuthBase {
3558
3711
  });
3559
3712
  }
3560
3713
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Login, deps: null, target: i0.ɵɵFactoryTarget.Component });
3561
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: Login, isStandalone: true, selector: "ntybase-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
3714
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: Login, isStandalone: true, selector: "ntybase-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3562
3715
  }
3563
3716
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Login, decorators: [{
3564
3717
  type: Component,
@@ -3670,7 +3823,7 @@ class MfaLogin extends AuthBase {
3670
3823
  clearInterval(this.countdownInterval);
3671
3824
  }
3672
3825
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MfaLogin, deps: null, target: i0.ɵɵFactoryTarget.Component });
3673
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: MfaLogin, isStandalone: true, selector: "ntybase-mfa-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"mfaCode\">{{'mfaCode' | translate}}</label>\n <input\n type=\"text\"\n id=\"mfaCode\"\n formControlName=\"mfaCode\"\n [placeholder]=\"'mfaCode' | translate\"\n required\n />\n @if (loginForm.controls['mfaCode'].invalid &&\n loginForm.controls['mfaCode'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n }\n\n <!-- Time -->\n @if (!resendable()) {\n <div class=\"time-remaining\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading() || !resendable()\"\n >\n {{ '@login' | translate }}\n </button>\n\n @if (resendable()) {\n <div class=\"resend-container\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n }\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--mfa-login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}.invalid-input{border:1px solid #dc3545!important}.invalid-input:focus{box-shadow:0 0 0 .2rem #dc354540}.resend-container{margin-top:15px;text-align:center}.resend-container .resend-link{color:#007bff;cursor:pointer;text-decoration:underline;font-size:13px}.resend-container .resend-link:hover{color:#0056b3}.time-remaining{margin-top:16px;font-size:1rem;color:#f5f5f5}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
3826
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: MfaLogin, isStandalone: true, selector: "ntybase-mfa-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"mfaCode\">{{'mfaCode' | translate}}</label>\n <input\n type=\"text\"\n id=\"mfaCode\"\n formControlName=\"mfaCode\"\n [placeholder]=\"'mfaCode' | translate\"\n required\n />\n @if (loginForm.controls['mfaCode'].invalid &&\n loginForm.controls['mfaCode'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n }\n\n <!-- Time -->\n @if (!resendable()) {\n <div class=\"time-remaining\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading() || !resendable()\"\n >\n {{ '@login' | translate }}\n </button>\n\n @if (resendable()) {\n <div class=\"resend-container\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n }\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--mfa-login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}.invalid-input{border:1px solid #dc3545!important}.invalid-input:focus{box-shadow:0 0 0 .2rem #dc354540}.resend-container{margin-top:15px;text-align:center}.resend-container .resend-link{color:#007bff;cursor:pointer;text-decoration:underline;font-size:13px}.resend-container .resend-link:hover{color:#0056b3}.time-remaining{margin-top:16px;font-size:1rem;color:#f5f5f5}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3674
3827
  }
3675
3828
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MfaLogin, decorators: [{
3676
3829
  type: Component,
@@ -3844,7 +3997,7 @@ class ForgotPassword extends AuthBase {
3844
3997
  });
3845
3998
  }
3846
3999
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ForgotPassword, deps: [], target: i0.ɵɵFactoryTarget.Component });
3847
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ForgotPassword, isStandalone: true, selector: "ntybase-forgot-password", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
4000
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: ForgotPassword, isStandalone: true, selector: "ntybase-forgot-password", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3848
4001
  }
3849
4002
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ForgotPassword, decorators: [{
3850
4003
  type: Component,
@@ -3935,6 +4088,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3935
4088
  args: [{ selector: 'ntybase-netty-base-app', imports: [], template: "" }]
3936
4089
  }] });
3937
4090
 
4091
+ class EnvironmentInfo {
4092
+ showNettyInfo = true;
4093
+ environmentProxy = inject(EnvironmentProxy);
4094
+ get hasConfig() {
4095
+ return this.environmentProxy.config() !== undefined;
4096
+ }
4097
+ get version() {
4098
+ return this.environmentProxy.version() ?? "";
4099
+ }
4100
+ get isProduction() {
4101
+ return false;
4102
+ }
4103
+ get defaultLanguage() {
4104
+ return "tr";
4105
+ }
4106
+ get supportedLanguages() {
4107
+ return [];
4108
+ }
4109
+ get apiUrl() {
4110
+ return this.environmentProxy.apiUrl();
4111
+ }
4112
+ get adminUrl() {
4113
+ return this.environmentProxy.adminUrl();
4114
+ }
4115
+ get baseHref() {
4116
+ return this.environmentProxy.baseHref();
4117
+ }
4118
+ get application() {
4119
+ return this.environmentProxy.application();
4120
+ }
4121
+ ngOnInit() {
4122
+ if (!this.hasConfig) {
4123
+ console.warn("Environment konfigürasyonu bulunamadı. ENVIRONMENT_CONFIG token'ı sağlandı mı?");
4124
+ }
4125
+ }
4126
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, deps: [], target: i0.ɵɵFactoryTarget.Component });
4127
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: EnvironmentInfo, isStandalone: true, selector: "ntybase-environment-info", inputs: { showNettyInfo: "showNettyInfo" }, ngImport: i0, template: "<div class=\"environment-info\" [class.production]=\"isProduction\">\n <div class=\"info-card\">\n <div class=\"card-header\">\n <h3>{{ 'ENVIRONMENT_INFO.applicationInfo' | translate }}</h3>\n <span class=\"env-badge\" [class.prod]=\"isProduction\">\n {{ isProduction ? ('ENVIRONMENT_INFO.prod' | translate) :\n ('ENVIRONMENT_INFO.dev' | translate) }}\n </span>\n </div>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.version' | translate }}</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.defaultLanguage' | translate }}</span\n >\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.supportedLanguages' | translate }}</span\n >\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n @if (showNettyInfo) {\n <div class=\"netty-info\">\n <h4>{{ 'ENVIRONMENT_INFO.nettyConnections' | translate }}</h4>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.apiUrl' | translate }}</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.adminUrl' | translate }}</span\n >\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.baseHref' | translate }}</span\n >\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.application' | translate }}</span\n >\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n } @if (!hasConfig) {\n <div class=\"no-config\">{{ 'ENVIRONMENT_INFO.noConfig' | translate }}</div>\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.environment-info{padding:24px;font-family:Inter,Arial,sans-serif;display:flex;justify-content:center}.info-card{width:100%;max-width:720px;background:var(--mat-sys-on-primary);border-radius:12px;padding:24px;box-shadow:0 8px 24px #0000000f;transition:all .3s ease;border:2px solid var(--mat-sys-on-primary-container)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.card-header h3{margin:0;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.env-badge{padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.env-badge.prod{background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:14px 20px;margin-bottom:20px}.info-item{display:contents}.label{color:var(--mat-sys-on-primary-container);font-size:13px;font-weight:500}.value{color:var(--mat-sys-on-primary-container);font-size:14px;font-weight:500;word-break:break-word}.netty-info{margin-top:24px;padding-top:20px;border-top:1px solid var(--mat-sys-primary)}.netty-info h4{margin:0 0 16px;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.production .info-card{border-left:6px solid #ef4444}.no-config{margin-top:20px;padding:14px;background:var(--mat-sys-primary-fixed);border:1px solid #fed7aa;border-radius:8px;color:#c2410c;font-weight:600;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4128
+ }
4129
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, decorators: [{
4130
+ type: Component,
4131
+ args: [{ selector: 'ntybase-environment-info', imports: [TranslateModule], template: "<div class=\"environment-info\" [class.production]=\"isProduction\">\n <div class=\"info-card\">\n <div class=\"card-header\">\n <h3>{{ 'ENVIRONMENT_INFO.applicationInfo' | translate }}</h3>\n <span class=\"env-badge\" [class.prod]=\"isProduction\">\n {{ isProduction ? ('ENVIRONMENT_INFO.prod' | translate) :\n ('ENVIRONMENT_INFO.dev' | translate) }}\n </span>\n </div>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.version' | translate }}</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.defaultLanguage' | translate }}</span\n >\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.supportedLanguages' | translate }}</span\n >\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n @if (showNettyInfo) {\n <div class=\"netty-info\">\n <h4>{{ 'ENVIRONMENT_INFO.nettyConnections' | translate }}</h4>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.apiUrl' | translate }}</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.adminUrl' | translate }}</span\n >\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.baseHref' | translate }}</span\n >\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.application' | translate }}</span\n >\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n } @if (!hasConfig) {\n <div class=\"no-config\">{{ 'ENVIRONMENT_INFO.noConfig' | translate }}</div>\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.environment-info{padding:24px;font-family:Inter,Arial,sans-serif;display:flex;justify-content:center}.info-card{width:100%;max-width:720px;background:var(--mat-sys-on-primary);border-radius:12px;padding:24px;box-shadow:0 8px 24px #0000000f;transition:all .3s ease;border:2px solid var(--mat-sys-on-primary-container)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.card-header h3{margin:0;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.env-badge{padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.env-badge.prod{background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:14px 20px;margin-bottom:20px}.info-item{display:contents}.label{color:var(--mat-sys-on-primary-container);font-size:13px;font-weight:500}.value{color:var(--mat-sys-on-primary-container);font-size:14px;font-weight:500;word-break:break-word}.netty-info{margin-top:24px;padding-top:20px;border-top:1px solid var(--mat-sys-primary)}.netty-info h4{margin:0 0 16px;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.production .info-card{border-left:6px solid #ef4444}.no-config{margin-top:20px;padding:14px;background:var(--mat-sys-primary-fixed);border:1px solid #fed7aa;border-radius:8px;color:#c2410c;font-weight:600;text-align:center}\n"] }]
4132
+ }], propDecorators: { showNettyInfo: [{
4133
+ type: Input
4134
+ }] } });
4135
+
3938
4136
  const ENVIRONMENT_CONFIG = new InjectionToken('ENVIRONMENT_CONFIG');
3939
4137
  class EnvironmentInfoService {
3940
4138
  config;
@@ -3977,56 +4175,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3977
4175
  args: [ENVIRONMENT_CONFIG]
3978
4176
  }] }] });
3979
4177
 
3980
- class EnvironmentInfo {
3981
- environmentService;
3982
- showNettyInfo = true;
3983
- environmentConfig = null;
3984
- get hasConfig() {
3985
- return this.environmentConfig !== null;
3986
- }
3987
- get version() {
3988
- return this.environmentService.getVersion();
3989
- }
3990
- get isProduction() {
3991
- return this.environmentService.isProduction();
3992
- }
3993
- get defaultLanguage() {
3994
- return this.environmentService.getDefaultLanguage();
3995
- }
3996
- get supportedLanguages() {
3997
- return this.environmentService.getSupportedLanguages();
3998
- }
3999
- get apiUrl() {
4000
- return this.environmentService.getApiUrl();
4001
- }
4002
- get adminUrl() {
4003
- return this.environmentService.getAdminUrl();
4004
- }
4005
- get baseHref() {
4006
- return this.environmentConfig?.nettyUrls?.baseHref || '';
4007
- }
4008
- get application() {
4009
- return this.environmentConfig?.nettyUrls?.application || '';
4010
- }
4011
- constructor(environmentService) {
4012
- this.environmentService = environmentService;
4013
- }
4014
- ngOnInit() {
4015
- this.environmentConfig = this.environmentService.getEnvironmentInfo();
4016
- if (!this.hasConfig) {
4017
- console.warn("Environment konfigürasyonu bulunamadı. ENVIRONMENT_CONFIG token'ı sağlandı mı?");
4018
- }
4019
- }
4020
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, deps: [{ token: EnvironmentInfoService }], target: i0.ɵɵFactoryTarget.Component });
4021
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: EnvironmentInfo, isStandalone: true, selector: "ntybase-environment-info", inputs: { showNettyInfo: "showNettyInfo" }, ngImport: i0, template: "<div class=\"environment-info\" [class.production]=\"isProduction\">\n <div class=\"info-card\">\n <div class=\"card-header\">\n <h3>{{ 'ENVIRONMENT_INFO.applicationInfo' | translate }}</h3>\n <span class=\"env-badge\" [class.prod]=\"isProduction\">\n {{ isProduction ? ('ENVIRONMENT_INFO.prod' | translate) :\n ('ENVIRONMENT_INFO.dev' | translate) }}\n </span>\n </div>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.version' | translate }}</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.defaultLanguage' | translate }}</span\n >\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.supportedLanguages' | translate }}</span\n >\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n @if (showNettyInfo) {\n <div class=\"netty-info\">\n <h4>{{ 'ENVIRONMENT_INFO.nettyConnections' | translate }}</h4>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.apiUrl' | translate }}</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.adminUrl' | translate }}</span\n >\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.baseHref' | translate }}</span\n >\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.application' | translate }}</span\n >\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n } @if (!hasConfig) {\n <div class=\"no-config\">{{ 'ENVIRONMENT_INFO.noConfig' | translate }}</div>\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.environment-info{padding:24px;font-family:Inter,Arial,sans-serif;display:flex;justify-content:center}.info-card{width:100%;max-width:720px;background:var(--mat-sys-on-primary);border-radius:12px;padding:24px;box-shadow:0 8px 24px #0000000f;transition:all .3s ease;border:2px solid var(--mat-sys-on-primary-container)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.card-header h3{margin:0;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.env-badge{padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.env-badge.prod{background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:14px 20px;margin-bottom:20px}.info-item{display:contents}.label{color:var(--mat-sys-on-primary-container);font-size:13px;font-weight:500}.value{color:var(--mat-sys-on-primary-container);font-size:14px;font-weight:500;word-break:break-word}.netty-info{margin-top:24px;padding-top:20px;border-top:1px solid var(--mat-sys-primary)}.netty-info h4{margin:0 0 16px;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.production .info-card{border-left:6px solid #ef4444}.no-config{margin-top:20px;padding:14px;background:var(--mat-sys-primary-fixed);border:1px solid #fed7aa;border-radius:8px;color:#c2410c;font-weight:600;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
4022
- }
4023
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, decorators: [{
4024
- type: Component,
4025
- args: [{ selector: 'ntybase-environment-info', imports: [TranslateModule], template: "<div class=\"environment-info\" [class.production]=\"isProduction\">\n <div class=\"info-card\">\n <div class=\"card-header\">\n <h3>{{ 'ENVIRONMENT_INFO.applicationInfo' | translate }}</h3>\n <span class=\"env-badge\" [class.prod]=\"isProduction\">\n {{ isProduction ? ('ENVIRONMENT_INFO.prod' | translate) :\n ('ENVIRONMENT_INFO.dev' | translate) }}\n </span>\n </div>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.version' | translate }}</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.defaultLanguage' | translate }}</span\n >\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.supportedLanguages' | translate }}</span\n >\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n @if (showNettyInfo) {\n <div class=\"netty-info\">\n <h4>{{ 'ENVIRONMENT_INFO.nettyConnections' | translate }}</h4>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">{{ 'ENVIRONMENT_INFO.apiUrl' | translate }}</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.adminUrl' | translate }}</span\n >\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.baseHref' | translate }}</span\n >\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\"\n >{{ 'ENVIRONMENT_INFO.application' | translate }}</span\n >\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n } @if (!hasConfig) {\n <div class=\"no-config\">{{ 'ENVIRONMENT_INFO.noConfig' | translate }}</div>\n }\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";.environment-info{padding:24px;font-family:Inter,Arial,sans-serif;display:flex;justify-content:center}.info-card{width:100%;max-width:720px;background:var(--mat-sys-on-primary);border-radius:12px;padding:24px;box-shadow:0 8px 24px #0000000f;transition:all .3s ease;border:2px solid var(--mat-sys-on-primary-container)}.card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}.card-header h3{margin:0;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.env-badge{padding:6px 12px;border-radius:999px;font-size:12px;font-weight:600;background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.env-badge.prod{background:var(--mat-sys-on-primary-container);color:var(--mat-sys-surface)}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:14px 20px;margin-bottom:20px}.info-item{display:contents}.label{color:var(--mat-sys-on-primary-container);font-size:13px;font-weight:500}.value{color:var(--mat-sys-on-primary-container);font-size:14px;font-weight:500;word-break:break-word}.netty-info{margin-top:24px;padding-top:20px;border-top:1px solid var(--mat-sys-primary)}.netty-info h4{margin:0 0 16px;font-size:20px;font-weight:600;color:var(--mat-sys-on-primary-container)}.production .info-card{border-left:6px solid #ef4444}.no-config{margin-top:20px;padding:14px;background:var(--mat-sys-primary-fixed);border:1px solid #fed7aa;border-radius:8px;color:#c2410c;font-weight:600;text-align:center}\n"] }]
4026
- }], ctorParameters: () => [{ type: EnvironmentInfoService }], propDecorators: { showNettyInfo: [{
4027
- type: Input
4028
- }] } });
4029
-
4030
4178
  class NtyLoadingService {
4031
4179
  requestCount = 0;
4032
4180
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
@@ -4063,7 +4211,7 @@ class NtyLoadingComponent {
4063
4211
  loadingService = inject(NtyLoadingService);
4064
4212
  isLoading = this.loadingService.isLoading;
4065
4213
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NtyLoadingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4066
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NtyLoadingComponent, isStandalone: true, selector: "app-nty-loading", host: { attributes: { "ntybase-id": "NtyLoadingComponent" } }, ngImport: i0, template: "@if (isLoading()) {\n<div class=\"loading-overlay\" (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"spinner\">\n <i class=\"fas fa-spinner\"></i>\n </div>\n <div style=\"margin-top: 10px;\">{{'@loading' | translate}}</div>\n</div>\n}", styles: [".loading-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:2147483647;display:flex;justify-content:center;align-items:center;color:#fff;flex-direction:column;pointer-events:all;cursor:wait;-webkit-user-select:none;user-select:none}.spinner{font-size:3rem}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.fa-spinner{animation:spin 1s linear infinite}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
4214
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.6", type: NtyLoadingComponent, isStandalone: true, selector: "app-nty-loading", host: { attributes: { "ntybase-id": "NtyLoadingComponent" } }, ngImport: i0, template: "@if (isLoading()) {\n<div class=\"loading-overlay\" (click)=\"$event.stopPropagation(); $event.preventDefault()\">\n <div class=\"spinner\">\n <i class=\"fas fa-spinner\"></i>\n </div>\n <div style=\"margin-top: 10px;\">{{'@loading' | translate}}</div>\n</div>\n}", styles: [".loading-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;z-index:2147483647;display:flex;justify-content:center;align-items:center;color:#fff;flex-direction:column;pointer-events:all;cursor:wait;-webkit-user-select:none;user-select:none}.spinner{font-size:3rem}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.fa-spinner{animation:spin 1s linear infinite}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4067
4215
  }
4068
4216
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NtyLoadingComponent, decorators: [{
4069
4217
  type: Component,
@@ -4119,5 +4267,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4119
4267
  * Generated bundle index. Do not edit.
4120
4268
  */
4121
4269
 
4122
- export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ENVIRONMENT_CONFIG, EnvironmentInfo, EnvironmentInfoService, ExcelImportBase, ForgotPassword, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridSaveBase, NettyAgGridService, NettyAppsBase, NettyBaseApp, NettyHelper, NettyImageService, NettyMenuService, NtyLoadingComponent, NtyLoadingInterceptor, Ntybase, NtybaseModule, RangeDateTimeFilter, RangeNumberFilter, RangeStringFilter, UrlHelperService, ntyAuthenticationInterceptor };
4270
+ export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ENVIRONMENT_CONFIG, EnvironmentInfo, EnvironmentInfoService, ExcelImportBase, ForgotPassword, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridListBase, NettyAgGridLogBase, NettyAgGridSaveBase, NettyAgGridService, NettyAppsBase, NettyBaseApp, NettyHelper, NettyImageService, NettyMenuService, NtyLoadingComponent, NtyLoadingInterceptor, Ntybase, NtybaseModule, RangeDateTimeFilter, RangeNumberFilter, RangeStringFilter, UrlHelperService, ntyAuthenticationInterceptor };
4123
4271
  //# sourceMappingURL=nettyapps-ntybase.mjs.map