@nettyapps/ntybase 21.0.34 → 21.0.35-beta.10

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, output, computed, linkedSignal, 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, NettyStandardFilterProxy } 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,24 +15,26 @@ 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
+ import { NettyEnumStorageProxy } from '@nettyapps/ntyui';
37
38
 
38
39
  class Ntybase {
39
40
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Ntybase, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -310,84 +311,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
310
311
  }]
311
312
  }] });
312
313
 
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
314
  class ConfirmDialog {
387
315
  dialogRef = inject((MatDialogRef));
388
316
  data = inject(MAT_DIALOG_DATA);
389
317
  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" }] });
318
+ 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
319
  }
392
320
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ConfirmDialog, decorators: [{
393
321
  type: Component,
@@ -404,7 +332,7 @@ class ErrorAlert {
404
332
  dialogRef = inject((MatDialogRef));
405
333
  data = inject(MAT_DIALOG_DATA);
406
334
  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" }] });
335
+ 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
336
  }
409
337
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ErrorAlert, decorators: [{
410
338
  type: Component,
@@ -484,7 +412,7 @@ class AlertService {
484
412
  });
485
413
  });
486
414
  }
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 });
415
+ 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
416
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, providedIn: 'root' });
489
417
  }
490
418
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: AlertService, decorators: [{
@@ -492,125 +420,321 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
492
420
  args: [{
493
421
  providedIn: 'root',
494
422
  }]
495
- }], ctorParameters: () => [{ type: i1$1.MatSnackBar }, { type: i1.MatDialog }, { type: i3$1.TranslateService }] });
423
+ }], ctorParameters: () => [{ type: i1$2.MatSnackBar }, { type: i1.MatDialog }, { type: i1$1.TranslateService }] });
496
424
 
497
- class CommonService {
498
- // Services
499
- router = inject(Router);
500
- location = inject(Location);
501
- datePipe = inject(DatePipe);
502
- decimalPipe = inject(DecimalPipe);
425
+ class NettyAppsBase {
426
+ // ---------------------------------
427
+ // --- SERVICES ---
428
+ // ---------------------------------
503
429
  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
- }
430
+ translateService = inject(TranslateService);
431
+ // ---------------------------------
432
+ // --- DOWNLOAD METHODS ---
433
+ // ---------------------------------
511
434
  /**
512
- * Normalizes Turkish text for search and comparison operations by converting
513
- * Turkish special characters to their English equivalents and lowercasing.
435
+ * Download the given base64Encoded data as file
514
436
  *
437
+ * @param base64Data: base64 encoded data
438
+ * @param fileName: filename to download
515
439
  */
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('/');
440
+ downloadFile(base64Data, fileName) {
441
+ if (base64Data == null) {
442
+ return;
537
443
  }
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
- });
444
+ if (fileName == null) {
445
+ return;
564
446
  }
565
- this.toggleRightSidenav(false);
566
- this.dialog.closeAll();
567
- }
568
- ngOnDestroy() {
569
- this.clearOutlet();
447
+ // Check if header is present
448
+ if (!base64Data.startsWith('data:')) {
449
+ console.error('Provided data is not in base64 format (missing header)');
450
+ return;
451
+ }
452
+ const contentType = base64Data.split(';')[0].split(':')[1];
453
+ const byteCharacters = atob(base64Data.split(',')[1]);
454
+ const byteArrays = [];
455
+ for (let i = 0; i < byteCharacters.length; i++) {
456
+ const byteArray = byteCharacters.charCodeAt(i);
457
+ byteArrays.push(byteArray);
458
+ }
459
+ const byteArray = new Uint8Array(byteArrays);
460
+ const blob = new Blob([byteArray], { type: contentType });
461
+ const link = document.createElement('a');
462
+ link.href = URL.createObjectURL(blob);
463
+ link.download = fileName;
464
+ link.click();
570
465
  }
571
- /** Merge columns with the given seperator
466
+ /** Download the given base64Endoced data as text file
572
467
  *
573
- * @param columns string array to merge
574
- * @param seperator seperator for the array. space if null
575
- * @returns merged string
468
+ * @param base64EncodedFileData
469
+ * @param fileName
576
470
  */
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();
471
+ downloadTextFile(base64EncodedFileData, fileName) {
472
+ // Check if the data has a prefix like "data:application/pdf;base64,"
473
+ if (base64EncodedFileData == null) {
474
+ return;
475
+ }
476
+ if (fileName == null) {
477
+ return;
478
+ }
479
+ let _data = base64EncodedFileData;
480
+ const prefix = 'data:';
481
+ if (_data.startsWith(prefix)) {
482
+ // Remove the prefix
483
+ _data = _data.slice(_data.indexOf(',') + 1);
484
+ }
485
+ // Convert the base64 data to a Uint8Array
486
+ const textData = Buffer.from(_data ?? '', 'base64').toString();
487
+ this.downloadTextFileNotEncoded(textData, fileName);
589
488
  }
590
- /** Go back to the last page or close the tab
489
+ /** Save the given text as a text file
591
490
  *
491
+ * @param fileData
492
+ * @param fileName
592
493
  */
593
- goBack() {
594
- if (!document.referrer) {
595
- this.location.back();
494
+ downloadTextFileNotEncoded(fileData, fileName) {
495
+ if (fileData == null) {
496
+ return;
596
497
  }
597
- else {
598
- window.close();
498
+ if (fileName == null) {
499
+ return;
599
500
  }
501
+ // Create a Blob from the Text
502
+ const blob = new Blob([fileData], { type: 'text/plain' });
503
+ // Create a download link
504
+ const url = window.URL.createObjectURL(blob);
505
+ const a = document.createElement('a');
506
+ document.body.appendChild(a);
507
+ a.style.display = 'none';
508
+ a.href = url;
509
+ a.download = fileName ?? 'filename';
510
+ // Trigger the download
511
+ a.click();
512
+ // Clean up
513
+ window.URL.revokeObjectURL(url);
514
+ document.body.removeChild(a);
600
515
  }
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
516
+ /**
517
+ * Download file where the data is provided as blob
518
+ * @param data - Array Buffer data
519
+ * @param type - type of the document.
607
520
  */
608
- delay(ms) {
609
- return new Promise((resolve) => setTimeout(resolve, ms));
610
- }
611
- // Base64 Functions
612
- //--------------------------------------
613
- /** Convert string to base64
521
+ downloadBlobFile(data, type, fileName) {
522
+ let blob = new Blob([data], { type: type });
523
+ let downloadLink = document.createElement('a');
524
+ downloadLink.href = window.URL.createObjectURL(blob);
525
+ downloadLink.setAttribute('download', fileName);
526
+ document.body.appendChild(downloadLink);
527
+ downloadLink.click();
528
+ downloadLink.parentNode?.removeChild(downloadLink);
529
+ }
530
+ // ---------------------------------
531
+ // --- INTERFACE IMPLEMENTATIONS ---
532
+ // ---------------------------------
533
+ onDestroy$ = new Subject();
534
+ ngOnDestroy() {
535
+ //Called once, before the instance is destroyed.
536
+ //Add 'implements OnDestroy' to the class.
537
+ this.onDestroy$.next();
538
+ this.onDestroy$.complete();
539
+ }
540
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
541
+ 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 });
542
+ }
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsBase, decorators: [{
544
+ type: Component,
545
+ args: [{ selector: 'ntybase-netty-apps-base', imports: [], template: `` }]
546
+ }] });
547
+
548
+ class NettyHelper {
549
+ /**
550
+ * Returns null if fields are equal otherwise return second field
551
+ * @param firstField
552
+ * @param secondField
553
+ * @returns
554
+ */
555
+ static difference(firstField, secondField) {
556
+ if (firstField != secondField) {
557
+ return secondField;
558
+ }
559
+ return null;
560
+ }
561
+ /**
562
+ * Returns null if fields are equal otherwise return second field
563
+ * @param firstField
564
+ * @param secondField
565
+ * @param format
566
+ * @returns
567
+ */
568
+ static dateDifference(firstField, secondField, format) {
569
+ let culture = localStorage.getItem('languageApiCode') ?? 'tr-TR';
570
+ let datePipe = new DatePipe(culture);
571
+ if (datePipe.transform(firstField, format) !=
572
+ datePipe.transform(secondField, format)) {
573
+ return secondField;
574
+ }
575
+ return null;
576
+ }
577
+ }
578
+
579
+ class CurrentUserPreference {
580
+ coid = null;
581
+ nettyUserPreferenceGUID = null;
582
+ nettyUserGUID = null;
583
+ nettyUserName = null;
584
+ nettyUserFullName = null;
585
+ nettyPreferenceType = null;
586
+ nettyPreferenceData = null;
587
+ init() {
588
+ this.coid = null;
589
+ this.nettyUserPreferenceGUID = null;
590
+ this.nettyUserGUID = null;
591
+ this.nettyUserName = '';
592
+ this.nettyUserFullName = '';
593
+ this.nettyPreferenceType = '';
594
+ this.nettyPreferenceData = '';
595
+ }
596
+ initParameter(parameters) {
597
+ if (parameters == null || parameters == undefined) {
598
+ this.init();
599
+ return;
600
+ }
601
+ this.coid = parameters.coid;
602
+ this.nettyUserPreferenceGUID = parameters.nettyUserPreferenceGUID;
603
+ this.nettyUserGUID = parameters.nettyUserGUID;
604
+ this.nettyUserName = parameters.nettyUserName;
605
+ this.nettyUserFullName = parameters.nettyUserFullName;
606
+ this.nettyPreferenceType = parameters.nettyPreferenceType;
607
+ this.nettyPreferenceData = parameters.nettyPreferenceData;
608
+ }
609
+ compare(record) {
610
+ let newRecord = new CurrentUserPreference();
611
+ newRecord.init();
612
+ newRecord.coid = record.coid;
613
+ newRecord.nettyUserPreferenceGUID = record.nettyUserPreferenceGUID;
614
+ newRecord.nettyUserGUID = NettyHelper.difference(this.nettyUserGUID, record.nettyUserGUID);
615
+ newRecord.nettyPreferenceType = NettyHelper.difference(this.nettyPreferenceType, record.nettyPreferenceType);
616
+ newRecord.nettyPreferenceData = NettyHelper.difference(this.nettyPreferenceData, record.nettyPreferenceData);
617
+ return newRecord;
618
+ }
619
+ }
620
+
621
+ class CommonService {
622
+ // Services
623
+ router = inject(Router);
624
+ location = inject(Location);
625
+ datePipe = inject(DatePipe);
626
+ decimalPipe = inject(DecimalPipe);
627
+ alertService = inject(AlertService);
628
+ translate = inject(TranslateService);
629
+ dialog = inject(MatDialog);
630
+ // Right sidenav
631
+ rightSidenavOpen = signal(false, ...(ngDevMode ? [{ debugName: "rightSidenavOpen" }] : []));
632
+ toggleRightSidenav(open) {
633
+ this.rightSidenavOpen.set(open);
634
+ }
635
+ /**
636
+ * Normalizes Turkish text for search and comparison operations by converting
637
+ * Turkish special characters to their English equivalents and lowercasing.
638
+ *
639
+ */
640
+ normalizeTurkish(text) {
641
+ return text
642
+ .toLocaleLowerCase('tr-TR')
643
+ .replace(/[ıİ]/g, 'i')
644
+ .replace(/[ğĞ]/g, 'g')
645
+ .replace(/[üÜ]/g, 'u')
646
+ .replace(/[şŞ]/g, 's')
647
+ .replace(/[öÖ]/g, 'o')
648
+ .replace(/[çÇ]/g, 'c');
649
+ }
650
+ /**
651
+ * Gets the clean URL path without fragments or query params
652
+ */
653
+ getCleanUrlPath() {
654
+ const tree = this.router.parseUrl(this.router.url);
655
+ const segments = tree.root.children['primary']?.segments || [];
656
+ if (segments.length >= 2) {
657
+ return segments
658
+ .slice(0, 2)
659
+ .map((s) => s.path)
660
+ .join('/');
661
+ }
662
+ return '/';
663
+ }
664
+ /**
665
+ * Clears the right sidenav outlet and resets the UI state.
666
+ * Removes the right sidenav route while keeping the main content and query parameters.
667
+ * Also collapses the sidenav and closes any open dialogs.
668
+ */
669
+ clearOutlet() {
670
+ const currentUrl = this.router.parseUrl(this.router.url);
671
+ const primaryOutlet = currentUrl.root.children['primary'];
672
+ const rightSidenavOutlet = currentUrl.root.children['rightSidenav'];
673
+ if (rightSidenavOutlet ||
674
+ currentUrl.queryParams['parameters'] ||
675
+ currentUrl.queryParams['type']) {
676
+ this.router.navigate([
677
+ {
678
+ outlets: {
679
+ rightSidenav: null,
680
+ primary: primaryOutlet ? primaryOutlet.toString() : null,
681
+ },
682
+ },
683
+ ], {
684
+ queryParams: {},
685
+ queryParamsHandling: '',
686
+ replaceUrl: true,
687
+ });
688
+ }
689
+ this.toggleRightSidenav(false);
690
+ this.dialog.closeAll();
691
+ }
692
+ ngOnDestroy() {
693
+ this.clearOutlet();
694
+ }
695
+ /** Merge columns with the given seperator
696
+ *
697
+ * @param columns string array to merge
698
+ * @param seperator seperator for the array. space if null
699
+ * @returns merged string
700
+ */
701
+ mergeColumns(columns, seperator = ' ') {
702
+ console.log('mergeColumns', columns);
703
+ let result = '';
704
+ columns.forEach((column) => {
705
+ if (!(column == undefined || column == null)) {
706
+ if (result.length > 0) {
707
+ result += seperator;
708
+ }
709
+ result += column.trim();
710
+ }
711
+ });
712
+ return result.trim();
713
+ }
714
+ /** Go back to the last page or close the tab
715
+ *
716
+ */
717
+ goBack() {
718
+ if (!document.referrer) {
719
+ this.location.back();
720
+ }
721
+ else {
722
+ window.close();
723
+ }
724
+ }
725
+ // General Functions
726
+ //--------------------------------------
727
+ /** Delay for the given duration
728
+ *
729
+ * @param ms wait duration in ms
730
+ * @returns promise that waits for the duration
731
+ */
732
+ delay(ms) {
733
+ return new Promise((resolve) => setTimeout(resolve, ms));
734
+ }
735
+ // Base64 Functions
736
+ //--------------------------------------
737
+ /** Convert string to base64
614
738
  *
615
739
  * @param stringForConversion
616
740
  * @returns
@@ -751,6 +875,7 @@ class NettyAgGridService {
751
875
  nettyAlertService = inject(AlertService);
752
876
  environmentProxy = inject(EnvironmentProxy);
753
877
  commonService = inject(CommonService);
878
+ translateService = inject(TranslateService);
754
879
  constructor() {
755
880
  this.userPreferenceLock = new Mutex();
756
881
  }
@@ -976,447 +1101,422 @@ class NettyAgGridService {
976
1101
  },
977
1102
  ];
978
1103
  }
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' });
1104
+ setAgGridTranslations(gridApi) {
1105
+ if (gridApi) {
1106
+ gridApi.setGridOption('localeText', {
1107
+ // Status panel translate
1108
+ totalRows: this.translateService.instant('AG_GRID.TOTAL_ROWS'),
1109
+ filteredRows: this.translateService.instant('AG_GRID.FILTERED_ROWS'),
1110
+ selectedRows: this.translateService.instant('AG_GRID.SELECTED_ROWS'),
1111
+ noRowsToShow: this.translateService.instant('AG_GRID.NO_ROWS_TO_SHOW'),
1112
+ loadingOoo: this.translateService.instant('AG_GRID.LOADING'),
1113
+ // Context menu translations
1114
+ copy: this.translateService.instant('AG_GRID.COPY'),
1115
+ copyWithHeaders: this.translateService.instant('AG_GRID.COPY_WITH_HEADERS'),
1116
+ copyWithGroupHeaders: this.translateService.instant('AG_GRID.COPY_WITH_GROUP_HEADERS'),
1117
+ paste: this.translateService.instant('AG_GRID.PASTE'),
1118
+ export: this.translateService.instant('AG_GRID.EXPORT'),
1119
+ csvExport: this.translateService.instant('AG_GRID.CSV_EXPORT'),
1120
+ excelExport: this.translateService.instant('AG_GRID.EXCEL_EXPORT'),
1121
+ pinColumn: this.translateService.instant('AG_GRID.PIN_COLUMN'),
1122
+ pinLeft: this.translateService.instant('AG_GRID.PIN_LEFT'),
1123
+ pinRight: this.translateService.instant('AG_GRID.PIN_RIGHT'),
1124
+ noPin: this.translateService.instant('AG_GRID.NO_PIN'),
1125
+ sortAscending: this.translateService.instant('AG_GRID.SORT_ASCENDING'),
1126
+ sortDescending: this.translateService.instant('AG_GRID.SORT_DESCENDING'),
1127
+ autosizeThisColumn: this.translateService.instant('AG_GRID.AUTOSIZE_THIS_COLUMN'),
1128
+ autosizeAllColumns: this.translateService.instant('AG_GRID.AUTOSIZE_ALL_COLUMNS'),
1129
+ resetColumns: this.translateService.instant('AG_GRID.RESET_COLUMNS'),
1130
+ expandAll: this.translateService.instant('AG_GRID.EXPAND_ALL'),
1131
+ collapseAll: this.translateService.instant('AG_GRID.COLLAPSE_ALL'),
1132
+ exportToExcel: this.translateService.instant('AG_GRID.EXPORT_TO_EXCEL'),
1133
+ sheetName: this.translateService.instant('AG_GRID.SHEET_NAME'),
1134
+ exportAsExcelTable: this.translateService.instant('AG_GRID.EXPORT_AS_EXCEL_TABLE'),
1135
+ rangeSelectTo: this.translateService.instant('AG_GRID.RANGE_SELECT_TO'),
1136
+ rangeSelectFrom: this.translateService.instant('AG_GRID.RANGE_SELECT_FROM'),
1137
+ rangeSelectCopy: this.translateService.instant('AG_GRID.RANGE_SELECT_COPY'),
1138
+ rangeSelectChart: this.translateService.instant('AG_GRID.RANGE_SELECT_CHART'),
1139
+ pasteAll: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE'),
1140
+ pasteWithoutHeader: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE_WITHOUT_HEADER'),
1141
+ copyAll: this.translateService.instant('AG_GRID.CLIPBOARD_COPY'),
1142
+ cut: this.translateService.instant('AG_GRID.CLIPBOARD_CUT'),
1143
+ // Pagination translations
1144
+ page: this.translateService.instant('AG_GRID.PAGE'),
1145
+ more: this.translateService.instant('AG_GRID.MORE'),
1146
+ to: this.translateService.instant('AG_GRID.TO'),
1147
+ of: this.translateService.instant('AG_GRID.OF'),
1148
+ next: this.translateService.instant('AG_GRID.NEXT'),
1149
+ last: this.translateService.instant('AG_GRID.LAST'),
1150
+ first: this.translateService.instant('AG_GRID.FIRST'),
1151
+ previous: this.translateService.instant('AG_GRID.PREVIOUS'),
1152
+ pageSizeSelectorLabel: this.translateService.instant('AG_GRID.PAGE_SIZE_SELECTOR_LABEL'),
1153
+ // Set Filter
1154
+ selectAll: this.translateService.instant('AG_GRID.SELECT_ALL'),
1155
+ selectAllSearchResults: this.translateService.instant('AG_GRID.SELECT_ALL_SEARCH_RESULTS'),
1156
+ searchOoo: this.translateService.instant('AG_GRID.SEARCH_OOO'),
1157
+ blanks: this.translateService.instant('AG_GRID.BLANKS'),
1158
+ noMatches: this.translateService.instant('AG_GRID.NO_MATCHES'),
1159
+ // Number Filter & Text Filter
1160
+ filterOoo: this.translateService.instant('AG_GRID.FILTER_OOO'),
1161
+ equals: this.translateService.instant('AG_GRID.EQUALS'),
1162
+ notEqual: this.translateService.instant('AG_GRID.NOT_EQUAL'),
1163
+ blank: this.translateService.instant('AG_GRID.BLANK'),
1164
+ notBlank: this.translateService.instant('AG_GRID.NOT_BLANK'),
1165
+ empty: this.translateService.instant('AG_GRID.EMPTY'),
1166
+ // Number Filter
1167
+ lessThan: this.translateService.instant('AG_GRID.LESS_THAN'),
1168
+ greaterThan: this.translateService.instant('AG_GRID.GREATER_THAN'),
1169
+ lessThanOrEqual: this.translateService.instant('AG_GRID.LESS_THAN_OR_EQUAL'),
1170
+ greaterThanOrEqual: this.translateService.instant('AG_GRID.GREATER_THAN_OR_EQUAL'),
1171
+ inRange: this.translateService.instant('AG_GRID.IN_RANGE'),
1172
+ inRangeStart: this.translateService.instant('AG_GRID.IN_RANGE_START'),
1173
+ inRangeEnd: this.translateService.instant('AG_GRID.IN_RANGE_END'),
1174
+ // Text Filter
1175
+ contains: this.translateService.instant('AG_GRID.CONTAINS'),
1176
+ notContains: this.translateService.instant('AG_GRID.NOT_CONTAINS'),
1177
+ startsWith: this.translateService.instant('AG_GRID.STARTS_WITH'),
1178
+ endsWith: this.translateService.instant('AG_GRID.ENDS_WITH'),
1179
+ // Date Filter
1180
+ dateFormatOoo: this.translateService.instant('AG_GRID.DATE_FORMAT_OOO'),
1181
+ // Filter Conditions
1182
+ andCondition: this.translateService.instant('AG_GRID.AND_CONDITION'),
1183
+ orCondition: this.translateService.instant('AG_GRID.OR_CONDITION'),
1184
+ // Filter Buttons
1185
+ applyFilter: this.translateService.instant('AG_GRID.APPLY_FILTER'),
1186
+ resetFilter: this.translateService.instant('AG_GRID.RESET_FILTER'),
1187
+ clearFilter: this.translateService.instant('AG_GRID.CLEAR_FILTER'),
1188
+ cancelFilter: this.translateService.instant('AG_GRID.CANCEL_FILTER'),
1189
+ // Filter Titles
1190
+ textFilter: this.translateService.instant('AG_GRID.TEXT_FILTER'),
1191
+ numberFilter: this.translateService.instant('AG_GRID.NUMBER_FILTER'),
1192
+ dateFilter: this.translateService.instant('AG_GRID.DATE_FILTER'),
1193
+ setFilter: this.translateService.instant('AG_GRID.SET_FILTER'),
1194
+ });
1195
+ }
1196
+ }
1197
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
1198
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, providedIn: 'root' });
1021
1199
  }
1022
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, decorators: [{
1200
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridService, decorators: [{
1023
1201
  type: Injectable,
1024
1202
  args: [{
1025
1203
  providedIn: 'root',
1026
1204
  }]
1027
- }], ctorParameters: () => [{ type: i1$2.HttpClient }, { type: i2$1.EnvironmentProxy }] });
1205
+ }], ctorParameters: () => [] });
1028
1206
 
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
- }
1207
+ class SecurityDto {
1208
+ coid = null;
1209
+ userGUID = null;
1210
+ application = '';
1211
+ formCode = '';
1212
+ }
1213
+
1214
+ class SysfunctionProxy {
1215
+ http;
1216
+ environmentProxy;
1217
+ constructor(http, environmentProxy) {
1218
+ this.http = http;
1219
+ this.environmentProxy = environmentProxy;
1090
1220
  }
1091
- /** Refresh the display
1221
+ /** Get the authentication list for the given form
1092
1222
  *
1093
- * @param params
1223
+ * @param formCode
1094
1224
  * @returns
1095
1225
  */
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
- }
1226
+ getAuthentication(formCode) {
1227
+ let sysFunctionsURL = this.environmentProxy.getAdminLink('getAuthentication');
1228
+ let securityDto = new SecurityDto();
1229
+ securityDto.formCode = formCode;
1230
+ securityDto.application = this.environmentProxy.getApplicationName();
1231
+ let call$ = this.http.post(sysFunctionsURL, securityDto);
1232
+ return call$.pipe(map((result) => result), catchError$1((error) => {
1233
+ let errorMessage = error.message; //.error.title;
1234
+ return throwError(() => new Error(errorMessage ?? ''));
1235
+ }));
1118
1236
  }
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 }] });
1237
+ 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 });
1238
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, providedIn: 'root' });
1121
1239
  }
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
- }] });
1240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: SysfunctionProxy, decorators: [{
1241
+ type: Injectable,
1242
+ args: [{
1243
+ providedIn: 'root',
1244
+ }]
1245
+ }], ctorParameters: () => [{ type: i1$3.HttpClient }, { type: i2$1.EnvironmentProxy }] });
1126
1246
 
1127
- class CheckboxRenderer {
1128
- params = null;
1129
- label = '';
1130
- type = '';
1131
- supportClick = false;
1132
- checked = null;
1133
- agInit(params) {
1134
- this.onProcess(params);
1247
+ class NettyAgGridBase extends NettyAppsBase {
1248
+ FILTER_MODE_KEY = 'nettyapps_filter_mode';
1249
+ // AgGrid Dark Mode Row Style
1250
+ myTheme = themeQuartz.withParams({
1251
+ backgroundColor: 'black',
1252
+ browserColorScheme: 'dark',
1253
+ }, 'dark');
1254
+ // ********************************************
1255
+ // *** INPUTS ***
1256
+ // ********************************************
1257
+ readOnly = signal(true, ...(ngDevMode ? [{ debugName: "readOnly" }] : [])); // Is the form in readonly mode
1258
+ popupFilterValid = input(false, ...(ngDevMode ? [{ debugName: "popupFilterValid" }] : [])); // Is the popup filter valid
1259
+ popupValid = input(false, ...(ngDevMode ? [{ debugName: "popupValid" }] : [])); // Is the form in popup mode
1260
+ isEmbedded = input(false, ...(ngDevMode ? [{ debugName: "isEmbedded" }] : [])); // Is the form embedded to an other component
1261
+ // Parameters passed when the component is embeded into an other
1262
+ componantParameterGUID = input('', ...(ngDevMode ? [{ debugName: "componantParameterGUID" }] : [])); // GUID of the parameter
1263
+ componantParameterType = input('', ...(ngDevMode ? [{ debugName: "componantParameterType" }] : [])); // Type of the parameter (Field Name)
1264
+ // ********************************************
1265
+ // *** EVENTS ***
1266
+ // ********************************************
1267
+ /*
1268
+ Selected records event
1269
+ @param records: Array of selected records
1270
+ */
1271
+ onElementSelect = output(); // Emit selected records when updated
1272
+ selectedElement = output(); // Selected element in popup mode
1273
+ // Component identifiers
1274
+ componentName = signal('Invalid', ...(ngDevMode ? [{ debugName: "componentName" }] : []));
1275
+ searchValueName = signal('Invalid_searchValue', ...(ngDevMode ? [{ debugName: "searchValueName" }] : []));
1276
+ preferenceType = signal('Invalid_columnState', ...(ngDevMode ? [{ debugName: "preferenceType" }] : []));
1277
+ searchValue = signal('', ...(ngDevMode ? [{ debugName: "searchValue" }] : []));
1278
+ // Query Parameters can be provide as parameters
1279
+ parameterGUID = signal('', ...(ngDevMode ? [{ debugName: "parameterGUID" }] : []));
1280
+ parameterType = signal('', ...(ngDevMode ? [{ debugName: "parameterType" }] : []));
1281
+ // Services
1282
+ nettyAgGridService = inject(NettyAgGridService);
1283
+ commonService = inject(CommonService);
1284
+ sysFunctionProxy = inject(SysfunctionProxy);
1285
+ environment = inject(EnvironmentProxy);
1286
+ // Button action management variables
1287
+ menuValid = signal(true, ...(ngDevMode ? [{ debugName: "menuValid" }] : [])); // true: Filter editbox is not visible so the menus are visible
1288
+ refreshButtonValid = signal(false, ...(ngDevMode ? [{ debugName: "refreshButtonValid" }] : [])); // true: Refresh button is enabled
1289
+ // Authentication
1290
+ authenticationList = [];
1291
+ // User access writes
1292
+ accessRightsProcessed = signal(false, ...(ngDevMode ? [{ debugName: "accessRightsProcessed" }] : []));
1293
+ allowAdd = signal(false, ...(ngDevMode ? [{ debugName: "allowAdd" }] : []));
1294
+ allowEdit = signal(false, ...(ngDevMode ? [{ debugName: "allowEdit" }] : []));
1295
+ allowDelete = signal(false, ...(ngDevMode ? [{ debugName: "allowDelete" }] : []));
1296
+ allowLog = signal(false, ...(ngDevMode ? [{ debugName: "allowLog" }] : []));
1297
+ allowRead = signal(true, ...(ngDevMode ? [{ debugName: "allowRead" }] : []));
1298
+ // ---------------------------------------------------
1299
+ // --- RECORD LIST ---
1300
+ // ---------------------------------------------------
1301
+ recordList = signal([], ...(ngDevMode ? [{ debugName: "recordList" }] : []));
1302
+ record = null;
1303
+ // ***************************************************************
1304
+ // *** METHODS For optional overide ***
1305
+ // ***************************************************************
1306
+ async AfterOnInit() { }
1307
+ setFilter() { } //override this to set a filter
1308
+ // ***************************************************************
1309
+ // *** METHODS ***
1310
+ // ***************************************************************
1311
+ popupClose() { this.selectedElement.emit(null); }
1312
+ onFilterTextBoxVisibilityChange(isOpen) {
1313
+ this.menuValid.set(!isOpen);
1135
1314
  }
1136
- refresh(params) {
1137
- if (params != null) {
1138
- this.onProcess(params);
1315
+ /**
1316
+ * Handle back button click
1317
+ */
1318
+ backClicked() {
1319
+ this.commonService.goBack();
1320
+ }
1321
+ async refreshData() {
1322
+ try {
1323
+ this.loadData();
1324
+ await this.alertService.showAlert('@dataRefreshedSuccessfully');
1325
+ }
1326
+ catch (err) {
1327
+ this.alertService.showError(err);
1139
1328
  }
1140
- return true;
1141
1329
  }
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;
1330
+ /** Set data into the grid */
1331
+ setData(data) {
1332
+ this.recordList.set(data);
1333
+ if (this.columnDefs() == null || this.columnDefs().length == 0) {
1334
+ this.initAgGrid();
1335
+ }
1336
+ if (this.searchValue() && this.gridApi) {
1337
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1338
+ if (this.recordList == undefined || this.recordList.length == 0) {
1339
+ if (this.isEmbedded()) {
1340
+ this.alertService.showWarning('@recordNotFoundSearch');
1341
+ }
1150
1342
  }
1151
1343
  }
1152
1344
  }
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);
1345
+ async setAccessRights() {
1346
+ this.authenticationList = await lastValueFrom(this.sysFunctionProxy.getAuthentication(this.componentName())).catch((e) => {
1347
+ return throwError(() => new Error(e));
1348
+ });
1349
+ try {
1350
+ this.allowRead.set(this.authenticationList.find((f) => f.action == 'read')?.allow ?? false);
1351
+ if (this.allowRead() == false) {
1352
+ this.commonService.userNotAllowedToRead();
1353
+ return false;
1354
+ }
1355
+ this.allowAdd.set(false);
1356
+ this.allowEdit.set(false);
1357
+ this.allowDelete.set(false);
1358
+ this.allowLog.set(false);
1359
+ }
1360
+ catch (error) {
1361
+ this.allowAdd.set(false);
1362
+ this.allowEdit.set(false);
1363
+ this.allowDelete.set(false);
1364
+ this.allowLog.set(false);
1365
+ return false;
1165
1366
  }
1367
+ this.accessRightsProcessed.set(true);
1368
+ return true;
1166
1369
  }
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
1370
  /**
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;
1371
+ * Get stored filter mode from local storage
1372
+ * @returns boolean
1373
+ */
1374
+ getStoredFilterMode() {
1375
+ try {
1376
+ const stored = localStorage.getItem(this.FILTER_MODE_KEY);
1377
+ return stored !== null ? JSON.parse(stored) : true;
1196
1378
  }
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;
1379
+ catch {
1380
+ return true;
1201
1381
  }
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);
1382
+ }
1383
+ // *********************************************************
1384
+ // *** AG Grid Management ***
1385
+ // *********************************************************
1386
+ // Component inputs
1387
+ agGridSelectionMode = input('multiRow', ...(ngDevMode ? [{ debugName: "agGridSelectionMode" }] : []));
1388
+ // AG-Grid theme setting (dark mode)
1389
+ theme = this.myTheme;
1390
+ // Grid references
1391
+ gridApi;
1392
+ userGridApi;
1393
+ excelStyles = null;
1394
+ // Column definitions
1395
+ columnDefs = signal(null, ...(ngDevMode ? [{ debugName: "columnDefs" }] : []));
1396
+ userColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "userColumnDefs" }] : []));
1397
+ groupMembersColumnDefs = signal(null, ...(ngDevMode ? [{ debugName: "groupMembersColumnDefs" }] : []));
1398
+ gridColumnsVisible = signal(true, ...(ngDevMode ? [{ debugName: "gridColumnsVisible" }] : []));
1399
+ gridExpanded = signal(false, ...(ngDevMode ? [{ debugName: "gridExpanded" }] : []));
1400
+ // Framework components
1401
+ frameworkComponents = null;
1402
+ // Selection management
1403
+ selectedRows = signal([], ...(ngDevMode ? [{ debugName: "selectedRows" }] : [])); // Selected rows in the grid
1404
+ isSingleRowSelected = computed(() => this.selectedRows().length === 1, ...(ngDevMode ? [{ debugName: "isSingleRowSelected" }] : [])); // True if only one row is selected
1405
+ isMultipleRowSelected = computed(() => this.selectedRows().length > 0, ...(ngDevMode ? [{ debugName: "isMultipleRowSelected" }] : [])); // True if multiple rows are selected
1406
+ // Services
1407
+ // AG Grid Filter
1408
+ customFilters = signal(this.getStoredFilterMode(), ...(ngDevMode ? [{ debugName: "customFilters" }] : []));
1409
+ // ---------------------------------------------
1410
+ // --- AG Grid Configuration ---
1411
+ // ---------------------------------------------
1412
+ // Grid configuration options
1413
+ gridOptions = {
1414
+ rowSelection: {
1415
+ mode: this.agGridSelectionMode(), checkboxes: true, headerCheckbox: true,
1416
+ selectAll: 'filtered', hideDisabledCheckboxes: true, suppressRowClickSelection: false,
1417
+ enableCellChangeFlash: true,
1418
+ },
1419
+ };
1420
+ // Statusbar
1421
+ statusBar = {
1422
+ statusPanels: [
1423
+ { statusPanel: 'agTotalRowCountComponent', align: 'left', key: 'rowCount' },
1424
+ { statusPanel: 'agFilteredRowCountComponent' },
1425
+ { statusPanel: 'agSelectedRowCountComponent' },
1426
+ { statusPanel: 'agAggregationComponent' },
1427
+ ],
1428
+ };
1429
+ // ---------------------------------------------
1430
+ // --- AG Grid Functions ---
1431
+ // ---------------------------------------------
1432
+ // Common grid ready handler
1433
+ onGridReady(params) {
1434
+ this.gridApi = params.api;
1435
+ this.setAgGridTranslations();
1436
+ this.gridApi.addEventListener('selectionChanged', () => {
1437
+ // Null-safe approach
1438
+ const selectedNodes = this.gridApi?.getSelectedNodes?.() || [];
1439
+ this.selectedRows.set(selectedNodes.map((node) => node.data));
1440
+ });
1441
+ if (this.searchValue()) {
1442
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1208
1443
  }
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
1444
  }
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;
1445
+ onFirstDataRendered(params) {
1446
+ //TODO: Fix this
1447
+ try {
1448
+ this.nettyAgGridService.loadGridUserPreference(this.preferenceType(), this.gridApi);
1449
+ this.expandCollapse();
1225
1450
  }
1226
- if (fileName == null) {
1227
- return;
1451
+ catch (error) {
1452
+ console.log('OnFirstDataRendered error:', error);
1228
1453
  }
1229
- let _data = base64EncodedFileData;
1230
- const prefix = 'data:';
1231
- if (_data.startsWith(prefix)) {
1232
- // Remove the prefix
1233
- _data = _data.slice(_data.indexOf(',') + 1);
1454
+ }
1455
+ // Save the user parameters
1456
+ saveGrid(params) {
1457
+ const gridState = {
1458
+ columnState: this.gridApi.getColumnState(),
1459
+ };
1460
+ this.nettyAgGridService.saveGridUserPreference(this.preferenceType(), this.gridApi, JSON.stringify(gridState));
1461
+ }
1462
+ // Grid utilities
1463
+ expandCollapse() {
1464
+ this.gridExpanded.set(this.nettyAgGridService.expandCollapseGrid(this.gridApi, this.gridExpanded()));
1465
+ }
1466
+ quickSearch(searchStr = '') {
1467
+ this.searchValue.set(searchStr);
1468
+ if (this.gridApi) {
1469
+ this.gridApi.setGridOption('quickFilterText', this.searchValue());
1234
1470
  }
1235
- // Convert the base64 data to a Uint8Array
1236
- const textData = Buffer.from(_data ?? '', 'base64').toString();
1237
- this.downloadTextFileNotEncoded(textData, fileName);
1471
+ sessionStorage.setItem(this.searchValueName(), this.searchValue());
1238
1472
  }
1239
- /** Save the given text as a text file
1240
- *
1241
- * @param fileData
1242
- * @param fileName
1473
+ /**
1474
+ * Update a single row in the grid
1475
+ * @param rowData The updated row data
1476
+ * @param idField The field name that serves as unique identifier (default: 'id')
1243
1477
  */
1244
- downloadTextFileNotEncoded(fileData, fileName) {
1245
- if (fileData == null) {
1246
- return;
1247
- }
1248
- if (fileName == null) {
1249
- return;
1250
- }
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);
1478
+ updateRowInGrid(rowData, idField = 'id') {
1479
+ const rowNode = this.gridApi.getRowNode(rowData[idField]);
1480
+ if (rowNode) {
1481
+ rowNode.setData(rowData);
1482
+ const params = { rowNodes: [rowNode], force: true, suppressFlash: false, };
1483
+ this.gridApi.refreshCells(params);
1484
+ }
1485
+ else {
1486
+ this.loadData(); // Reload all data if row not found
1487
+ }
1265
1488
  }
1266
1489
  /**
1267
- * Download file where the data is provided as blob
1268
- * @param data - Array Buffer data
1269
- * @param type - type of the document.
1490
+ * Filter mode change
1270
1491
  */
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);
1492
+ toggleFilterMode() {
1493
+ const newMode = !this.customFilters();
1494
+ this.customFilters.set(newMode);
1495
+ localStorage.setItem(this.FILTER_MODE_KEY, JSON.stringify(newMode));
1496
+ this.initAgGrid();
1497
+ if (this.gridApi) {
1498
+ this.gridApi.refreshHeader();
1499
+ this.gridApi.setFilterModel(null);
1500
+ const message = this.customFilters()
1501
+ ? '@customFilterModeEnabled'
1502
+ : '@defaultFilterModeEnabled';
1503
+ this.alertService.showAlert(this.translateService.instant(message));
1504
+ }
1279
1505
  }
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();
1506
+ setAgGridTranslations() {
1507
+ this.nettyAgGridService.setAgGridTranslations(this.gridApi);
1289
1508
  }
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
1509
  initAgGrid_extension() {
1396
1510
  if (this.allowEdit() == false && (this.popupValid() ?? false) == false) {
1397
1511
  this.columnDefs().pop();
1398
1512
  this.columnDefs().shift();
1399
1513
  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',
1514
+ headerName: '', headerCheckboxSelection: true, sortable: true, resizable: true,
1515
+ filter: true, minWidth: 60, maxWidth: 60, suppressSizeToFit: true, colId: 'editColumn',
1409
1516
  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,
1517
+ cellRendererParams: { label: '1', type: 'edit' },
1419
1518
  });
1519
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true });
1420
1520
  }
1421
1521
  if (this.popupValid() == true) {
1422
1522
  this.columnDefs().pop();
@@ -1424,155 +1524,301 @@ class NettyAgGridBase extends NettyAppsBase {
1424
1524
  if (this.popupFilterValid() == true) {
1425
1525
  if (this.allowEdit()) {
1426
1526
  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',
1527
+ headerName: '', sortable: false, resizable: false, filter: false,
1528
+ minWidth: 50, maxWidth: 50, suppressSizeToFit: true, cellRenderer: 'buttonRenderer',
1435
1529
  cellRendererParams: {
1436
1530
  onClick: this.onBtnClick?.bind(this),
1437
1531
  label: this.translateService.instant('@Update'),
1438
1532
  type: 'popupEdit',
1439
1533
  },
1440
1534
  });
1441
- this.gridApi.setGridOption('rowSelection', {
1442
- mode: 'multiRow',
1443
- checkboxes: true,
1444
- });
1535
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true, });
1445
1536
  }
1446
1537
  else {
1447
1538
  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,
1539
+ headerName: '', sortable: false, resizable: false, filter: false,
1540
+ minWidth: 50, maxWidth: 50, suppressSizeToFit: true, cellStyle: { 'padding-top': '5px' }
1460
1541
  });
1542
+ this.gridApi.setGridOption('rowSelection', { mode: 'multiRow', checkboxes: true });
1461
1543
  }
1462
1544
  }
1463
1545
  else {
1464
1546
  if (this.allowEdit() == false) {
1465
1547
  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',
1548
+ headerName: '', sortable: false, resizable: false, filter: false, minWidth: 50,
1549
+ maxWidth: 50, suppressSizeToFit: true, cellRenderer: 'buttonRenderer',
1474
1550
  cellRendererParams: {
1475
1551
  onClick: this.onBtnClick?.bind(this),
1476
1552
  label: this.translateService.instant('@Update'),
1477
1553
  type: 'popupEdit',
1478
1554
  },
1479
1555
  });
1480
- this.gridApi.setGridOption('rowSelection', {
1481
- mode: 'singleRow',
1482
- checkboxes: false,
1483
- });
1556
+ this.gridApi.setGridOption('rowSelection', { mode: 'singleRow', checkboxes: false });
1484
1557
  }
1485
1558
  if (!this.readOnly()) {
1486
1559
  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' },
1560
+ headerName: this.translateService.instant('@select'), sortable: false, resizable: false,
1561
+ filter: false, minWidth: 80, maxWidth: 80, suppressSizeToFit: true,
1562
+ cellRenderer: 'buttonRenderer', cellStyle: { 'margin-top': '8px' },
1496
1563
  cellRendererParams: {
1497
1564
  onClick: this.onBtnClick?.bind(this),
1498
1565
  label: this.translateService.instant('@select'),
1499
1566
  type: 'popupSelect',
1500
1567
  },
1501
1568
  });
1502
- this.gridApi.setGridOption('rowSelection', {
1503
- mode: 'singleRow',
1504
- checkboxes: false,
1505
- });
1569
+ this.gridApi.setGridOption('rowSelection', { mode: 'singleRow', checkboxes: false });
1506
1570
  }
1507
1571
  }
1508
1572
  }
1509
1573
  }
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
1537
- */
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));
1574
+ // ---------------------------------------------
1575
+ // --- Functions to Show / Hide Grid Columns ---
1576
+ // ---------------------------------------------
1577
+ onShowHideColumns() {
1578
+ this.gridColumnsVisible.update((a) => !a);
1579
+ this.showHideColumnsAsync();
1580
+ }
1581
+ showHideColumnsAsync() {
1582
+ setTimeout(() => this.showHideColumns(), 400);
1583
+ }
1584
+ showHideColumns() {
1585
+ var fields = this.columnDefs()
1586
+ .filter((columnDef) => columnDef.ntyHide === 'x')
1587
+ .map((columnDef) => columnDef.field);
1588
+ this.gridApi?.setColumnsVisible(fields, this.gridColumnsVisible());
1589
+ }
1590
+ showHideEmbeddedColumnsAsync() {
1591
+ setTimeout(() => this.showHideEmbeddedColumns(), 100);
1592
+ }
1593
+ showHideEmbeddedColumns() {
1594
+ if (this.columnDefs() == undefined || this.columnDefs() == null) {
1595
+ return;
1596
+ }
1597
+ var fields = this.columnDefs()
1598
+ .filter((columnDef) => columnDef.ntyEmbeddedHide == 'x')
1599
+ .map((columnDef) => columnDef.field);
1600
+ this.gridApi?.setColumnsVisible(fields, !this.isEmbedded());
1601
+ }
1602
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
1603
+ 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 }, componantParameterGUID: { classPropertyName: "componantParameterGUID", publicName: "componantParameterGUID", isSignal: true, isRequired: false, transformFunction: null }, componantParameterType: { classPropertyName: "componantParameterType", publicName: "componantParameterType", isSignal: true, isRequired: false, transformFunction: null }, agGridSelectionMode: { classPropertyName: "agGridSelectionMode", publicName: "agGridSelectionMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onElementSelect: "onElementSelect", selectedElement: "selectedElement" }, host: { attributes: { "ntybase-id": "NettyAgGridBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
1604
+ }
1605
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, decorators: [{
1606
+ type: Component,
1607
+ args: [{ selector: 'ntybase-ag-grid-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridBase' } }]
1608
+ }], 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 }] }], 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"] }], agGridSelectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "agGridSelectionMode", required: false }] }] } });
1609
+
1610
+ class ButtonRenderer {
1611
+ params = null;
1612
+ label = '';
1613
+ type = '';
1614
+ toggleValue = null;
1615
+ editValid = false;
1616
+ historyValid = false;
1617
+ lineValid = false;
1618
+ popupSelectValid = false;
1619
+ popupEditValid = false;
1620
+ toggleValid = false;
1621
+ toggle_icon = '';
1622
+ none = false;
1623
+ addValid = false;
1624
+ deleteValid = false;
1625
+ agInit(params) {
1626
+ this.params = params;
1627
+ this.type = this.params.type || null;
1628
+ this.label = this.params.label || null;
1629
+ this.toggleValue = this.params.value || null;
1630
+ switch (this.toggleValue) {
1631
+ case true:
1632
+ this.toggle_icon = 'select_check_box';
1633
+ break;
1634
+ case false:
1635
+ this.toggle_icon = 'check_box_outline_blank';
1636
+ break;
1637
+ default:
1638
+ this.toggle_icon = '';
1639
+ break;
1640
+ }
1641
+ this.resetValids();
1642
+ switch (this.type.toLowerCase().trim()) {
1643
+ case 'edit':
1644
+ this.editValid = true;
1645
+ break;
1646
+ case 'log':
1647
+ this.historyValid = true;
1648
+ break;
1649
+ case 'line':
1650
+ this.lineValid = true;
1651
+ break;
1652
+ case 'popupselect':
1653
+ this.popupSelectValid = true;
1654
+ break;
1655
+ case 'toggle':
1656
+ this.toggleValid = true;
1657
+ break;
1658
+ case 'none':
1659
+ this.none = true;
1660
+ break;
1661
+ case 'add':
1662
+ this.addValid = true;
1663
+ break;
1664
+ case 'delete':
1665
+ this.deleteValid = true;
1666
+ break;
1667
+ default:
1668
+ this.popupEditValid = true;
1669
+ break;
1670
+ }
1671
+ }
1672
+ /** Refresh the display
1673
+ *
1674
+ * @param params
1675
+ * @returns
1676
+ */
1677
+ refresh(params) {
1678
+ return false;
1679
+ }
1680
+ resetValids() {
1681
+ this.editValid = false;
1682
+ this.historyValid = false;
1683
+ this.lineValid = false;
1684
+ this.popupSelectValid = false;
1685
+ this.popupEditValid = false;
1686
+ this.toggleValid = false;
1687
+ }
1688
+ onClick(event) {
1689
+ if (this.params.onClick instanceof Function) {
1690
+ // put anything into params u want pass into parents component
1691
+ const params = {
1692
+ event: event,
1693
+ rowData: this.params.node.data,
1694
+ type: this.type,
1695
+ // ...something
1696
+ };
1697
+ this.params.onClick(params);
1698
+ }
1699
+ }
1700
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1701
+ 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 }] });
1702
+ }
1703
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonRenderer, decorators: [{
1704
+ type: Component,
1705
+ 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"] }]
1706
+ }] });
1707
+
1708
+ class CheckboxRenderer {
1709
+ params = null;
1710
+ label = '';
1711
+ type = '';
1712
+ supportClick = false;
1713
+ checked = null;
1714
+ agInit(params) {
1715
+ this.onProcess(params);
1716
+ }
1717
+ refresh(params) {
1718
+ if (params != null) {
1719
+ this.onProcess(params);
1720
+ }
1721
+ return true;
1722
+ }
1723
+ onProcess(params) {
1724
+ this.params = params;
1725
+ this.checked = this.params.value ?? false;
1726
+ this.type = this.params.type || null;
1727
+ this.label = this.params.label || null;
1728
+ if (this.type != null) {
1729
+ if (this.type.toLowerCase().trim() == 'click') {
1730
+ this.supportClick = true;
1731
+ }
1550
1732
  }
1551
1733
  }
1552
- getStoredFilterMode() {
1553
- try {
1554
- const stored = localStorage.getItem(FILTER_MODE_KEY);
1555
- return stored !== null ? JSON.parse(stored) : true;
1734
+ onClick(event) {
1735
+ this.checked = !this.checked;
1736
+ if (this.params.onClick instanceof Function) {
1737
+ // put anything into params u want pass into parents component
1738
+ const params = {
1739
+ event: event,
1740
+ rowData: this.params.node.data,
1741
+ type: this.type,
1742
+ checked: this.checked,
1743
+ // ...something
1744
+ };
1745
+ this.params.onClick(params);
1556
1746
  }
1557
- catch {
1558
- return true;
1747
+ }
1748
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, deps: [], target: i0.ɵɵFactoryTarget.Component });
1749
+ 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: [""] });
1750
+ }
1751
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: CheckboxRenderer, decorators: [{
1752
+ type: Component,
1753
+ 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" }]
1754
+ }] });
1755
+
1756
+ ModuleRegistry.registerModules([AllCommunityModule, StatusBarModule, ClientSideRowModelModule, ClipboardModule, ExcelExportModule, ColumnMenuModule,
1757
+ ContextMenuModule, CellSelectionModule, HighlightChangesModule, RowSelectionModule,]);
1758
+ // AgGrid Dark Mode Row Style
1759
+ class NettyAgGridListBase extends NettyAgGridBase {
1760
+ // ********************************************
1761
+ // *** INPUTS ***
1762
+ // ********************************************
1763
+ // Filter section
1764
+ hasFilter = input(false, ...(ngDevMode ? [{ debugName: "hasFilter" }] : [])); // Does the component have a filter
1765
+ isFilterValid = signal(true, ...(ngDevMode ? [{ debugName: "isFilterValid" }] : [])); // Can the filter be used
1766
+ isFilterExpanded = linkedSignal({ ...(ngDevMode ? { debugName: "isFilterExpanded" } : {}), source: () => ({
1767
+ embedded: this.isEmbedded(),
1768
+ hasFilter: this.hasFilter(),
1769
+ valid: this.isFilterValid(),
1770
+ }),
1771
+ computation: (s) => {
1772
+ if (s.embedded || !s.hasFilter)
1773
+ return false;
1774
+ return s.valid;
1775
+ } });
1776
+ filterRefreshTrigger = signal(0, ...(ngDevMode ? [{ debugName: "filterRefreshTrigger" }] : []));
1777
+ /**
1778
+ * Triggers the filter component to refresh its data
1779
+ */
1780
+ refreshFilterData() {
1781
+ let value = this.filterRefreshTrigger();
1782
+ if (value > 10000) {
1783
+ value = 0;
1559
1784
  }
1785
+ value++;
1786
+ this.filterRefreshTrigger.set(value);
1560
1787
  }
1788
+ // Open component management
1789
+ openEditComponentInPopup = signal(false, ...(ngDevMode ? [{ debugName: "openEditComponentInPopup" }] : []));
1790
+ // Services
1791
+ router = inject(Router);
1792
+ routerActive = inject(ActivatedRoute);
1793
+ dialog = inject(MatDialog);
1794
+ // Parse query parameters
1795
+ queryParameterGUID = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('parameters')), map((value) => this.parseOrReturnValue(value))), {
1796
+ initialValue: null, // set initial value to null
1797
+ });
1798
+ queryParameterType = toSignal(this.routerActive.queryParamMap.pipe(map((params) => params.get('type')), map((value) => this.parseOrReturnValue(value))), {
1799
+ initialValue: null, // set initial value to null
1800
+ });
1801
+ openInPopup = signal(false, ...(ngDevMode ? [{ debugName: "openInPopup" }] : [])); // true: Open add / edit component in popup
1802
+ // ---------------------------------------------------
1803
+ // --- RECORD LIST ---
1804
+ // ---------------------------------------------------
1805
+ nettyAppsProxy = injectNettyStandardProxy(this.componentName());
1561
1806
  /**
1562
1807
  * Component initialization lifecycle hook
1563
1808
  */
1564
1809
  async ngOnInit() {
1810
+ this.nettyAppsProxy = injectNettyStandardProxy(this.componentName());
1565
1811
  await this.setAccessRights();
1566
1812
  const savedSearchValue = sessionStorage.getItem(this.searchValueName());
1567
1813
  if (savedSearchValue) {
1568
1814
  this.searchValue.set(savedSearchValue);
1569
- this.loadData(savedSearchValue);
1570
1815
  }
1571
- else {
1816
+ if (!this.hasFilter()) {
1572
1817
  this.loadData();
1573
1818
  }
1574
1819
  // Load user grid preferences
1575
1820
  await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
1821
+ await this.AfterOnInit();
1576
1822
  }
1577
1823
  parseOrReturnValue(value) {
1578
1824
  if (value) {
@@ -1585,53 +1831,6 @@ class NettyAgGridBase extends NettyAppsBase {
1585
1831
  }
1586
1832
  return null;
1587
1833
  }
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
- /**
1630
- * Handle back button click
1631
- */
1632
- backClicked() {
1633
- this.commonService.goBack();
1634
- }
1635
1834
  gotoURL(routePrefix, rightSidenav = [], parameters, type, dialogComponent = null, isNewTab = false, isPopup = this.isEmbedded()) {
1636
1835
  const baseHref = this.environment.getBaseHref().endsWith('/')
1637
1836
  ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
@@ -1705,8 +1904,8 @@ class NettyAgGridBase extends NettyAppsBase {
1705
1904
  ]);
1706
1905
  }
1707
1906
  toggleOpenMode() {
1708
- const newMode = !this.openInPopup();
1709
- this.openInPopup.set(newMode);
1907
+ const newMode = !this.openEditComponentInPopup();
1908
+ this.openEditComponentInPopup.set(newMode);
1710
1909
  localStorage.setItem('openInPopup', JSON.stringify(newMode));
1711
1910
  const message = newMode ? '@openInPopup' : '@openInSidenav';
1712
1911
  this.alertService.showSuccess(message);
@@ -1727,7 +1926,7 @@ class NettyAgGridBase extends NettyAppsBase {
1727
1926
  };
1728
1927
  const savedMode = localStorage.getItem('openInPopup');
1729
1928
  if (savedMode !== null) {
1730
- this.openInPopup.set(JSON.parse(savedMode) === true);
1929
+ this.openEditComponentInPopup.set(JSON.parse(savedMode) === true);
1731
1930
  }
1732
1931
  this.translateService.onLangChange.subscribe(() => {
1733
1932
  this.setAgGridTranslations();
@@ -1746,6 +1945,7 @@ class NettyAgGridBase extends NettyAppsBase {
1746
1945
  this.parameterType.set(this.queryParameterType());
1747
1946
  }
1748
1947
  if (this.hasValidValue(this.parameterGUID)) {
1948
+ this.isFilterValid.set(false);
1749
1949
  this.setFilter();
1750
1950
  this.loadData();
1751
1951
  }
@@ -1764,157 +1964,47 @@ class NettyAgGridBase extends NettyAppsBase {
1764
1964
  case 'update':
1765
1965
  this.updateRowInGrid(update.data);
1766
1966
  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
- }
1967
+ }
1968
+ }
1969
+ });
1970
+ effect(() => { this.onElementSelect.emit(this.selectedRows()); });
1971
+ // Manage filter expanded state
1972
+ effect(() => {
1973
+ this.isEmbedded();
1974
+ this.showHideEmbeddedColumnsAsync();
1975
+ });
1976
+ }
1977
+ onReverseIsFilterValid() {
1978
+ this.isFilterValid.update((a) => !a);
1898
1979
  }
1899
1980
  /**
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')
1981
+ * Validates if the given value is equal to null,undefined or ''
1982
+ * @param value
1983
+ * @returns true if has a valid value
1903
1984
  */
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);
1985
+ hasValidValue(value) {
1986
+ if (value == null || value == undefined) {
1987
+ return false;
1914
1988
  }
1915
- else {
1916
- this.loadData(); // Reload all data if row not found
1989
+ if (value == '') {
1990
+ return false;
1991
+ }
1992
+ return true;
1993
+ }
1994
+ // *********************************************************
1995
+ // *** Data Management Functions ***
1996
+ // *********************************************************
1997
+ loadData() {
1998
+ if (this.hasFilter()) {
1999
+ this.setData([]);
2000
+ return;
1917
2001
  }
2002
+ this.nettyAppsProxy.select(this.record).subscribe({
2003
+ next: (data) => {
2004
+ this.setData(data);
2005
+ },
2006
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
2007
+ });
1918
2008
  }
1919
2009
  async deleteSelected() {
1920
2010
  if (!this.gridApi)
@@ -1927,96 +2017,61 @@ class NettyAgGridBase extends NettyAppsBase {
1927
2017
  const confirmed = await this.alertService.showConfirm('@confirmDeleteSelectedRecords');
1928
2018
  if (confirmed) {
1929
2019
  const selectedRows = selectedNodes.map((node) => node.data);
1930
- this.deleteRows?.(selectedRows);
1931
- }
1932
- }
1933
- async refreshData() {
1934
- try {
1935
- this.loadData();
1936
- await this.alertService.showAlert('@dataRefreshedSuccessfully');
1937
- }
1938
- catch (err) {
1939
- this.alertService.showError(err);
2020
+ this.deleteRows(selectedRows);
1940
2021
  }
1941
2022
  }
1942
- async setAccessRights() {
1943
- this.authenticationList = await lastValueFrom(this.sysFunctionProxy.getAuthentication(this.componentName())).catch((e) => {
1944
- return throwError(() => new Error(e));
2023
+ deleteRows(rows) {
2024
+ this.nettyAppsProxy.deleteList(rows).subscribe({
2025
+ next: () => {
2026
+ this.gridApi.applyTransaction({ remove: rows });
2027
+ this.alertService.showSuccess('@recordDeletedSuccessfully');
2028
+ },
2029
+ error: (err) => this.alertService.showError(err),
1945
2030
  });
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
2031
  }
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
- }
2004
- showHideEmbeddedColumns() {
2005
- if (this.columnDefs() == undefined || this.columnDefs() == null) {
2006
- return;
2032
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridListBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2033
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAgGridListBase, isStandalone: true, selector: "ntybase-ag-grid-list-base", inputs: { hasFilter: { classPropertyName: "hasFilter", publicName: "hasFilter", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ntybase-id": "NettyAgGridListBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2034
+ }
2035
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridListBase, decorators: [{
2036
+ type: Component,
2037
+ args: [{ selector: 'ntybase-ag-grid-list-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridListBase' } }]
2038
+ }], ctorParameters: () => [], propDecorators: { hasFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasFilter", required: false }] }] } });
2039
+
2040
+ class NettyAgGridLogBase extends NettyAgGridBase {
2041
+ // ---------------------------------------------------
2042
+ // --- RECORD LIST ---
2043
+ // ---------------------------------------------------
2044
+ nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
2045
+ /**
2046
+ * Component initialization lifecycle hook
2047
+ */
2048
+ async ngOnInit() {
2049
+ this.nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
2050
+ await this.setAccessRights();
2051
+ const savedSearchValue = sessionStorage.getItem(this.searchValueName());
2052
+ if (savedSearchValue) {
2053
+ this.searchValue.set(savedSearchValue);
2007
2054
  }
2008
- var fields = this.columnDefs()
2009
- .filter((columnDef) => columnDef.ntyEmbeddedHide == 'x')
2010
- .map((columnDef) => columnDef.field);
2011
- this.gridApi?.setColumnsVisible(fields, !this.isEmbedded());
2055
+ this.loadData();
2056
+ // Load user grid preferences
2057
+ await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
2058
+ await this.AfterOnInit();
2012
2059
  }
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: [""] });
2060
+ loadData() {
2061
+ this.nettyAppsProxy.selectLog(this.record).subscribe({
2062
+ next: (data) => {
2063
+ this.setData(data);
2064
+ },
2065
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
2066
+ });
2067
+ }
2068
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridLogBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2069
+ 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
2070
  }
2016
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridBase, decorators: [{
2071
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridLogBase, decorators: [{
2017
2072
  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"] }] } });
2073
+ args: [{ selector: 'ntybase-ag-grid-log-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridLogBase' } }]
2074
+ }] });
2020
2075
 
2021
2076
  class NettyAgGridSaveBase extends NettyAppsBase {
2022
2077
  // Services
@@ -2030,6 +2085,11 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2030
2085
  parameters = input('', ...(ngDevMode ? [{ debugName: "parameters" }] : []));
2031
2086
  embedded = input(false, ...(ngDevMode ? [{ debugName: "embedded" }] : []));
2032
2087
  isEmbedded = input(false, ...(ngDevMode ? [{ debugName: "isEmbedded" }] : []));
2088
+ // ---------------------------------------------------
2089
+ // --- RECORD LIST ---
2090
+ // ---------------------------------------------------
2091
+ nettyAppsProxy = injectNettyStandardProxy('');
2092
+ recordType = signal('', ...(ngDevMode ? [{ debugName: "recordType" }] : []));
2033
2093
  currentItem = signal({}, ...(ngDevMode ? [{ debugName: "currentItem" }] : []));
2034
2094
  initialItem = {};
2035
2095
  // Form tracking
@@ -2038,12 +2098,29 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2038
2098
  // Dialog related properties
2039
2099
  dialogRef = inject((MatDialogRef), { optional: true });
2040
2100
  dialogData = inject(MAT_DIALOG_DATA, { optional: true });
2101
+ constructor() {
2102
+ super();
2103
+ effect(() => {
2104
+ this.parameters();
2105
+ this.loadDetailData();
2106
+ });
2107
+ }
2108
+ async ngOnInit() {
2109
+ this.loadDetailData();
2110
+ }
2041
2111
  // Controls the visibility of additional editable fields (e.g., password, extra settings)
2042
2112
  // When true, certain input fields become visible for editing
2043
2113
  updateValid = signal(false, ...(ngDevMode ? [{ debugName: "updateValid" }] : []));
2044
2114
  setUpdateValid(value) {
2045
2115
  this.updateValid.set(value);
2046
2116
  }
2117
+ /**
2118
+ * Initialize parameters. This method is called in ngOnInit or constructor
2119
+ */
2120
+ initParameters(urlPath) {
2121
+ this.nettyAppsProxy = injectNettyStandardProxy(urlPath);
2122
+ this.recordType.set(urlPath);
2123
+ }
2047
2124
  /**
2048
2125
  * Determine view mode based on current route
2049
2126
  */
@@ -2058,9 +2135,6 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2058
2135
  this.viewMode.set('fullscreen');
2059
2136
  }
2060
2137
  }
2061
- ngOnInit() {
2062
- this.loadDetailData();
2063
- }
2064
2138
  /**
2065
2139
  * Set data to the form while preserving any unsaved changes
2066
2140
  * @param item - Data object of type T to populate the form
@@ -2081,8 +2155,9 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2081
2155
  * @param data - Data to populate the new instance
2082
2156
  */
2083
2157
  createItemInstance(data) {
2084
- // Default implementation - child classes can override this
2085
- return { ...data };
2158
+ const instance = this.createNewRecord();
2159
+ Object.assign(instance, data);
2160
+ return instance;
2086
2161
  }
2087
2162
  /**
2088
2163
  * Check for form changes
@@ -2120,11 +2195,6 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2120
2195
  }
2121
2196
  return '';
2122
2197
  }
2123
- ngOnChanges(changes) {
2124
- if (changes['parameters']) {
2125
- this.loadDetailData();
2126
- }
2127
- }
2128
2198
  /**
2129
2199
  * Close sidenav or navigate back
2130
2200
  */
@@ -2178,6 +2248,103 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2178
2248
  }
2179
2249
  return true;
2180
2250
  }
2251
+ /**
2252
+ * Save data to API
2253
+ * Handles both create and update operations based on record existence
2254
+ */
2255
+ saveRecord() {
2256
+ if (!this.validateSaveRecord(this.currentItem().getPK())) {
2257
+ return;
2258
+ }
2259
+ if (this.currentItem().getPK()) {
2260
+ this.updateRecord();
2261
+ return;
2262
+ }
2263
+ this.insertRecord();
2264
+ }
2265
+ /**
2266
+ * Create new record
2267
+ */
2268
+ insertRecord() {
2269
+ const createData = {};
2270
+ const currentItem = this.currentItem();
2271
+ Object.keys(currentItem).forEach((key) => {
2272
+ if (currentItem[key] !== undefined && currentItem[key] !== null && currentItem[key] !== '') {
2273
+ createData[key] = currentItem[key];
2274
+ }
2275
+ });
2276
+ this.nettyAppsProxy.insert(createData).subscribe({
2277
+ next: (newRecord) => {
2278
+ this.initializeFormData(newRecord);
2279
+ this.commonService.notifyUpdate(this.recordType(), 'add', newRecord);
2280
+ this.closeSidenav();
2281
+ this.alertService.showSuccess('@recordCreatedSuccessfully');
2282
+ },
2283
+ error: (err) => console.error('@creationFailed:', err),
2284
+ });
2285
+ }
2286
+ /**
2287
+ * Update record
2288
+ */
2289
+ updateRecord() {
2290
+ const changes = this.initialItem.compare(this.currentItem());
2291
+ const updateData = this.createNewRecord();
2292
+ Object.assign(updateData, changes);
2293
+ updateData.setPK(this.currentItem().getPK());
2294
+ this.nettyAppsProxy.update(updateData).subscribe({
2295
+ next: (updatedRecord) => {
2296
+ this.initializeFormData(updatedRecord);
2297
+ this.commonService.notifyUpdate('Item', 'update', updatedRecord);
2298
+ this.closeSidenav();
2299
+ this.alertService.showSuccess('@recordUpdatedSuccessfully');
2300
+ },
2301
+ error: (err) => this.alertService.showError('@updateFailed', err),
2302
+ });
2303
+ }
2304
+ /**
2305
+ * Load data from API based on GUID
2306
+ * Handles both new record creation and existing record editing
2307
+ * guid - Unique identifier of the record
2308
+ */
2309
+ loadDetailData() {
2310
+ const guid = this.getGuidFromParameters();
2311
+ if (!guid) {
2312
+ // If no GUID provided, initialize a new record
2313
+ const newRecord = this.createNewRecord();
2314
+ this.initializeFormData(newRecord);
2315
+ this.updateValid.set(true);
2316
+ return;
2317
+ }
2318
+ // Fetch existing record from API
2319
+ this.nettyAppsProxy.selectGUID(guid).subscribe({
2320
+ next: (record) => {
2321
+ if (!record || !record.getPK()) {
2322
+ this.alertService.showError('@recordNotFound');
2323
+ const cleanPath = this.commonService.getCleanUrlPath();
2324
+ this.router.navigate([cleanPath]);
2325
+ return;
2326
+ }
2327
+ this.initializeFormData(record);
2328
+ this.alertService.showSuccess('@dataLoadSuccess');
2329
+ // Ensure sidenav is visible when in sidenav mode
2330
+ if (this.viewMode() === 'sidenav') {
2331
+ this.commonService.toggleRightSidenav(true);
2332
+ }
2333
+ },
2334
+ error: (err) => {
2335
+ this.alertService.showError('@dataLoadFailed');
2336
+ this.commonService.toggleRightSidenav(false);
2337
+ // Redirect to user list on error in fullscreen mode
2338
+ if (this.viewMode() === 'fullscreen') {
2339
+ const cleanPath = this.commonService.getCleanUrlPath();
2340
+ this.router.navigate([cleanPath]);
2341
+ }
2342
+ },
2343
+ });
2344
+ }
2345
+ // ***************************************************
2346
+ // *** gotoURL Methods ***
2347
+ // ***************************************************
2181
2348
  gotoURL(routePrefix, rightSidenav = [], parameters, type, dialogComponent = null, isNewTab = false, isPopup = this.isEmbedded()) {
2182
2349
  const baseHref = this.environment.getBaseHref().endsWith('/')
2183
2350
  ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
@@ -2250,18 +2417,18 @@ class NettyAgGridSaveBase extends NettyAppsBase {
2250
2417
  },
2251
2418
  ]);
2252
2419
  }
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: [""] });
2420
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridSaveBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2421
+ 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
2422
  }
2256
2423
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAgGridSaveBase, decorators: [{
2257
2424
  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: [{
2425
+ args: [{ selector: 'ntybase-ag-grid-save-base', imports: [], template: `` }]
2426
+ }], 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
2427
  type: ViewChild,
2261
2428
  args: ['saveForm']
2262
2429
  }] } });
2263
2430
 
2264
- class ExcelImportBase extends NettyAgGridBase {
2431
+ class ExcelImportBase extends NettyAgGridListBase {
2265
2432
  dataList = [];
2266
2433
  wopts = { bookType: 'xlsx', type: 'array' };
2267
2434
  fileName = 'PayrollJournalTrans.xlsx';
@@ -2290,11 +2457,11 @@ class ExcelImportBase extends NettyAgGridBase {
2290
2457
  reader.readAsBinaryString(target.files[0]);
2291
2458
  }
2292
2459
  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: [""] });
2460
+ 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
2461
  }
2295
2462
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ExcelImportBase, decorators: [{
2296
2463
  type: Component,
2297
- args: [{ selector: 'ntybase-excel-import-base', imports: [], template: "<p>excel-import-base works!</p>\n" }]
2464
+ args: [{ selector: 'ntybase-excel-import-base', imports: [], template: `` }]
2298
2465
  }] });
2299
2466
 
2300
2467
  class RangeDateTimeFilter {
@@ -2589,7 +2756,7 @@ class RangeDateTimeFilter {
2589
2756
  }
2590
2757
  }
2591
2758
  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" }] });
2759
+ 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
2760
  }
2594
2761
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeDateTimeFilter, decorators: [{
2595
2762
  type: Component,
@@ -2788,7 +2955,7 @@ class RangeNumberFilter {
2788
2955
  }
2789
2956
  }
2790
2957
  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" }] });
2958
+ 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
2959
  }
2793
2960
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeNumberFilter, decorators: [{
2794
2961
  type: Component,
@@ -3041,7 +3208,7 @@ class RangeStringFilter {
3041
3208
  }
3042
3209
  }
3043
3210
  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" }] });
3211
+ 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
3212
  }
3046
3213
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RangeStringFilter, decorators: [{
3047
3214
  type: Component,
@@ -3558,7 +3725,7 @@ class Login extends AuthBase {
3558
3725
  });
3559
3726
  }
3560
3727
  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" }] });
3728
+ 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
3729
  }
3563
3730
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: Login, decorators: [{
3564
3731
  type: Component,
@@ -3670,7 +3837,7 @@ class MfaLogin extends AuthBase {
3670
3837
  clearInterval(this.countdownInterval);
3671
3838
  }
3672
3839
  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" }] });
3840
+ 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
3841
  }
3675
3842
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: MfaLogin, decorators: [{
3676
3843
  type: Component,
@@ -3844,7 +4011,7 @@ class ForgotPassword extends AuthBase {
3844
4011
  });
3845
4012
  }
3846
4013
  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" }] });
4014
+ 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
4015
  }
3849
4016
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ForgotPassword, decorators: [{
3850
4017
  type: Component,
@@ -3935,6 +4102,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3935
4102
  args: [{ selector: 'ntybase-netty-base-app', imports: [], template: "" }]
3936
4103
  }] });
3937
4104
 
4105
+ class EnvironmentInfo {
4106
+ showNettyInfo = true;
4107
+ environmentProxy = inject(EnvironmentProxy);
4108
+ get hasConfig() {
4109
+ return this.environmentProxy.config() !== undefined;
4110
+ }
4111
+ get version() {
4112
+ return this.environmentProxy.version() ?? "";
4113
+ }
4114
+ get isProduction() {
4115
+ return false;
4116
+ }
4117
+ get defaultLanguage() {
4118
+ return "tr";
4119
+ }
4120
+ get supportedLanguages() {
4121
+ return [];
4122
+ }
4123
+ get apiUrl() {
4124
+ return this.environmentProxy.apiUrl();
4125
+ }
4126
+ get adminUrl() {
4127
+ return this.environmentProxy.adminUrl();
4128
+ }
4129
+ get baseHref() {
4130
+ return this.environmentProxy.baseHref();
4131
+ }
4132
+ get application() {
4133
+ return this.environmentProxy.application();
4134
+ }
4135
+ ngOnInit() {
4136
+ if (!this.hasConfig) {
4137
+ console.warn("Environment konfigürasyonu bulunamadı. ENVIRONMENT_CONFIG token'ı sağlandı mı?");
4138
+ }
4139
+ }
4140
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, deps: [], target: i0.ɵɵFactoryTarget.Component });
4141
+ 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" }] });
4142
+ }
4143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: EnvironmentInfo, decorators: [{
4144
+ type: Component,
4145
+ 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"] }]
4146
+ }], propDecorators: { showNettyInfo: [{
4147
+ type: Input
4148
+ }] } });
4149
+
3938
4150
  const ENVIRONMENT_CONFIG = new InjectionToken('ENVIRONMENT_CONFIG');
3939
4151
  class EnvironmentInfoService {
3940
4152
  config;
@@ -3977,56 +4189,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3977
4189
  args: [ENVIRONMENT_CONFIG]
3978
4190
  }] }] });
3979
4191
 
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
4192
  class NtyLoadingService {
4031
4193
  requestCount = 0;
4032
4194
  isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
@@ -4063,7 +4225,7 @@ class NtyLoadingComponent {
4063
4225
  loadingService = inject(NtyLoadingService);
4064
4226
  isLoading = this.loadingService.isLoading;
4065
4227
  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" }] });
4228
+ 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
4229
  }
4068
4230
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NtyLoadingComponent, decorators: [{
4069
4231
  type: Component,
@@ -4111,6 +4273,75 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4111
4273
  }]
4112
4274
  }], ctorParameters: () => [] });
4113
4275
 
4276
+ class NettyAppsFilterBase extends NettyAppsBase {
4277
+ // *********************************************************
4278
+ // *** Input / Output ***
4279
+ // *********************************************************
4280
+ isFilterExpanded = model(true, ...(ngDevMode ? [{ debugName: "isFilterExpanded" }] : []));
4281
+ filteredRecords = output();
4282
+ refresh = input(0, ...(ngDevMode ? [{ debugName: "refresh" }] : []));
4283
+ // *********************************************************
4284
+ // *** Service ***
4285
+ // *********************************************************
4286
+ filterProxy = inject(NettyStandardFilterProxy);
4287
+ enumStorage = inject(NettyEnumStorageProxy);
4288
+ // *********************************************************
4289
+ // *** Signals ***
4290
+ // *********************************************************
4291
+ currentItem = signal(this.createNewRecord(), ...(ngDevMode ? [{ debugName: "currentItem" }] : []));
4292
+ allYesNoEnumList = signal([], ...(ngDevMode ? [{ debugName: "allYesNoEnumList" }] : []));
4293
+ // *********************************************************
4294
+ // *** Constructor ***
4295
+ // *********************************************************
4296
+ constructor() {
4297
+ super();
4298
+ effect(() => {
4299
+ if (this.refresh() > 0) {
4300
+ this.onApply();
4301
+ }
4302
+ });
4303
+ }
4304
+ // *********************************************************
4305
+ // *** Functions ***
4306
+ // *********************************************************
4307
+ async ngOnInit() {
4308
+ // Load enum data for dropdowns
4309
+ await this.enumStorage.loadEnumList();
4310
+ this.allYesNoEnumList.set(this.enumStorage.getEnum('AllYesNo'));
4311
+ }
4312
+ onApply() {
4313
+ this.filterProxy.selectFilter(this.currentItem()).subscribe({
4314
+ next: (result) => {
4315
+ this.filteredRecords.emit(result);
4316
+ this.isFilterExpanded.set(false);
4317
+ },
4318
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
4319
+ });
4320
+ }
4321
+ onReset() {
4322
+ this.filterProxy.initFilter().subscribe({
4323
+ next: (filter) => {
4324
+ this.currentItem.set(filter);
4325
+ },
4326
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
4327
+ });
4328
+ }
4329
+ onExport() {
4330
+ this.filterProxy.downloadXLS(this.currentItem()).subscribe({
4331
+ next: (response) => {
4332
+ this.downloadBlobFile(response, 'application/zip', this.translateService.instant('@00000072') + '.zip');
4333
+ },
4334
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
4335
+ });
4336
+ }
4337
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsFilterBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
4338
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.6", type: NettyAppsFilterBase, isStandalone: true, selector: "ntybase-netty-apps-base", inputs: { isFilterExpanded: { classPropertyName: "isFilterExpanded", publicName: "isFilterExpanded", isSignal: true, isRequired: false, transformFunction: null }, refresh: { classPropertyName: "refresh", publicName: "refresh", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isFilterExpanded: "isFilterExpandedChange", filteredRecords: "filteredRecords" }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
4339
+ }
4340
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: NettyAppsFilterBase, decorators: [{
4341
+ type: Component,
4342
+ args: [{ selector: 'ntybase-netty-apps-base', imports: [], template: `` }]
4343
+ }], ctorParameters: () => [], propDecorators: { isFilterExpanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFilterExpanded", required: false }] }, { type: i0.Output, args: ["isFilterExpandedChange"] }], filteredRecords: [{ type: i0.Output, args: ["filteredRecords"] }], refresh: [{ type: i0.Input, args: [{ isSignal: true, alias: "refresh", required: false }] }] } });
4344
+
4114
4345
  /*
4115
4346
  * Public API Surface of ntybase
4116
4347
  */
@@ -4119,5 +4350,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
4119
4350
  * Generated bundle index. Do not edit.
4120
4351
  */
4121
4352
 
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 };
4353
+ 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, NettyAppsFilterBase, NettyBaseApp, NettyHelper, NettyImageService, NettyMenuService, NtyLoadingComponent, NtyLoadingInterceptor, Ntybase, NtybaseModule, RangeDateTimeFilter, RangeNumberFilter, RangeStringFilter, UrlHelperService, ntyAuthenticationInterceptor };
4123
4354
  //# sourceMappingURL=nettyapps-ntybase.mjs.map