@nettyapps/ntybase 0.1.9 → 0.1.11

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, Injectable, inject, NgModule, Inject, signal, input, output, computed, effect, model, ViewChild, ElementRef, ViewContainerRef, Input, ViewEncapsulation, forwardRef, ChangeDetectionStrategy } from '@angular/core';
2
+ import { Component, Injectable, inject, NgModule, Inject, signal, input, output, computed, effect, model, ViewChild, ElementRef, InjectionToken, Optional, Input, ViewContainerRef, ViewEncapsulation, forwardRef, ChangeDetectionStrategy } from '@angular/core';
3
3
  import * as i1$2 from '@angular/common/http';
4
4
  import { HttpErrorResponse, HttpResponse, HTTP_INTERCEPTORS, HttpClient, HttpHeaders } from '@angular/common/http';
5
5
  import { of, throwError, lastValueFrom, map, catchError as catchError$1, Subject, finalize, take as take$1, takeUntil } from 'rxjs';
@@ -444,7 +444,7 @@ class AlertService {
444
444
  height: 'auto',
445
445
  data: {
446
446
  message: this.translate.instant(message),
447
- title: this.translate.instant('@Confirmation'),
447
+ title: this.translate.instant('@confirmation'),
448
448
  },
449
449
  });
450
450
  dialogRef.afterClosed().subscribe((result) => {
@@ -1203,7 +1203,7 @@ class NettyAgGridBase {
1203
1203
  allowLog = signal(false, ...(ngDevMode ? [{ debugName: "allowLog" }] : []));
1204
1204
  allowRead = signal(true, ...(ngDevMode ? [{ debugName: "allowRead" }] : []));
1205
1205
  // Button action management variables
1206
- menuValid = signal(false, ...(ngDevMode ? [{ debugName: "menuValid" }] : []));
1206
+ menuValid = signal(true, ...(ngDevMode ? [{ debugName: "menuValid" }] : []));
1207
1207
  deleteValid = signal(false, ...(ngDevMode ? [{ debugName: "deleteValid" }] : []));
1208
1208
  selectionValid = signal(false, ...(ngDevMode ? [{ debugName: "selectionValid" }] : []));
1209
1209
  refreshButtonValid = signal(false, ...(ngDevMode ? [{ debugName: "refreshButtonValid" }] : []));
@@ -1366,95 +1366,6 @@ class NettyAgGridBase {
1366
1366
  suppressRowClickSelection: false,
1367
1367
  enableCellChangeFlash: true,
1368
1368
  },
1369
- localeText: {
1370
- // Status panel translate
1371
- totalRows: this.translateService.instant('AG_GRID.TOTAL_ROWS'),
1372
- filteredRows: this.translateService.instant('AG_GRID.FILTERED_ROWS'),
1373
- selectedRows: this.translateService.instant('AG_GRID.SELECTED_ROWS'),
1374
- noRowsToShow: this.translateService.instant('AG_GRID.NO_ROWS_TO_SHOW'),
1375
- loadingOoo: this.translateService.instant('AG_GRID.LOADING'),
1376
- // Context menu translations
1377
- copy: this.translateService.instant('AG_GRID.COPY'),
1378
- copyWithHeaders: this.translateService.instant('AG_GRID.COPY_WITH_HEADERS'),
1379
- copyWithGroupHeaders: this.translateService.instant('AG_GRID.COPY_WITH_GROUP_HEADERS'),
1380
- paste: this.translateService.instant('AG_GRID.PASTE'),
1381
- export: this.translateService.instant('AG_GRID.EXPORT'),
1382
- csvExport: this.translateService.instant('AG_GRID.CSV_EXPORT'),
1383
- excelExport: this.translateService.instant('AG_GRID.EXCEL_EXPORT'),
1384
- pinColumn: this.translateService.instant('AG_GRID.PIN_COLUMN'),
1385
- pinLeft: this.translateService.instant('AG_GRID.PIN_LEFT'),
1386
- pinRight: this.translateService.instant('AG_GRID.PIN_RIGHT'),
1387
- noPin: this.translateService.instant('AG_GRID.NO_PIN'),
1388
- sortAscending: this.translateService.instant('AG_GRID.SORT_ASCENDING'),
1389
- sortDescending: this.translateService.instant('AG_GRID.SORT_DESCENDING'),
1390
- autosizeThisColumn: this.translateService.instant('AG_GRID.AUTOSIZE_THIS_COLUMN'),
1391
- autosizeAllColumns: this.translateService.instant('AG_GRID.AUTOSIZE_ALL_COLUMNS'),
1392
- resetColumns: this.translateService.instant('AG_GRID.RESET_COLUMNS'),
1393
- expandAll: this.translateService.instant('AG_GRID.EXPAND_ALL'),
1394
- collapseAll: this.translateService.instant('AG_GRID.COLLAPSE_ALL'),
1395
- exportToExcel: this.translateService.instant('AG_GRID.EXPORT_TO_EXCEL'),
1396
- sheetName: this.translateService.instant('AG_GRID.SHEET_NAME'),
1397
- exportAsExcelTable: this.translateService.instant('AG_GRID.EXPORT_AS_EXCEL_TABLE'),
1398
- rangeSelectTo: this.translateService.instant('AG_GRID.RANGE_SELECT_TO'),
1399
- rangeSelectFrom: this.translateService.instant('AG_GRID.RANGE_SELECT_FROM'),
1400
- rangeSelectCopy: this.translateService.instant('AG_GRID.RANGE_SELECT_COPY'),
1401
- rangeSelectChart: this.translateService.instant('AG_GRID.RANGE_SELECT_CHART'),
1402
- pasteAll: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE'),
1403
- pasteWithoutHeader: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE_WITHOUT_HEADER'),
1404
- copyAll: this.translateService.instant('AG_GRID.CLIPBOARD_COPY'),
1405
- cut: this.translateService.instant('AG_GRID.CLIPBOARD_CUT'),
1406
- // Pagination translations
1407
- page: this.translateService.instant('AG_GRID.PAGE'),
1408
- more: this.translateService.instant('AG_GRID.MORE'),
1409
- to: this.translateService.instant('AG_GRID.TO'),
1410
- of: this.translateService.instant('AG_GRID.OF'),
1411
- next: this.translateService.instant('AG_GRID.NEXT'),
1412
- last: this.translateService.instant('AG_GRID.LAST'),
1413
- first: this.translateService.instant('AG_GRID.FIRST'),
1414
- previous: this.translateService.instant('AG_GRID.PREVIOUS'),
1415
- pageSizeSelectorLabel: this.translateService.instant('AG_GRID.PAGE_SIZE_SELECTOR_LABEL'),
1416
- // Set Filter
1417
- selectAll: this.translateService.instant('AG_GRID.SELECT_ALL'),
1418
- selectAllSearchResults: this.translateService.instant('AG_GRID.SELECT_ALL_SEARCH_RESULTS'),
1419
- searchOoo: this.translateService.instant('AG_GRID.SEARCH_OOO'),
1420
- blanks: this.translateService.instant('AG_GRID.BLANKS'),
1421
- noMatches: this.translateService.instant('AG_GRID.NO_MATCHES'),
1422
- // Number Filter & Text Filter
1423
- filterOoo: this.translateService.instant('AG_GRID.FILTER_OOO'),
1424
- equals: this.translateService.instant('AG_GRID.EQUALS'),
1425
- notEqual: this.translateService.instant('AG_GRID.NOT_EQUAL'),
1426
- blank: this.translateService.instant('AG_GRID.BLANK'),
1427
- notBlank: this.translateService.instant('AG_GRID.NOT_BLANK'),
1428
- empty: this.translateService.instant('AG_GRID.EMPTY'),
1429
- // Number Filter
1430
- lessThan: this.translateService.instant('AG_GRID.LESS_THAN'),
1431
- greaterThan: this.translateService.instant('AG_GRID.GREATER_THAN'),
1432
- lessThanOrEqual: this.translateService.instant('AG_GRID.LESS_THAN_OR_EQUAL'),
1433
- greaterThanOrEqual: this.translateService.instant('AG_GRID.GREATER_THAN_OR_EQUAL'),
1434
- inRange: this.translateService.instant('AG_GRID.IN_RANGE'),
1435
- inRangeStart: this.translateService.instant('AG_GRID.IN_RANGE_START'),
1436
- inRangeEnd: this.translateService.instant('AG_GRID.IN_RANGE_END'),
1437
- // Text Filter
1438
- contains: this.translateService.instant('AG_GRID.CONTAINS'),
1439
- notContains: this.translateService.instant('AG_GRID.NOT_CONTAINS'),
1440
- startsWith: this.translateService.instant('AG_GRID.STARTS_WITH'),
1441
- endsWith: this.translateService.instant('AG_GRID.ENDS_WITH'),
1442
- // Date Filter
1443
- dateFormatOoo: this.translateService.instant('AG_GRID.DATE_FORMAT_OOO'),
1444
- // Filter Conditions
1445
- andCondition: this.translateService.instant('AG_GRID.AND_CONDITION'),
1446
- orCondition: this.translateService.instant('AG_GRID.OR_CONDITION'),
1447
- // Filter Buttons
1448
- applyFilter: this.translateService.instant('AG_GRID.APPLY_FILTER'),
1449
- resetFilter: this.translateService.instant('AG_GRID.RESET_FILTER'),
1450
- clearFilter: this.translateService.instant('AG_GRID.CLEAR_FILTER'),
1451
- cancelFilter: this.translateService.instant('AG_GRID.CANCEL_FILTER'),
1452
- // Filter Titles
1453
- textFilter: this.translateService.instant('AG_GRID.TEXT_FILTER'),
1454
- numberFilter: this.translateService.instant('AG_GRID.NUMBER_FILTER'),
1455
- dateFilter: this.translateService.instant('AG_GRID.DATE_FILTER'),
1456
- setFilter: this.translateService.instant('AG_GRID.SET_FILTER'),
1457
- },
1458
1369
  };
1459
1370
  // Statusbar
1460
1371
  statusBar = {
@@ -1503,6 +1414,7 @@ class NettyAgGridBase {
1503
1414
  // Common grid ready handler
1504
1415
  onGridReady(params) {
1505
1416
  this.gridApi = params.api;
1417
+ this.setAgGridTranslations();
1506
1418
  this.gridApi.addEventListener('selectionChanged', () => {
1507
1419
  // Null-safe approach
1508
1420
  const selectedNodes = this.gridApi?.getSelectedNodes?.() || [];
@@ -1624,6 +1536,9 @@ class NettyAgGridBase {
1624
1536
  buttonRenderer: ButtonRenderer,
1625
1537
  checkboxRenderer: CheckboxRenderer,
1626
1538
  };
1539
+ this.translateService.onLangChange.subscribe(() => {
1540
+ this.setAgGridTranslations();
1541
+ });
1627
1542
  effect(() => {
1628
1543
  const update = this.commonService.updates();
1629
1544
  if (!update || !this.gridApi)
@@ -1638,6 +1553,99 @@ class NettyAgGridBase {
1638
1553
  }
1639
1554
  });
1640
1555
  }
1556
+ setAgGridTranslations() {
1557
+ if (this.gridApi) {
1558
+ this.gridApi.setGridOption('localeText', {
1559
+ // Status panel translate
1560
+ totalRows: this.translateService.instant('AG_GRID.TOTAL_ROWS'),
1561
+ filteredRows: this.translateService.instant('AG_GRID.FILTERED_ROWS'),
1562
+ selectedRows: this.translateService.instant('AG_GRID.SELECTED_ROWS'),
1563
+ noRowsToShow: this.translateService.instant('AG_GRID.NO_ROWS_TO_SHOW'),
1564
+ loadingOoo: this.translateService.instant('AG_GRID.LOADING'),
1565
+ // Context menu translations
1566
+ copy: this.translateService.instant('AG_GRID.COPY'),
1567
+ copyWithHeaders: this.translateService.instant('AG_GRID.COPY_WITH_HEADERS'),
1568
+ copyWithGroupHeaders: this.translateService.instant('AG_GRID.COPY_WITH_GROUP_HEADERS'),
1569
+ paste: this.translateService.instant('AG_GRID.PASTE'),
1570
+ export: this.translateService.instant('AG_GRID.EXPORT'),
1571
+ csvExport: this.translateService.instant('AG_GRID.CSV_EXPORT'),
1572
+ excelExport: this.translateService.instant('AG_GRID.EXCEL_EXPORT'),
1573
+ pinColumn: this.translateService.instant('AG_GRID.PIN_COLUMN'),
1574
+ pinLeft: this.translateService.instant('AG_GRID.PIN_LEFT'),
1575
+ pinRight: this.translateService.instant('AG_GRID.PIN_RIGHT'),
1576
+ noPin: this.translateService.instant('AG_GRID.NO_PIN'),
1577
+ sortAscending: this.translateService.instant('AG_GRID.SORT_ASCENDING'),
1578
+ sortDescending: this.translateService.instant('AG_GRID.SORT_DESCENDING'),
1579
+ autosizeThisColumn: this.translateService.instant('AG_GRID.AUTOSIZE_THIS_COLUMN'),
1580
+ autosizeAllColumns: this.translateService.instant('AG_GRID.AUTOSIZE_ALL_COLUMNS'),
1581
+ resetColumns: this.translateService.instant('AG_GRID.RESET_COLUMNS'),
1582
+ expandAll: this.translateService.instant('AG_GRID.EXPAND_ALL'),
1583
+ collapseAll: this.translateService.instant('AG_GRID.COLLAPSE_ALL'),
1584
+ exportToExcel: this.translateService.instant('AG_GRID.EXPORT_TO_EXCEL'),
1585
+ sheetName: this.translateService.instant('AG_GRID.SHEET_NAME'),
1586
+ exportAsExcelTable: this.translateService.instant('AG_GRID.EXPORT_AS_EXCEL_TABLE'),
1587
+ rangeSelectTo: this.translateService.instant('AG_GRID.RANGE_SELECT_TO'),
1588
+ rangeSelectFrom: this.translateService.instant('AG_GRID.RANGE_SELECT_FROM'),
1589
+ rangeSelectCopy: this.translateService.instant('AG_GRID.RANGE_SELECT_COPY'),
1590
+ rangeSelectChart: this.translateService.instant('AG_GRID.RANGE_SELECT_CHART'),
1591
+ pasteAll: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE'),
1592
+ pasteWithoutHeader: this.translateService.instant('AG_GRID.CLIPBOARD_PASTE_WITHOUT_HEADER'),
1593
+ copyAll: this.translateService.instant('AG_GRID.CLIPBOARD_COPY'),
1594
+ cut: this.translateService.instant('AG_GRID.CLIPBOARD_CUT'),
1595
+ // Pagination translations
1596
+ page: this.translateService.instant('AG_GRID.PAGE'),
1597
+ more: this.translateService.instant('AG_GRID.MORE'),
1598
+ to: this.translateService.instant('AG_GRID.TO'),
1599
+ of: this.translateService.instant('AG_GRID.OF'),
1600
+ next: this.translateService.instant('AG_GRID.NEXT'),
1601
+ last: this.translateService.instant('AG_GRID.LAST'),
1602
+ first: this.translateService.instant('AG_GRID.FIRST'),
1603
+ previous: this.translateService.instant('AG_GRID.PREVIOUS'),
1604
+ pageSizeSelectorLabel: this.translateService.instant('AG_GRID.PAGE_SIZE_SELECTOR_LABEL'),
1605
+ // Set Filter
1606
+ selectAll: this.translateService.instant('AG_GRID.SELECT_ALL'),
1607
+ selectAllSearchResults: this.translateService.instant('AG_GRID.SELECT_ALL_SEARCH_RESULTS'),
1608
+ searchOoo: this.translateService.instant('AG_GRID.SEARCH_OOO'),
1609
+ blanks: this.translateService.instant('AG_GRID.BLANKS'),
1610
+ noMatches: this.translateService.instant('AG_GRID.NO_MATCHES'),
1611
+ // Number Filter & Text Filter
1612
+ filterOoo: this.translateService.instant('AG_GRID.FILTER_OOO'),
1613
+ equals: this.translateService.instant('AG_GRID.EQUALS'),
1614
+ notEqual: this.translateService.instant('AG_GRID.NOT_EQUAL'),
1615
+ blank: this.translateService.instant('AG_GRID.BLANK'),
1616
+ notBlank: this.translateService.instant('AG_GRID.NOT_BLANK'),
1617
+ empty: this.translateService.instant('AG_GRID.EMPTY'),
1618
+ // Number Filter
1619
+ lessThan: this.translateService.instant('AG_GRID.LESS_THAN'),
1620
+ greaterThan: this.translateService.instant('AG_GRID.GREATER_THAN'),
1621
+ lessThanOrEqual: this.translateService.instant('AG_GRID.LESS_THAN_OR_EQUAL'),
1622
+ greaterThanOrEqual: this.translateService.instant('AG_GRID.GREATER_THAN_OR_EQUAL'),
1623
+ inRange: this.translateService.instant('AG_GRID.IN_RANGE'),
1624
+ inRangeStart: this.translateService.instant('AG_GRID.IN_RANGE_START'),
1625
+ inRangeEnd: this.translateService.instant('AG_GRID.IN_RANGE_END'),
1626
+ // Text Filter
1627
+ contains: this.translateService.instant('AG_GRID.CONTAINS'),
1628
+ notContains: this.translateService.instant('AG_GRID.NOT_CONTAINS'),
1629
+ startsWith: this.translateService.instant('AG_GRID.STARTS_WITH'),
1630
+ endsWith: this.translateService.instant('AG_GRID.ENDS_WITH'),
1631
+ // Date Filter
1632
+ dateFormatOoo: this.translateService.instant('AG_GRID.DATE_FORMAT_OOO'),
1633
+ // Filter Conditions
1634
+ andCondition: this.translateService.instant('AG_GRID.AND_CONDITION'),
1635
+ orCondition: this.translateService.instant('AG_GRID.OR_CONDITION'),
1636
+ // Filter Buttons
1637
+ applyFilter: this.translateService.instant('AG_GRID.APPLY_FILTER'),
1638
+ resetFilter: this.translateService.instant('AG_GRID.RESET_FILTER'),
1639
+ clearFilter: this.translateService.instant('AG_GRID.CLEAR_FILTER'),
1640
+ cancelFilter: this.translateService.instant('AG_GRID.CANCEL_FILTER'),
1641
+ // Filter Titles
1642
+ textFilter: this.translateService.instant('AG_GRID.TEXT_FILTER'),
1643
+ numberFilter: this.translateService.instant('AG_GRID.NUMBER_FILTER'),
1644
+ dateFilter: this.translateService.instant('AG_GRID.DATE_FILTER'),
1645
+ setFilter: this.translateService.instant('AG_GRID.SET_FILTER'),
1646
+ });
1647
+ }
1648
+ }
1641
1649
  /**
1642
1650
  * Update a single row in the grid
1643
1651
  * @param rowData The updated row data
@@ -1663,10 +1671,10 @@ class NettyAgGridBase {
1663
1671
  return;
1664
1672
  const selectedNodes = this.gridApi.getSelectedNodes();
1665
1673
  if (selectedNodes.length === 0) {
1666
- await this.alertService.showAlert('@PleaseSelectRowToDelete');
1674
+ await this.alertService.showAlert('@pleaseSelectRowToDelete');
1667
1675
  return;
1668
1676
  }
1669
- const confirmed = await this.alertService.showConfirm('@ConfirmDeleteSelectedRecords');
1677
+ const confirmed = await this.alertService.showConfirm('@confirmDeleteSelectedRecords');
1670
1678
  if (confirmed) {
1671
1679
  const selectedRows = selectedNodes.map((node) => node.data);
1672
1680
  this.deleteRows?.(selectedRows);
@@ -1675,7 +1683,7 @@ class NettyAgGridBase {
1675
1683
  async refreshData() {
1676
1684
  try {
1677
1685
  this.loadData();
1678
- await this.alertService.showAlert('@DataRefreshedSuccessfully');
1686
+ await this.alertService.showAlert('@dataRefreshedSuccessfully');
1679
1687
  }
1680
1688
  catch (err) {
1681
1689
  this.alertService.showError(err);
@@ -1717,6 +1725,9 @@ class NettyAgGridBase {
1717
1725
  this.accessRightsProcessed.set(true);
1718
1726
  return true;
1719
1727
  }
1728
+ onFilterTextBoxVisibilityChange(isOpen) {
1729
+ this.menuValid.set(!isOpen);
1730
+ }
1720
1731
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: NettyAgGridBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
1721
1732
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.11", 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 }, params: { classPropertyName: "params", publicName: "params", isSignal: true, isRequired: false, transformFunction: null }, parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedElement: "selectedElement" }, usesOnChanges: true, ngImport: i0, template: "<p>ag-grid-base works!</p>\n", styles: [""] });
1722
1733
  }
@@ -1805,7 +1816,7 @@ class NettyAgGridSaveBase {
1805
1816
  */
1806
1817
  async canDeactivate() {
1807
1818
  if (this.formChanged) {
1808
- return await this.alertService.showConfirm('@UnsavedChangesConfirm');
1819
+ return await this.alertService.showConfirm('@unsavedChangesConfirm');
1809
1820
  }
1810
1821
  return true;
1811
1822
  }
@@ -1858,12 +1869,12 @@ class NettyAgGridSaveBase {
1858
1869
  control.markAsTouched();
1859
1870
  control.markAsDirty();
1860
1871
  });
1861
- this.alertService.showError('@PleaseFillRequiredFields');
1872
+ this.alertService.showError('@pleaseFillRequiredFields');
1862
1873
  return false;
1863
1874
  }
1864
1875
  // First check if there are any visual form changes
1865
1876
  if (!this.formChanged && recordGUID) {
1866
- this.alertService.showAlert('@NoChangesDetected');
1877
+ this.alertService.showAlert('@noChangesDetected');
1867
1878
  if (this.closeAfterSave()) {
1868
1879
  this.closeSidenav();
1869
1880
  }
@@ -2257,7 +2268,7 @@ class Login extends AuthBase {
2257
2268
  }
2258
2269
  },
2259
2270
  error: (error) => {
2260
- const errorMessage = error.message || '@LoginFailed';
2271
+ const errorMessage = error.message || '@loginFailed';
2261
2272
  this.error.set(errorMessage); // Set the error signal
2262
2273
  this.alertService.showError(errorMessage);
2263
2274
  },
@@ -2281,7 +2292,7 @@ class Login extends AuthBase {
2281
2292
  });
2282
2293
  }
2283
2294
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: Login, deps: null, target: i0.ɵɵFactoryTarget.Component });
2284
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['username'].invalid && loginForm.controls['username'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Username is required' | translate }}\n </mat-error>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['password'].invalid && loginForm.controls['password'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </div>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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(--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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i1$4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2295
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['username'].invalid && loginForm.controls['username'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['password'].invalid && loginForm.controls['password'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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(--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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i1$4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2285
2296
  }
2286
2297
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: Login, decorators: [{
2287
2298
  type: Component,
@@ -2294,7 +2305,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
2294
2305
  MatInputModule,
2295
2306
  MatFormFieldModule,
2296
2307
  TranslateModule,
2297
- ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['username'].invalid && loginForm.controls['username'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Username is required' | translate }}\n </mat-error>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['password'].invalid && loginForm.controls['password'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </div>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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(--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"] }]
2308
+ ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['username'].invalid && loginForm.controls['username'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['password'].invalid && loginForm.controls['password'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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(--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"] }]
2298
2309
  }] });
2299
2310
 
2300
2311
  class MfaLogin extends AuthBase {
@@ -2395,7 +2406,7 @@ class MfaLogin extends AuthBase {
2395
2406
  clearInterval(this.countdownInterval);
2396
2407
  }
2397
2408
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: MfaLogin, deps: null, target: i0.ɵɵFactoryTarget.Component });
2398
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['mfaCode'].invalid && loginForm.controls['mfaCode'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'MFACode is required' | translate }}\n </div>\n <!-- Time -->\n <div class=\"time-remaining\" *ngIf=\"!resendable()\">\n {{ '@TokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\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 <div class=\"resend-container\" *ngIf=\"resendable()\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'Resend MFACode' | translate }}\n </span>\n </div>\n </form>\n\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i5.TranslatePipe, name: "translate" }] });
2409
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['mfaCode'].invalid && loginForm.controls['mfaCode'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n <!-- Time -->\n <div class=\"time-remaining\" *ngIf=\"!resendable()\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\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 <div class=\"resend-container\" *ngIf=\"resendable()\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n </form>\n\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i5.TranslatePipe, name: "translate" }] });
2399
2410
  }
2400
2411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: MfaLogin, decorators: [{
2401
2412
  type: Component,
@@ -2406,7 +2417,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
2406
2417
  MatMenuModule,
2407
2418
  MatIconModule,
2408
2419
  TranslateModule,
2409
- ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['mfaCode'].invalid && loginForm.controls['mfaCode'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'MFACode is required' | translate }}\n </div>\n <!-- Time -->\n <div class=\"time-remaining\" *ngIf=\"!resendable()\">\n {{ '@TokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\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 <div class=\"resend-container\" *ngIf=\"resendable()\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'Resend MFACode' | translate }}\n </span>\n </div>\n </form>\n\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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"] }]
2420
+ ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"login()\"\n [formGroup]=\"loginForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <div\n class=\"validation-error\"\n *ngIf=\"loginForm.controls['mfaCode'].invalid && loginForm.controls['mfaCode'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n <!-- Time -->\n <div class=\"time-remaining\" *ngIf=\"!resendable()\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\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 <div class=\"resend-container\" *ngIf=\"resendable()\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n </form>\n\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n </ng-template>\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"] }]
2410
2421
  }] });
2411
2422
 
2412
2423
  class PasswordProxy {
@@ -2570,7 +2581,7 @@ class ForgotPassword extends AuthBase {
2570
2581
  });
2571
2582
  }
2572
2583
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: ForgotPassword, deps: [], target: i0.ɵɵFactoryTarget.Component });
2573
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPassword'].invalid && updatePasswordForm.controls['newPassword'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </mat-error>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPasswordCheck'].invalid && updatePasswordForm.controls['newPasswordCheck'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </mat-error>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n </ng-template>\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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i1$4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2584
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPassword'].invalid && updatePasswordForm.controls['newPassword'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPasswordCheck'].invalid && updatePasswordForm.controls['newPasswordCheck'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n </ng-template>\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],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: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.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: i1$4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2574
2585
  }
2575
2586
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: ForgotPassword, decorators: [{
2576
2587
  type: Component,
@@ -2583,7 +2594,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
2583
2594
  MatInputModule,
2584
2595
  MatFormFieldModule,
2585
2596
  TranslateModule,
2586
- ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPassword'].invalid && updatePasswordForm.controls['newPassword'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </mat-error>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPasswordCheck'].invalid && updatePasswordForm.controls['newPasswordCheck'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'Password is required' | translate }}\n </mat-error>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n </ng-template>\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"] }]
2597
+ ], 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 <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n *ngIf=\"!isLoading(); else loading\"\n novalidate\n >\n <div class=\"error-message\" *ngIf=\"error()\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPassword'].invalid && updatePasswordForm.controls['newPassword'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\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 <mat-error\n class=\"validation-error\"\n *ngIf=\"updatePasswordForm.controls['newPasswordCheck'].invalid && updatePasswordForm.controls['newPasswordCheck'].touched\"\n >\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\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\n <ng-template #loading>\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n </ng-template>\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"] }]
2587
2598
  }], ctorParameters: () => [] });
2588
2599
 
2589
2600
  class HttpError403 {
@@ -2735,6 +2746,9 @@ class NettyMenuService {
2735
2746
  constructor() {
2736
2747
  effect(() => {
2737
2748
  const currentMenuName = this.menuName();
2749
+ if (!currentMenuName.trim()) {
2750
+ return;
2751
+ }
2738
2752
  let functionUrl = this.environmentProxy.getAdminLink('/GetMenu');
2739
2753
  if (currentMenuName.trim().length > 0) {
2740
2754
  functionUrl += '/' + currentMenuName.trim();
@@ -2947,7 +2961,7 @@ class LeftSidenav {
2947
2961
  this.searchTerm.set(term);
2948
2962
  }
2949
2963
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: LeftSidenav, deps: [], target: i0.ɵɵFactoryTarget.Component });
2950
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.11", type: LeftSidenav, isStandalone: true, selector: "ntybase-left-sidenav", inputs: { isMinimized: { classPropertyName: "isMinimized", publicName: "isMinimized", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleMinimize: "toggleMinimize" }, ngImport: i0, template: "<div class=\"sidenav-content-wrapper\">\n <!-- Minimize Icon -->\n <button mat-icon-button (click)=\"onToggleMinimize()\" class=\"minimize-button\">\n <mat-icon class=\"minimize-icon\">\n {{ isMinimized() ? \"chevron_right\" : \"chevron_left\" }}\n </mat-icon>\n </button>\n\n <!-- Profile -->\n <div class=\"profile-section\">\n <button mat-button [matMenuTriggerFor]=\"profileMenu\" class=\"profile-button\">\n <img [src]=\"profileImage()\" [alt]=\"username()\" class=\"profile-image\" />\n @if(!isMinimized()){\n <div class=\"profile-info\">\n <p class=\"profile-name\">{{ username() }}</p>\n </div>\n }\n </button>\n\n <mat-menu #profileMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>account_circle</mat-icon>\n <span>{{ '@profile' | translate }}</span>\n </button>\n <button mat-menu-item mat-button disabled>\n <mat-icon>swap_horiz</mat-icon>\n <span>{{ '@changeCompany' | translate }}</span>\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n </div>\n\n <!-- Search Input -->\n <ntyui-search-input\n class=\"search-input\"\n [label]=\"'@search' | translate\"\n [placeholder]=\"'@placeholderSearch' | translate\"\n [appearance]=\"'outline'\"\n *ngIf=\"!isMinimized()\"\n (search)=\"onSearch($event)\"\n >\n </ntyui-search-input>\n\n <!-- Menu -->\n <mat-nav-list *ngIf=\"!isMinimized()\">\n <div class=\"sidebar\">\n <ul>\n <ng-container *ngFor=\"let item of filteredMenuItems()\">\n <li>\n <a\n *ngIf=\"!item.children || item.children.length === 0\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"active\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n </a>\n\n <a\n *ngIf=\"item.children && item.children.length > 0\"\n (click)=\"toggleSubMenu(item)\"\n [class.expanded]=\"item.expanded\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n <mat-icon [class.rotated]=\"item.expanded\">\n {{ item.expanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </a>\n\n <ul\n *ngIf=\"item.children && item.children.length > 0 && item.expanded\"\n class=\"submenu\"\n >\n <li *ngFor=\"let child of item.children\">\n <a [routerLink]=\"child.link\" routerLinkActive=\"active\">\n <mat-icon>{{ child.icon }}</mat-icon>\n <span>{{ child.name }}</span>\n </a>\n </li>\n </ul>\n </li>\n </ng-container>\n </ul>\n </div>\n </mat-nav-list>\n\n <!-- Footer -->\n <div class=\"sidenav-footer\">\n <button mat-button [matMenuTriggerFor]=\"footerMenu\" class=\"footer-button\">\n <div class=\"footer-text\" *ngIf=\"!isMinimized()\">\n <div class=\"company-name\">\n <p>&copy; 2025 AXIS</p>\n </div>\n </div>\n </button>\n <div class=\"version\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n\n <mat-menu #footerMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>swap_horiz</mat-icon>\n {{ '@changeCompany' | translate }}\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n</div>\n", styles: [".profile-section{text-align:center;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;flex-direction:column;position:relative}.profile-section:hover{transform:scale(.98)}.profile-section .profile-button{display:flex;flex-direction:column;align-items:center;background:none;border:none;padding:0;cursor:pointer;width:100%}.profile-image{width:60px;height:60px;border-radius:50%;object-fit:cover;margin:0 auto 8px;display:block;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:all .3s ease}.profile-name{font-weight:500;font-size:1rem;color:inherit;transition:opacity .3s ease;margin-top:8px}:host-context(.minimized) .profile-section{padding:10px 0}:host-context(.minimized) .profile-image{width:40px;height:40px;margin:0 auto}.sidenav-footer{position:static;bottom:0;left:0;right:0;padding:16px;color:inherit;font-size:12px;border-top:1px solid rgba(0,0,0,.1);transition:all .3s ease;display:flex;align-items:center;justify-content:space-between;margin-top:auto}.sidenav-footer .version{font-size:10px;margin-top:4px}.footer-button{border:none;background:none;cursor:pointer}:host-context(.minimized) .version{margin-right:7px}:host-context(.minimized) .sidenav-content-wrapper{overflow:hidden}.sidenav-content-wrapper{position:relative;height:100%;display:flex;flex-direction:column;overflow-x:hidden}.sidebar{flex:1;overflow:auto}.sidebar ul{list-style:none;padding:0;margin:0}.sidebar li{margin-bottom:4px;position:relative}.sidebar li a{display:flex;align-items:center;padding:12px 0 0;border-radius:6px;color:var(--mat-sys-primary);text-decoration:none;transition:all .2s ease;position:relative;overflow:hidden}.sidebar li a:hover{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier)}.sidebar li a.active{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier);font-weight:500}.sidebar li a.active:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--mat-nty-save-record-header-bar);border-radius:3px 0 0 3px}.sidebar mat-icon{font-size:20px;width:20px;height:20px;color:inherit}.sidebar span{font-size:.875rem;white-space:nowrap}.submenu{padding-left:12px;margin-top:4px}.submenu li a{padding:10px 16px 0 20px}.submenu mat-icon{font-size:18px}.sidebar li a mat-icon:last-child{margin-left:auto;margin-right:0;font-size:18px;color:#5f6368}:host-context(.minimized) .sidebar li a{justify-content:center;padding:12px 0}:host-context(.minimized) .sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:50%;z-index:999}:host-context(.minimized) .sidebar mat-icon{margin-right:0}:host-context(.minimized) .sidebar span,:host-context(.minimized) .sidebar li a mat-icon:last-child{display:none}:host-context(.minimized) .submenu{display:none}.sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:1px;z-index:999}.search-input{margin-top:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3$3.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i5$1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: NettyUISearchInput, selector: "ntyui-search-input", outputs: ["search"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2964
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.11", type: LeftSidenav, isStandalone: true, selector: "ntybase-left-sidenav", inputs: { isMinimized: { classPropertyName: "isMinimized", publicName: "isMinimized", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggleMinimize: "toggleMinimize" }, ngImport: i0, template: "<div class=\"sidenav-content-wrapper\">\n <!-- Minimize Icon -->\n <button mat-icon-button (click)=\"onToggleMinimize()\" class=\"minimize-button\">\n <mat-icon class=\"minimize-icon\">\n {{ isMinimized() ? \"chevron_right\" : \"chevron_left\" }}\n </mat-icon>\n </button>\n\n <!-- Profile -->\n <div class=\"profile-section\">\n <button mat-button [matMenuTriggerFor]=\"profileMenu\" class=\"profile-button\">\n <img [src]=\"profileImage()\" [alt]=\"username()\" class=\"profile-image\" />\n @if(!isMinimized()){\n <div class=\"profile-info\">\n <p class=\"profile-name\">{{ username() }}</p>\n </div>\n }\n </button>\n\n <mat-menu #profileMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>account_circle</mat-icon>\n <span>{{ '@profile' | translate }}</span>\n </button>\n <button mat-menu-item mat-button disabled>\n <mat-icon>swap_horiz</mat-icon>\n <span>{{ '@changeCompany' | translate }}</span>\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n </div>\n\n <!-- Search Input -->\n <ntyui-search-input\n class=\"search-input\"\n [label]=\"'@search' | translate\"\n [placeholder]=\"'@placeholderSearch' | translate\"\n [appearance]=\"'outline'\"\n *ngIf=\"!isMinimized()\"\n (search)=\"onSearch($event)\"\n >\n </ntyui-search-input>\n\n <!-- Menu -->\n <mat-nav-list *ngIf=\"!isMinimized()\">\n <div class=\"sidebar\">\n <ul>\n <!-- Recursive menu render -->\n <ng-container\n *ngTemplateOutlet=\"menuItemsTemplate; context: { $implicit: filteredMenuItems(), level: 0 }\"\n ></ng-container>\n </ul>\n </div>\n </mat-nav-list>\n\n <!-- Footer -->\n <div class=\"sidenav-footer\">\n <button mat-button [matMenuTriggerFor]=\"footerMenu\" class=\"footer-button\">\n @if (!isMinimized()) {\n <div class=\"footer-text\">\n <div class=\"company-name\">\n <p>&copy; 2025 AXIS</p>\n </div>\n </div>\n }\n </button>\n <div class=\"version\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n\n <mat-menu #footerMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>swap_horiz</mat-icon>\n {{ '@changeCompany' | translate }}\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n</div>\n\n<!-- Recursive Menu Template -->\n<ng-template #menuItemsTemplate let-items let-level=\"level\">\n @for (item of items; track item.name) {\n <li [class]=\"'menu-level-' + level\">\n <!-- Leaf node (no children) -->\n @if (!item.children || item.children.length === 0) {\n <a\n [routerLink]=\"item.link\"\n routerLinkActive=\"active\"\n [class]=\"'menu-link level-' + level\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n </a>\n }\n\n <!-- Parent node with children -->\n @if (item.children && item.children.length > 0) {\n <a\n (click)=\"toggleSubMenu(item)\"\n [class.expanded]=\"item.expanded\"\n [class]=\"'menu-link has-children level-' + level\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n <mat-icon [class.rotated]=\"item.expanded\" class=\"expand-icon\">\n {{ item.expanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </a>\n }\n\n <!-- Recursive submenu -->\n @if (item.children && item.children.length > 0 && item.expanded) {\n <ul [class]=\"'submenu level-' + (level + 1)\">\n <ng-container\n *ngTemplateOutlet=\"menuItemsTemplate; context: { $implicit: item.children, level: level + 1 }\"\n ></ng-container>\n </ul>\n }\n </li>\n }\n</ng-template>\n", styles: [".profile-section{text-align:center;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;flex-direction:column;position:relative}.profile-section:hover{transform:scale(.98)}.profile-section .profile-button{display:flex;flex-direction:column;align-items:center;background:none;border:none;padding:0;cursor:pointer;width:100%}.profile-image{width:60px;height:60px;border-radius:50%;object-fit:cover;margin:0 auto 8px;display:block;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:all .3s ease}.profile-name{font-weight:500;font-size:1rem;color:inherit;transition:opacity .3s ease;margin-top:8px}:host-context(.minimized) .profile-section{padding:10px 0}:host-context(.minimized) .profile-image{width:40px;height:40px;margin:0 auto}.sidenav-footer{position:static;bottom:0;left:0;right:0;padding:16px;color:inherit;font-size:12px;border-top:1px solid rgba(0,0,0,.1);transition:all .3s ease;display:flex;align-items:center;justify-content:space-between;margin-top:auto}.sidenav-footer .version{font-size:10px;margin-top:4px}.footer-button{border:none;background:none;cursor:pointer}:host-context(.minimized) .version{margin-right:7px}:host-context(.minimized) .sidenav-content-wrapper{overflow:hidden}.sidenav-content-wrapper{position:relative;height:100%;display:flex;flex-direction:column;overflow-x:hidden}.sidebar{flex:1;overflow:auto}.sidebar ul{list-style:none;padding:0;margin:0}.sidebar li{margin-bottom:4px;position:relative}.sidebar li a{display:flex;align-items:center;padding:12px 0 0;border-radius:6px;color:var(--mat-sys-primary);text-decoration:none;transition:all .2s ease;position:relative;overflow:hidden}.sidebar li a:hover{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier)}.sidebar li a.active{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier);font-weight:500}.sidebar li a.active:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--mat-nty-save-record-header-bar);border-radius:3px 0 0 3px}.sidebar mat-icon{font-size:20px;width:20px;height:20px;color:inherit}.sidebar span{font-size:.875rem;white-space:nowrap}.menu-link.level-2{margin-left:20px;font-size:.82rem}.menu-link.level-3{margin-left:20px;font-size:.8rem}.menu-link.level-4{margin-left:20px;font-size:.78rem}.submenu{padding-left:12px;margin-top:4px}.submenu li a{padding:10px 16px 0 20px}.submenu mat-icon{font-size:18px}.sidebar li a mat-icon:last-child{margin-left:auto;margin-right:0;font-size:18px;color:#5f6368}:host-context(.minimized) .sidebar li a{justify-content:center;padding:12px 0}:host-context(.minimized) .sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:50%;z-index:999}:host-context(.minimized) .sidebar mat-icon{margin-right:0}:host-context(.minimized) .sidebar span,:host-context(.minimized) .sidebar li a mat-icon:last-child{display:none}:host-context(.minimized) .submenu{display:none}.sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:1px;z-index:999}.search-input{margin-top:10px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i3$3.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i3$2.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: i3$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i3$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i5$1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: NettyUISearchInput, selector: "ntyui-search-input", outputs: ["search"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] });
2951
2965
  }
2952
2966
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: LeftSidenav, decorators: [{
2953
2967
  type: Component,
@@ -2961,7 +2975,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
2961
2975
  RouterModule,
2962
2976
  NettyUISearchInput,
2963
2977
  TranslateModule,
2964
- ], template: "<div class=\"sidenav-content-wrapper\">\n <!-- Minimize Icon -->\n <button mat-icon-button (click)=\"onToggleMinimize()\" class=\"minimize-button\">\n <mat-icon class=\"minimize-icon\">\n {{ isMinimized() ? \"chevron_right\" : \"chevron_left\" }}\n </mat-icon>\n </button>\n\n <!-- Profile -->\n <div class=\"profile-section\">\n <button mat-button [matMenuTriggerFor]=\"profileMenu\" class=\"profile-button\">\n <img [src]=\"profileImage()\" [alt]=\"username()\" class=\"profile-image\" />\n @if(!isMinimized()){\n <div class=\"profile-info\">\n <p class=\"profile-name\">{{ username() }}</p>\n </div>\n }\n </button>\n\n <mat-menu #profileMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>account_circle</mat-icon>\n <span>{{ '@profile' | translate }}</span>\n </button>\n <button mat-menu-item mat-button disabled>\n <mat-icon>swap_horiz</mat-icon>\n <span>{{ '@changeCompany' | translate }}</span>\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n </div>\n\n <!-- Search Input -->\n <ntyui-search-input\n class=\"search-input\"\n [label]=\"'@search' | translate\"\n [placeholder]=\"'@placeholderSearch' | translate\"\n [appearance]=\"'outline'\"\n *ngIf=\"!isMinimized()\"\n (search)=\"onSearch($event)\"\n >\n </ntyui-search-input>\n\n <!-- Menu -->\n <mat-nav-list *ngIf=\"!isMinimized()\">\n <div class=\"sidebar\">\n <ul>\n <ng-container *ngFor=\"let item of filteredMenuItems()\">\n <li>\n <a\n *ngIf=\"!item.children || item.children.length === 0\"\n [routerLink]=\"item.link\"\n routerLinkActive=\"active\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n </a>\n\n <a\n *ngIf=\"item.children && item.children.length > 0\"\n (click)=\"toggleSubMenu(item)\"\n [class.expanded]=\"item.expanded\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n <mat-icon [class.rotated]=\"item.expanded\">\n {{ item.expanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </a>\n\n <ul\n *ngIf=\"item.children && item.children.length > 0 && item.expanded\"\n class=\"submenu\"\n >\n <li *ngFor=\"let child of item.children\">\n <a [routerLink]=\"child.link\" routerLinkActive=\"active\">\n <mat-icon>{{ child.icon }}</mat-icon>\n <span>{{ child.name }}</span>\n </a>\n </li>\n </ul>\n </li>\n </ng-container>\n </ul>\n </div>\n </mat-nav-list>\n\n <!-- Footer -->\n <div class=\"sidenav-footer\">\n <button mat-button [matMenuTriggerFor]=\"footerMenu\" class=\"footer-button\">\n <div class=\"footer-text\" *ngIf=\"!isMinimized()\">\n <div class=\"company-name\">\n <p>&copy; 2025 AXIS</p>\n </div>\n </div>\n </button>\n <div class=\"version\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n\n <mat-menu #footerMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>swap_horiz</mat-icon>\n {{ '@changeCompany' | translate }}\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n</div>\n", styles: [".profile-section{text-align:center;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;flex-direction:column;position:relative}.profile-section:hover{transform:scale(.98)}.profile-section .profile-button{display:flex;flex-direction:column;align-items:center;background:none;border:none;padding:0;cursor:pointer;width:100%}.profile-image{width:60px;height:60px;border-radius:50%;object-fit:cover;margin:0 auto 8px;display:block;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:all .3s ease}.profile-name{font-weight:500;font-size:1rem;color:inherit;transition:opacity .3s ease;margin-top:8px}:host-context(.minimized) .profile-section{padding:10px 0}:host-context(.minimized) .profile-image{width:40px;height:40px;margin:0 auto}.sidenav-footer{position:static;bottom:0;left:0;right:0;padding:16px;color:inherit;font-size:12px;border-top:1px solid rgba(0,0,0,.1);transition:all .3s ease;display:flex;align-items:center;justify-content:space-between;margin-top:auto}.sidenav-footer .version{font-size:10px;margin-top:4px}.footer-button{border:none;background:none;cursor:pointer}:host-context(.minimized) .version{margin-right:7px}:host-context(.minimized) .sidenav-content-wrapper{overflow:hidden}.sidenav-content-wrapper{position:relative;height:100%;display:flex;flex-direction:column;overflow-x:hidden}.sidebar{flex:1;overflow:auto}.sidebar ul{list-style:none;padding:0;margin:0}.sidebar li{margin-bottom:4px;position:relative}.sidebar li a{display:flex;align-items:center;padding:12px 0 0;border-radius:6px;color:var(--mat-sys-primary);text-decoration:none;transition:all .2s ease;position:relative;overflow:hidden}.sidebar li a:hover{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier)}.sidebar li a.active{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier);font-weight:500}.sidebar li a.active:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--mat-nty-save-record-header-bar);border-radius:3px 0 0 3px}.sidebar mat-icon{font-size:20px;width:20px;height:20px;color:inherit}.sidebar span{font-size:.875rem;white-space:nowrap}.submenu{padding-left:12px;margin-top:4px}.submenu li a{padding:10px 16px 0 20px}.submenu mat-icon{font-size:18px}.sidebar li a mat-icon:last-child{margin-left:auto;margin-right:0;font-size:18px;color:#5f6368}:host-context(.minimized) .sidebar li a{justify-content:center;padding:12px 0}:host-context(.minimized) .sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:50%;z-index:999}:host-context(.minimized) .sidebar mat-icon{margin-right:0}:host-context(.minimized) .sidebar span,:host-context(.minimized) .sidebar li a mat-icon:last-child{display:none}:host-context(.minimized) .submenu{display:none}.sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:1px;z-index:999}.search-input{margin-top:10px}\n"] }]
2978
+ ], template: "<div class=\"sidenav-content-wrapper\">\n <!-- Minimize Icon -->\n <button mat-icon-button (click)=\"onToggleMinimize()\" class=\"minimize-button\">\n <mat-icon class=\"minimize-icon\">\n {{ isMinimized() ? \"chevron_right\" : \"chevron_left\" }}\n </mat-icon>\n </button>\n\n <!-- Profile -->\n <div class=\"profile-section\">\n <button mat-button [matMenuTriggerFor]=\"profileMenu\" class=\"profile-button\">\n <img [src]=\"profileImage()\" [alt]=\"username()\" class=\"profile-image\" />\n @if(!isMinimized()){\n <div class=\"profile-info\">\n <p class=\"profile-name\">{{ username() }}</p>\n </div>\n }\n </button>\n\n <mat-menu #profileMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>account_circle</mat-icon>\n <span>{{ '@profile' | translate }}</span>\n </button>\n <button mat-menu-item mat-button disabled>\n <mat-icon>swap_horiz</mat-icon>\n <span>{{ '@changeCompany' | translate }}</span>\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n </div>\n\n <!-- Search Input -->\n <ntyui-search-input\n class=\"search-input\"\n [label]=\"'@search' | translate\"\n [placeholder]=\"'@placeholderSearch' | translate\"\n [appearance]=\"'outline'\"\n *ngIf=\"!isMinimized()\"\n (search)=\"onSearch($event)\"\n >\n </ntyui-search-input>\n\n <!-- Menu -->\n <mat-nav-list *ngIf=\"!isMinimized()\">\n <div class=\"sidebar\">\n <ul>\n <!-- Recursive menu render -->\n <ng-container\n *ngTemplateOutlet=\"menuItemsTemplate; context: { $implicit: filteredMenuItems(), level: 0 }\"\n ></ng-container>\n </ul>\n </div>\n </mat-nav-list>\n\n <!-- Footer -->\n <div class=\"sidenav-footer\">\n <button mat-button [matMenuTriggerFor]=\"footerMenu\" class=\"footer-button\">\n @if (!isMinimized()) {\n <div class=\"footer-text\">\n <div class=\"company-name\">\n <p>&copy; 2025 AXIS</p>\n </div>\n </div>\n }\n </button>\n <div class=\"version\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n\n <mat-menu #footerMenu=\"matMenu\" xPosition=\"before\">\n <button mat-menu-item disabled>\n <mat-icon>swap_horiz</mat-icon>\n {{ '@changeCompany' | translate }}\n </button>\n <button mat-menu-item mat-button (click)=\"logout()\">\n <mat-icon>logout</mat-icon>\n <span>{{ '@logout' | translate }}</span>\n </button>\n </mat-menu>\n</div>\n\n<!-- Recursive Menu Template -->\n<ng-template #menuItemsTemplate let-items let-level=\"level\">\n @for (item of items; track item.name) {\n <li [class]=\"'menu-level-' + level\">\n <!-- Leaf node (no children) -->\n @if (!item.children || item.children.length === 0) {\n <a\n [routerLink]=\"item.link\"\n routerLinkActive=\"active\"\n [class]=\"'menu-link level-' + level\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n </a>\n }\n\n <!-- Parent node with children -->\n @if (item.children && item.children.length > 0) {\n <a\n (click)=\"toggleSubMenu(item)\"\n [class.expanded]=\"item.expanded\"\n [class]=\"'menu-link has-children level-' + level\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n <span>{{ item.name }}</span>\n <mat-icon [class.rotated]=\"item.expanded\" class=\"expand-icon\">\n {{ item.expanded ? 'expand_less' : 'expand_more' }}\n </mat-icon>\n </a>\n }\n\n <!-- Recursive submenu -->\n @if (item.children && item.children.length > 0 && item.expanded) {\n <ul [class]=\"'submenu level-' + (level + 1)\">\n <ng-container\n *ngTemplateOutlet=\"menuItemsTemplate; context: { $implicit: item.children, level: level + 1 }\"\n ></ng-container>\n </ul>\n }\n </li>\n }\n</ng-template>\n", styles: [".profile-section{text-align:center;cursor:pointer;transition:all .3s ease;display:flex;align-items:center;flex-direction:column;position:relative}.profile-section:hover{transform:scale(.98)}.profile-section .profile-button{display:flex;flex-direction:column;align-items:center;background:none;border:none;padding:0;cursor:pointer;width:100%}.profile-image{width:60px;height:60px;border-radius:50%;object-fit:cover;margin:0 auto 8px;display:block;border:2px solid white;box-shadow:0 2px 4px #0000001a;transition:all .3s ease}.profile-name{font-weight:500;font-size:1rem;color:inherit;transition:opacity .3s ease;margin-top:8px}:host-context(.minimized) .profile-section{padding:10px 0}:host-context(.minimized) .profile-image{width:40px;height:40px;margin:0 auto}.sidenav-footer{position:static;bottom:0;left:0;right:0;padding:16px;color:inherit;font-size:12px;border-top:1px solid rgba(0,0,0,.1);transition:all .3s ease;display:flex;align-items:center;justify-content:space-between;margin-top:auto}.sidenav-footer .version{font-size:10px;margin-top:4px}.footer-button{border:none;background:none;cursor:pointer}:host-context(.minimized) .version{margin-right:7px}:host-context(.minimized) .sidenav-content-wrapper{overflow:hidden}.sidenav-content-wrapper{position:relative;height:100%;display:flex;flex-direction:column;overflow-x:hidden}.sidebar{flex:1;overflow:auto}.sidebar ul{list-style:none;padding:0;margin:0}.sidebar li{margin-bottom:4px;position:relative}.sidebar li a{display:flex;align-items:center;padding:12px 0 0;border-radius:6px;color:var(--mat-sys-primary);text-decoration:none;transition:all .2s ease;position:relative;overflow:hidden}.sidebar li a:hover{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier)}.sidebar li a.active{background-color:var(--mat-nty-save-record-header-bar);color:var(--mat-nty-save-record-identifier);font-weight:500}.sidebar li a.active:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:3px;background-color:var(--mat-nty-save-record-header-bar);border-radius:3px 0 0 3px}.sidebar mat-icon{font-size:20px;width:20px;height:20px;color:inherit}.sidebar span{font-size:.875rem;white-space:nowrap}.menu-link.level-2{margin-left:20px;font-size:.82rem}.menu-link.level-3{margin-left:20px;font-size:.8rem}.menu-link.level-4{margin-left:20px;font-size:.78rem}.submenu{padding-left:12px;margin-top:4px}.submenu li a{padding:10px 16px 0 20px}.submenu mat-icon{font-size:18px}.sidebar li a mat-icon:last-child{margin-left:auto;margin-right:0;font-size:18px;color:#5f6368}:host-context(.minimized) .sidebar li a{justify-content:center;padding:12px 0}:host-context(.minimized) .sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:50%;z-index:999}:host-context(.minimized) .sidebar mat-icon{margin-right:0}:host-context(.minimized) .sidebar span,:host-context(.minimized) .sidebar li a mat-icon:last-child{display:none}:host-context(.minimized) .submenu{display:none}.sidenav-content-wrapper button[mat-icon-button]{position:absolute;right:-8px;top:1px;z-index:999}.search-input{margin-top:10px}\n"] }]
2965
2979
  }], ctorParameters: () => [], propDecorators: { isMinimized: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMinimized", required: false }] }], toggleMinimize: [{ type: i0.Output, args: ["toggleMinimize"] }] } });
2966
2980
 
2967
2981
  class Theme {
@@ -3071,6 +3085,7 @@ class Toolbar {
3071
3085
  themeService = inject(Theme);
3072
3086
  colorPaletteService = inject(ColorPalette);
3073
3087
  i18nService = inject(I18nService);
3088
+ router = inject(Router);
3074
3089
  toggleSidenav = output();
3075
3090
  onToggleSidenav() {
3076
3091
  this.toggleSidenav.emit();
@@ -3085,7 +3100,14 @@ class Toolbar {
3085
3100
  }
3086
3101
  setLanguage(language) {
3087
3102
  this.i18nService.language = language;
3088
- window.location.reload();
3103
+ setTimeout(() => {
3104
+ this.router.navigateByUrl('/', { skipLocationChange: true }).then(() => {
3105
+ this.router.navigate([window.location.pathname]);
3106
+ });
3107
+ }, 500);
3108
+ setTimeout(() => {
3109
+ window.location.reload();
3110
+ }, 500);
3089
3111
  }
3090
3112
  getCurrentLanguageIcon() {
3091
3113
  switch (this.i18nService.language) {
@@ -3118,10 +3140,124 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
3118
3140
  MatToolbarModule,
3119
3141
  CommonModule,
3120
3142
  TitleCasePipe,
3121
- TranslateModule
3143
+ TranslateModule,
3122
3144
  ], template: "<mat-toolbar class=\"sidenav-header\">\n <div class=\"left-section\">\n <button mat-icon-button (click)=\"onToggleSidenav()\" class=\"menu-button\">\n <mat-icon>menu</mat-icon>\n </button>\n <span>{{'app_name' | translate }}</span>\n\n <!-- Language Selection -->\n <div class=\"language-toggle\">\n <button\n *ngIf=\"icon; else text\"\n mat-icon-button\n [matMenuTriggerFor]=\"languageMenu\"\n >\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n <ng-template #text>\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n </ng-template>\n </div>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let language of languages\"\n (click)=\"setLanguage(language)\"\n >\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n </mat-menu>\n </div>\n\n <div class=\"spacer\"></div>\n\n <div class=\"flex-stretch\"></div>\n <button\n mat-icon-button\n [mat-menu-trigger-for]=\"themeMenu\"\n class=\"theme-button\"\n >\n <mat-icon>{{ themeService.selectedTheme()?.icon }}</mat-icon>\n </button>\n <mat-menu #themeMenu=\"matMenu\">\n @for (theme of themeService.getThemes(); track theme.name) {\n <button\n [class.selected-theme]=\"themeService.selectedTheme()?.name === theme.name\"\n mat-menu-item\n (click)=\"themeService.setTheme(theme.name)\"\n >\n <mat-icon>{{ theme.icon }}</mat-icon>\n <span>{{ theme.name | titlecase }}</span>\n </button>\n }\n </mat-menu>\n <button\n mat-icon-button\n [matMenuTriggerFor]=\"customThemeMenu\"\n class=\"custom-theme-button\"\n >\n <mat-icon>format_color_fill</mat-icon>\n </button>\n <mat-menu #customThemeMenu=\"matMenu\">\n @for (customTheme of colorPaletteService.getThemes(); track customTheme.id)\n {\n <button\n mat-menu-item\n (click)=\"colorPaletteService.setTheme(customTheme.id)\"\n >\n <div class=\"theme-menu-item\">\n <div\n class=\"color-preview\"\n [style.background-color]=\"customTheme.primary\"\n ></div>\n <span>{{ customTheme.displayName }}</span>\n </div>\n </button>\n }\n </mat-menu>\n</mat-toolbar>\n", styles: ["mat-toolbar{position:fixed;top:0;left:0;right:0;z-index:3;box-shadow:0 1px 5px #0000001a;display:flex;align-items:center}.sidenav-header{display:flex;justify-content:space-between;align-items:center;padding:16px;margin:0;font-weight:500}.sidenav-header .left-section{display:flex;align-items:center;gap:16px}.sidenav-header .spacer{flex:1 1 auto}.flex-stretch{flex:1 0 auto}.theme-menu-item{display:flex;align-items:center;gap:12px}.color-preview{width:24px;height:24px;border-radius:50%}::ng-deep .theme-button{border:none;background:none;margin-right:15px;cursor:pointer}::ng-deep .custom-theme-button{border:none;background:none;cursor:pointer}::ng-deep .menu-button{border:none;background:none;cursor:pointer}.language-button{margin:0 auto}::ng-deep button{border:none;background:none;cursor:pointer}\n"] }]
3123
3145
  }], propDecorators: { toggleSidenav: [{ type: i0.Output, args: ["toggleSidenav"] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }, { type: i0.Output, args: ["iconChange"] }] } });
3124
3146
 
3147
+ class NettyBaseApp {
3148
+ i18nService = inject(I18nService);
3149
+ async loadBaseTranslations() {
3150
+ try {
3151
+ const enUSBase = await import('./nettyapps-ntybase-en-USbase-DlNRzuX4.mjs');
3152
+ const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-v9G-AlQ2.mjs');
3153
+ this.i18nService.addTranslations('English', enUSBase.default);
3154
+ this.i18nService.addTranslations('Türkçe', trTRBase.default);
3155
+ }
3156
+ catch (error) {
3157
+ console.error('Error loading base translations in component:', error);
3158
+ throw error;
3159
+ }
3160
+ }
3161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: NettyBaseApp, deps: [], target: i0.ɵɵFactoryTarget.Component });
3162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: NettyBaseApp, isStandalone: true, selector: "ntybase-netty-base-app", ngImport: i0, template: "", styles: [""] });
3163
+ }
3164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: NettyBaseApp, decorators: [{
3165
+ type: Component,
3166
+ args: [{ selector: 'ntybase-netty-base-app', imports: [], template: "" }]
3167
+ }] });
3168
+
3169
+ const ENVIRONMENT_CONFIG = new InjectionToken('ENVIRONMENT_CONFIG');
3170
+ class EnvironmentInfoService {
3171
+ config;
3172
+ constructor(config) {
3173
+ this.config = config;
3174
+ }
3175
+ getEnvironmentInfo() {
3176
+ return this.config;
3177
+ }
3178
+ getApiUrl() {
3179
+ return this.config?.nettyUrls?.apiUrl || '';
3180
+ }
3181
+ getAdminUrl() {
3182
+ return this.config?.nettyUrls?.adminUrl || '';
3183
+ }
3184
+ isProduction() {
3185
+ return this.config?.production || false;
3186
+ }
3187
+ getVersion() {
3188
+ return this.config?.version || 'Unknown';
3189
+ }
3190
+ getSupportedLanguages() {
3191
+ return this.config?.supportedLanguages || [];
3192
+ }
3193
+ getDefaultLanguage() {
3194
+ return this.config?.defaultLanguage || '';
3195
+ }
3196
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: EnvironmentInfoService, deps: [{ token: ENVIRONMENT_CONFIG, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
3197
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: EnvironmentInfoService, providedIn: 'root' });
3198
+ }
3199
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: EnvironmentInfoService, decorators: [{
3200
+ type: Injectable,
3201
+ args: [{
3202
+ providedIn: 'root',
3203
+ }]
3204
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
3205
+ type: Optional
3206
+ }, {
3207
+ type: Inject,
3208
+ args: [ENVIRONMENT_CONFIG]
3209
+ }] }] });
3210
+
3211
+ class EnvironmentInfo {
3212
+ environmentService;
3213
+ showNettyInfo = true;
3214
+ environmentConfig = null;
3215
+ get hasConfig() {
3216
+ return this.environmentConfig !== null;
3217
+ }
3218
+ get version() {
3219
+ return this.environmentService.getVersion();
3220
+ }
3221
+ get isProduction() {
3222
+ return this.environmentService.isProduction();
3223
+ }
3224
+ get defaultLanguage() {
3225
+ return this.environmentService.getDefaultLanguage();
3226
+ }
3227
+ get supportedLanguages() {
3228
+ return this.environmentService.getSupportedLanguages();
3229
+ }
3230
+ get apiUrl() {
3231
+ return this.environmentService.getApiUrl();
3232
+ }
3233
+ get adminUrl() {
3234
+ return this.environmentService.getAdminUrl();
3235
+ }
3236
+ get baseHref() {
3237
+ return this.environmentConfig?.nettyUrls?.baseHref || '';
3238
+ }
3239
+ get application() {
3240
+ return this.environmentConfig?.nettyUrls?.application || '';
3241
+ }
3242
+ constructor(environmentService) {
3243
+ this.environmentService = environmentService;
3244
+ }
3245
+ ngOnInit() {
3246
+ this.environmentConfig = this.environmentService.getEnvironmentInfo();
3247
+ if (!this.hasConfig) {
3248
+ console.warn("Environment konfigürasyonu bulunamadı. ENVIRONMENT_CONFIG token'ı sağlandı mı?");
3249
+ }
3250
+ }
3251
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: EnvironmentInfo, deps: [{ token: EnvironmentInfoService }], target: i0.ɵɵFactoryTarget.Component });
3252
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", 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 <h3>Uygulama Bilgileri</h3>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">Versiyon:</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Ortam:</span>\n <span class=\"value\" [class.prod]=\"isProduction\">\n {{ isProduction ? 'Production' : 'Development' }}\n </span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Varsay\u0131lan Dil:</span>\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Desteklenen Diller:</span>\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n <div class=\"netty-info\" *ngIf=\"showNettyInfo\">\n <h4>Netty Ba\u011Flant\u0131lar\u0131</h4>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">API URL:</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Admin URL:</span>\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Base Href:</span>\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Uygulama:</span>\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n\n <div class=\"no-config\" *ngIf=\"!hasConfig\">\n <p>Environment konfig\u00FCrasyonu bulunamad\u0131</p>\n </div>\n </div>\n</div>\n", styles: [".environment-info{padding:16px;font-family:Arial,sans-serif}.info-card{background:#f5f5f5;border-radius:8px;padding:20px;box-shadow:0 2px 4px #0000001a}h3,h4{margin:0 0 16px;color:#333}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:12px;margin-bottom:16px}.info-item{display:contents}.label{font-weight:700;color:#666}.value{color:#333;word-break:break-all}.value.prod{color:#d32f2f;font-weight:700}.netty-info{border-top:1px solid #ddd;padding-top:16px}.production .info-card{background:#fff3e0;border-left:4px solid #ff9800}.no-config{text-align:center;color:#ff9800;font-weight:700}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
3253
+ }
3254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: EnvironmentInfo, decorators: [{
3255
+ type: Component,
3256
+ args: [{ selector: 'ntybase-environment-info', imports: [CommonModule], template: "<div class=\"environment-info\" [class.production]=\"isProduction\">\n <div class=\"info-card\">\n <h3>Uygulama Bilgileri</h3>\n\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">Versiyon:</span>\n <span class=\"value\">{{ version }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Ortam:</span>\n <span class=\"value\" [class.prod]=\"isProduction\">\n {{ isProduction ? 'Production' : 'Development' }}\n </span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Varsay\u0131lan Dil:</span>\n <span class=\"value\">{{ defaultLanguage }}</span>\n </div>\n\n <div class=\"info-item\">\n <span class=\"label\">Desteklenen Diller:</span>\n <span class=\"value\">{{ supportedLanguages.join(', ') }}</span>\n </div>\n </div>\n\n <div class=\"netty-info\" *ngIf=\"showNettyInfo\">\n <h4>Netty Ba\u011Flant\u0131lar\u0131</h4>\n <div class=\"info-grid\">\n <div class=\"info-item\">\n <span class=\"label\">API URL:</span>\n <span class=\"value\">{{ apiUrl }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Admin URL:</span>\n <span class=\"value\">{{ adminUrl }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Base Href:</span>\n <span class=\"value\">{{ baseHref }}</span>\n </div>\n <div class=\"info-item\">\n <span class=\"label\">Uygulama:</span>\n <span class=\"value\">{{ application }}</span>\n </div>\n </div>\n </div>\n\n <div class=\"no-config\" *ngIf=\"!hasConfig\">\n <p>Environment konfig\u00FCrasyonu bulunamad\u0131</p>\n </div>\n </div>\n</div>\n", styles: [".environment-info{padding:16px;font-family:Arial,sans-serif}.info-card{background:#f5f5f5;border-radius:8px;padding:20px;box-shadow:0 2px 4px #0000001a}h3,h4{margin:0 0 16px;color:#333}.info-grid{display:grid;grid-template-columns:1fr 2fr;gap:12px;margin-bottom:16px}.info-item{display:contents}.label{font-weight:700;color:#666}.value{color:#333;word-break:break-all}.value.prod{color:#d32f2f;font-weight:700}.netty-info{border-top:1px solid #ddd;padding-top:16px}.production .info-card{background:#fff3e0;border-left:4px solid #ff9800}.no-config{text-align:center;color:#ff9800;font-weight:700}\n"] }]
3257
+ }], ctorParameters: () => [{ type: EnvironmentInfoService }], propDecorators: { showNettyInfo: [{
3258
+ type: Input
3259
+ }] } });
3260
+
3125
3261
  class Guid {
3126
3262
  value = this.empty;
3127
3263
  constructor(value) {
@@ -3356,16 +3492,16 @@ class AutoCompletePopupMenu {
3356
3492
  copyToClipboard() {
3357
3493
  if (this.inputValue) {
3358
3494
  this.clipboard.copy(this.inputValue);
3359
- this.alertService.showAlert('@CopiedToClipboard');
3495
+ this.alertService.showAlert('@copiedToClipboard');
3360
3496
  this.Result.emit('Copy');
3361
3497
  }
3362
3498
  }
3363
3499
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: AutoCompletePopupMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
3364
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: AutoCompletePopupMenu, isStandalone: true, selector: "ntybase-auto-complete-popup-menu", inputs: { field: "field", recordGuid: "recordGuid", fieldDisabled: "fieldDisabled", componentPath: "componentPath", inputValue: "inputValue" }, outputs: { Result: "Result" }, ngImport: i0, template: "<div class=\"dialogbase\">\n <div class=\"menu\">\n <ul class=\"list-group\">\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"copyToClipboard()\" class=\"align-line\"\n ><mat-icon>content_copy</mat-icon>{{'@Copy'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoMain()\" class=\"align-line\"\n ><mat-icon>edit</mat-icon>{{'@PopupGotoRecordDefinition'|\n translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoNew()\" class=\"align-line\"\n ><mat-icon>add</mat-icon>{{'@PopupNewRecord'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center\"\n [ngClass]=\"{'menu-item':!fieldDisabled , 'menu-item-disabled':fieldDisabled }\"\n >\n <span (click)=\"gotoLookup()\" class=\"align-line\"\n ><mat-icon>search</mat-icon>{{'@PopupSelectFromList'|translate}}</span\n >\n </li>\n </ul>\n </div>\n</div>\n", styles: [".dialogbase{background:#0000001a;padding:0;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px #00000026}.menu{background:var(--mat-sys-primary-container);padding:0;display:flex;border-radius:inherit}.align-line{display:flex;vertical-align:middle;align-items:center;gap:12px;padding:0 8px}.menu-item{padding:12px 16px;display:flex;vertical-align:middle;cursor:pointer;transition:all .2s ease-out;border-radius:8px;margin:4px;color:var(--mat-sys-on-primary-container)}.menu-item:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.menu-item:hover .mat-icon{color:var(--mat-sys-on-primary);transform:scale(1.05)}.menu-item-disabled,.menu-item-disabled:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);font-style:italic;opacity:.7;cursor:not-allowed}.menu-item-disabled .mat-icon,.menu-item-disabled:hover .mat-icon{color:var(--mat-sys-on-primary)}.mat-icon{transition:all .2s ease-out;font-size:20px;width:20px;height:20px}.list-group{list-style:none;padding:8px;margin:0;width:100%}.list-group-item{background-position:bottom;background-size:100% 1px;background-repeat:no-repeat;padding-bottom:12px;margin-bottom:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
3500
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: AutoCompletePopupMenu, isStandalone: true, selector: "ntybase-auto-complete-popup-menu", inputs: { field: "field", recordGuid: "recordGuid", fieldDisabled: "fieldDisabled", componentPath: "componentPath", inputValue: "inputValue" }, outputs: { Result: "Result" }, ngImport: i0, template: "<div class=\"dialogbase\">\n <div class=\"menu\">\n <ul class=\"list-group\">\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"copyToClipboard()\" class=\"align-line\"\n ><mat-icon>content_copy</mat-icon>{{'@copy'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoMain()\" class=\"align-line\"\n ><mat-icon>edit</mat-icon>{{'@popupGotoRecordDefinition'|\n translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoNew()\" class=\"align-line\"\n ><mat-icon>add</mat-icon>{{'@popupNewRecord'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center\"\n [ngClass]=\"{'menu-item':!fieldDisabled , 'menu-item-disabled':fieldDisabled }\"\n >\n <span (click)=\"gotoLookup()\" class=\"align-line\"\n ><mat-icon>search</mat-icon>{{'@popupSelectFromList'|translate}}</span\n >\n </li>\n </ul>\n </div>\n</div>\n", styles: [".dialogbase{background:#0000001a;padding:0;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px #00000026}.menu{background:var(--mat-sys-primary-container);padding:0;display:flex;border-radius:inherit}.align-line{display:flex;vertical-align:middle;align-items:center;gap:12px;padding:0 8px}.menu-item{padding:12px 16px;display:flex;vertical-align:middle;cursor:pointer;transition:all .2s ease-out;border-radius:8px;margin:4px;color:var(--mat-sys-on-primary-container)}.menu-item:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.menu-item:hover .mat-icon{color:var(--mat-sys-on-primary);transform:scale(1.05)}.menu-item-disabled,.menu-item-disabled:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);font-style:italic;opacity:.7;cursor:not-allowed}.menu-item-disabled .mat-icon,.menu-item-disabled:hover .mat-icon{color:var(--mat-sys-on-primary)}.mat-icon{transition:all .2s ease-out;font-size:20px;width:20px;height:20px}.list-group{list-style:none;padding:8px;margin:0;width:100%}.list-group-item{background-position:bottom;background-size:100% 1px;background-repeat:no-repeat;padding-bottom:12px;margin-bottom:4px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
3365
3501
  }
3366
3502
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: AutoCompletePopupMenu, decorators: [{
3367
3503
  type: Component,
3368
- args: [{ selector: 'ntybase-auto-complete-popup-menu', imports: [CommonModule, ReactiveFormsModule, MatIconModule, TranslateModule], encapsulation: ViewEncapsulation.None, template: "<div class=\"dialogbase\">\n <div class=\"menu\">\n <ul class=\"list-group\">\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"copyToClipboard()\" class=\"align-line\"\n ><mat-icon>content_copy</mat-icon>{{'@Copy'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoMain()\" class=\"align-line\"\n ><mat-icon>edit</mat-icon>{{'@PopupGotoRecordDefinition'|\n translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoNew()\" class=\"align-line\"\n ><mat-icon>add</mat-icon>{{'@PopupNewRecord'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center\"\n [ngClass]=\"{'menu-item':!fieldDisabled , 'menu-item-disabled':fieldDisabled }\"\n >\n <span (click)=\"gotoLookup()\" class=\"align-line\"\n ><mat-icon>search</mat-icon>{{'@PopupSelectFromList'|translate}}</span\n >\n </li>\n </ul>\n </div>\n</div>\n", styles: [".dialogbase{background:#0000001a;padding:0;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px #00000026}.menu{background:var(--mat-sys-primary-container);padding:0;display:flex;border-radius:inherit}.align-line{display:flex;vertical-align:middle;align-items:center;gap:12px;padding:0 8px}.menu-item{padding:12px 16px;display:flex;vertical-align:middle;cursor:pointer;transition:all .2s ease-out;border-radius:8px;margin:4px;color:var(--mat-sys-on-primary-container)}.menu-item:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.menu-item:hover .mat-icon{color:var(--mat-sys-on-primary);transform:scale(1.05)}.menu-item-disabled,.menu-item-disabled:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);font-style:italic;opacity:.7;cursor:not-allowed}.menu-item-disabled .mat-icon,.menu-item-disabled:hover .mat-icon{color:var(--mat-sys-on-primary)}.mat-icon{transition:all .2s ease-out;font-size:20px;width:20px;height:20px}.list-group{list-style:none;padding:8px;margin:0;width:100%}.list-group-item{background-position:bottom;background-size:100% 1px;background-repeat:no-repeat;padding-bottom:12px;margin-bottom:4px}\n"] }]
3504
+ args: [{ selector: 'ntybase-auto-complete-popup-menu', imports: [CommonModule, ReactiveFormsModule, MatIconModule, TranslateModule], encapsulation: ViewEncapsulation.None, template: "<div class=\"dialogbase\">\n <div class=\"menu\">\n <ul class=\"list-group\">\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"copyToClipboard()\" class=\"align-line\"\n ><mat-icon>content_copy</mat-icon>{{'@copy'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoMain()\" class=\"align-line\"\n ><mat-icon>edit</mat-icon>{{'@popupGotoRecordDefinition'|\n translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center menu-item\"\n >\n <span (click)=\"gotoNew()\" class=\"align-line\"\n ><mat-icon>add</mat-icon>{{'@popupNewRecord'| translate}}</span\n >\n </li>\n <li\n class=\"list-group-item list-group-item-action d-flex justify-content-between align-items-center\"\n [ngClass]=\"{'menu-item':!fieldDisabled , 'menu-item-disabled':fieldDisabled }\"\n >\n <span (click)=\"gotoLookup()\" class=\"align-line\"\n ><mat-icon>search</mat-icon>{{'@popupSelectFromList'|translate}}</span\n >\n </li>\n </ul>\n </div>\n</div>\n", styles: [".dialogbase{background:#0000001a;padding:0;border-radius:12px;overflow:hidden;box-shadow:0 4px 20px #00000026}.menu{background:var(--mat-sys-primary-container);padding:0;display:flex;border-radius:inherit}.align-line{display:flex;vertical-align:middle;align-items:center;gap:12px;padding:0 8px}.menu-item{padding:12px 16px;display:flex;vertical-align:middle;cursor:pointer;transition:all .2s ease-out;border-radius:8px;margin:4px;color:var(--mat-sys-on-primary-container)}.menu-item:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);transform:translateY(-2px);box-shadow:0 2px 8px #0000001a}.menu-item:hover .mat-icon{color:var(--mat-sys-on-primary);transform:scale(1.05)}.menu-item-disabled,.menu-item-disabled:hover{background:var(--mat-sys-on-primary-fixed);color:var(--mat-sys-on-primary);font-style:italic;opacity:.7;cursor:not-allowed}.menu-item-disabled .mat-icon,.menu-item-disabled:hover .mat-icon{color:var(--mat-sys-on-primary)}.mat-icon{transition:all .2s ease-out;font-size:20px;width:20px;height:20px}.list-group{list-style:none;padding:8px;margin:0;width:100%}.list-group-item{background-position:bottom;background-size:100% 1px;background-repeat:no-repeat;padding-bottom:12px;margin-bottom:4px}\n"] }]
3369
3505
  }], propDecorators: { field: [{
3370
3506
  type: Input
3371
3507
  }], recordGuid: [{
@@ -3674,5 +3810,5 @@ class NettyFilter {
3674
3810
  * Generated bundle index. Do not edit.
3675
3811
  */
3676
3812
 
3677
- export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, AutoComplete, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, ColorPalette, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ExcelImportBase, ForgotPassword, Guid, HttpError403, HttpError404, LeftSidenav, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridSaveBase, NettyAgGridService, NettyFilter, NettyHelper, NettyMenuService, Ntybase, NtybaseModule, SelectionItem, Theme, Toolbar, UrlHelperService };
3813
+ export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, AutoComplete, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, ColorPalette, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ENVIRONMENT_CONFIG, EnvironmentInfo, EnvironmentInfoService, ExcelImportBase, ForgotPassword, Guid, HttpError403, HttpError404, LeftSidenav, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridSaveBase, NettyAgGridService, NettyBaseApp, NettyFilter, NettyHelper, NettyMenuService, Ntybase, NtybaseModule, SelectionItem, Theme, Toolbar, UrlHelperService };
3678
3814
  //# sourceMappingURL=nettyapps-ntybase.mjs.map