@nettyapps/ntybase 21.1.40 → 21.1.41

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.
@@ -12,13 +12,12 @@ import * as i1$2 from '@angular/material/snack-bar';
12
12
  import { MatSnackBarModule } from '@angular/material/snack-bar';
13
13
  import * as i1$1 from '@ngx-translate/core';
14
14
  import { TranslateModule, TranslateService } from '@ngx-translate/core';
15
- import * as i1$5 from '@angular/common';
15
+ import * as i1$4 from '@angular/common';
16
16
  import { CommonModule, DatePipe, Location, DecimalPipe } from '@angular/common';
17
17
  import { Title } from '@angular/platform-browser';
18
18
  import * as i2$2 from '@nettyapps/ntycontract';
19
19
  import { injectNettyStandardFilterProxy, EnvironmentProxy, injectNettyStandardProxy, injectNettyStandardLogProxy } from '@nettyapps/ntycontract';
20
20
  import { I18nService } from '@nettyapps/ntyi18n';
21
- import { ExcelLogViewer as ExcelLogViewer$1 } from '@nettyapps/ntyux';
22
21
  import { Router, ActivatedRoute } from '@angular/router';
23
22
  import { ModuleRegistry, AllCommunityModule, ClientSideRowModelModule, HighlightChangesModule, TextFilterModule, NumberFilterModule, DateFilterModule } from 'ag-grid-community';
24
23
  import { themeQuartz, StatusBarModule, ClipboardModule, ExcelExportModule, ColumnMenuModule, ContextMenuModule, CellSelectionModule, RowSelectionModule, SetFilterModule, MultiFilterModule } from 'ag-grid-enterprise';
@@ -30,14 +29,14 @@ import * as i1$3 from '@angular/common/http';
30
29
  import { HttpClient, HttpErrorResponse, HttpResponse, HTTP_INTERCEPTORS, HttpHeaders } from '@angular/common/http';
31
30
  import { Mutex } from 'async-mutex';
32
31
  import { toSignal } from '@angular/core/rxjs-interop';
32
+ import * as i1$5 from '@angular/forms';
33
+ import { FormsModule, FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
34
+ import { AgGridAngular } from 'ag-grid-angular';
35
+ import { NettyUIButton, NettyUIFilterButton } from '@nettyapps/ntyui';
33
36
  import { catchError as catchError$1, map as map$1, take, finalize as finalize$1 } from 'rxjs/operators';
34
- import * as i1$4 from '@angular/forms';
35
- import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
36
37
  import * as i3$1 from '@angular/material/input';
37
38
  import { MatInputModule } from '@angular/material/input';
38
39
  import { MatFormFieldModule } from '@angular/material/form-field';
39
- import { AgGridAngular } from 'ag-grid-angular';
40
- import { NettyUIButton, NettyUIFilterButton } from '@nettyapps/ntyui';
41
40
 
42
41
  class ConfirmDialog {
43
42
  dialogRef = inject((MatDialogRef));
@@ -2152,1397 +2151,1409 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
2152
2151
  args: [{ selector: 'ntybase-ag-grid-list-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridListBase' } }]
2153
2152
  }], ctorParameters: () => [] });
2154
2153
 
2155
- class ExcelImportBase extends NettyAgGridListBase {
2156
- isFileSelectionHidden = signal(false, ...(ngDevMode ? [{ debugName: "isFileSelectionHidden" }] : []));
2157
- isFileValid = signal(false, ...(ngDevMode ? [{ debugName: "isFileValid" }] : []));
2158
- logs = signal([], ...(ngDevMode ? [{ debugName: "logs" }] : []));
2159
- hasLogs = computed(() => this.logs().length > 0, ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
2160
- logDialog = inject(MatDialog);
2161
- parser = new ExcelParser([]);
2162
- // override methods
2163
- onBtnClick(e) { }
2164
- loadData() { }
2165
- // Methods
2166
- onFilesSelected(evt) {
2167
- const files = Array.isArray(evt) ? evt : evt.target.files;
2168
- if (!files || files.length !== 1) {
2154
+ class RangeNumberFilter {
2155
+ params;
2156
+ filterText = '';
2157
+ conditions = [];
2158
+ agInit(params) {
2159
+ this.params = params;
2160
+ }
2161
+ onFilterTextChanged(event) {
2162
+ this.filterText = event.target.value;
2163
+ this.parseFilterText();
2164
+ this.params.filterChangedCallback();
2165
+ }
2166
+ parseFilterText() {
2167
+ this.conditions = [];
2168
+ if (!this.filterText.trim()) {
2169
2169
  return;
2170
2170
  }
2171
- const file = files[0];
2172
- if (file) {
2173
- this.recordList.set([]);
2174
- this.logs.set([]);
2175
- this.parser.parse(file).then(result => {
2176
- this.recordList.set(result.data);
2177
- this.logs.set(result.logs);
2178
- this.isFileSelectionHidden.set(true);
2179
- if (result.logs.length > 0)
2180
- this.showLogs();
2181
- });
2171
+ const parts = this.filterText
2172
+ .split(',')
2173
+ .map((part) => part.trim())
2174
+ .filter((part) => part !== '');
2175
+ for (const part of parts) {
2176
+ // Hariç tutma kontrolü (! ile başlıyor mu)
2177
+ if (part.startsWith('!')) {
2178
+ const excludePart = part.substring(1).trim();
2179
+ // Hariç tutma için aralık kontrolü
2180
+ if (excludePart.includes('..')) {
2181
+ const rangeParts = excludePart.split('..');
2182
+ if (rangeParts.length === 2) {
2183
+ const minStr = rangeParts[0].trim();
2184
+ const maxStr = rangeParts[1].trim();
2185
+ // !..10 formatı (max hariç)
2186
+ if (minStr === '' && maxStr !== '') {
2187
+ const max = Number(maxStr);
2188
+ if (!isNaN(max)) {
2189
+ this.conditions.push({
2190
+ type: 'exclude',
2191
+ min: -Infinity,
2192
+ max: max,
2193
+ });
2194
+ }
2195
+ }
2196
+ // !10.. formatı (min hariç)
2197
+ else if (minStr !== '' && maxStr === '') {
2198
+ const min = Number(minStr);
2199
+ if (!isNaN(min)) {
2200
+ this.conditions.push({
2201
+ type: 'exclude',
2202
+ min: min,
2203
+ max: Infinity,
2204
+ });
2205
+ }
2206
+ }
2207
+ // !min..max formatı (aralık hariç)
2208
+ else if (minStr !== '' && maxStr !== '') {
2209
+ const min = Number(minStr);
2210
+ const max = Number(maxStr);
2211
+ if (!isNaN(min) && !isNaN(max)) {
2212
+ this.conditions.push({
2213
+ type: 'exclude',
2214
+ min: Math.min(min, max),
2215
+ max: Math.max(min, max),
2216
+ });
2217
+ }
2218
+ }
2219
+ }
2220
+ }
2221
+ else {
2222
+ // Tek değer hariç tutma
2223
+ const value = Number(excludePart);
2224
+ if (!isNaN(value)) {
2225
+ this.conditions.push({
2226
+ type: 'exclude',
2227
+ value: value,
2228
+ });
2229
+ }
2230
+ }
2231
+ }
2232
+ // Aralık kontrolü (.. içeriyor mu)
2233
+ else if (part.includes('..')) {
2234
+ const rangeParts = part.split('..');
2235
+ if (rangeParts.length === 2) {
2236
+ const minStr = rangeParts[0].trim();
2237
+ const maxStr = rangeParts[1].trim();
2238
+ // ..10 formatı (max belirtilmiş)
2239
+ if (minStr === '' && maxStr !== '') {
2240
+ const max = Number(maxStr);
2241
+ if (!isNaN(max)) {
2242
+ this.conditions.push({
2243
+ type: 'range',
2244
+ min: -Infinity,
2245
+ max: max,
2246
+ });
2247
+ }
2248
+ }
2249
+ // 10.. formatı (min belirtilmiş)
2250
+ else if (minStr !== '' && maxStr === '') {
2251
+ const min = Number(minStr);
2252
+ if (!isNaN(min)) {
2253
+ this.conditions.push({
2254
+ type: 'range',
2255
+ min: min,
2256
+ max: Infinity,
2257
+ });
2258
+ }
2259
+ }
2260
+ // min..max formatı
2261
+ else if (minStr !== '' && maxStr !== '') {
2262
+ const min = Number(minStr);
2263
+ const max = Number(maxStr);
2264
+ if (!isNaN(min) && !isNaN(max)) {
2265
+ this.conditions.push({
2266
+ type: 'range',
2267
+ min: Math.min(min, max),
2268
+ max: Math.max(min, max),
2269
+ });
2270
+ }
2271
+ }
2272
+ }
2273
+ }
2274
+ else {
2275
+ // Tek değer kontrolü
2276
+ const value = Number(part);
2277
+ if (!isNaN(value)) {
2278
+ this.conditions.push({
2279
+ type: 'value',
2280
+ value: value,
2281
+ });
2282
+ }
2283
+ }
2182
2284
  }
2183
2285
  }
2184
- downloadSampleExcel() {
2185
- this.parser.generateSampleExcel();
2186
- }
2187
- showLogs() {
2188
- const dialogRef = this.logDialog.open(ExcelLogViewer$1, {
2189
- height: '70%',
2190
- width: '90%',
2191
- maxWidth: '100vw',
2192
- maxHeight: '100vh'
2193
- });
2194
- dialogRef.componentInstance.setParseData(this.logs());
2195
- dialogRef.componentInstance.selectedElement.subscribe((element) => {
2196
- dialogRef.close();
2286
+ doesFilterPass(params) {
2287
+ const cellValue = this.params.getValue(params.node);
2288
+ // Eğer filtre yoksa tüm satırları göster
2289
+ if (this.conditions.length === 0) {
2290
+ return true;
2291
+ }
2292
+ // Hücre değeri null/undefined ise veya sayı değilse filtrele
2293
+ if (cellValue == null || typeof cellValue !== 'number') {
2294
+ return false;
2295
+ }
2296
+ // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
2297
+ const passesAnyCondition = this.conditions.some((condition) => {
2298
+ if (condition.type === 'range' &&
2299
+ condition.min !== undefined &&
2300
+ condition.max !== undefined) {
2301
+ // Aralık koşulu: değer aralık içinde olmalı
2302
+ return cellValue >= condition.min && cellValue <= condition.max;
2303
+ }
2304
+ else if (condition.type === 'value' && condition.value !== undefined) {
2305
+ // Değer koşulu: değer eşit olmalı
2306
+ return cellValue === condition.value;
2307
+ }
2308
+ else if (condition.type === 'exclude') {
2309
+ if (condition.value !== undefined) {
2310
+ // Tek değer hariç tutma: değer eşit olmamalı
2311
+ return cellValue !== condition.value;
2312
+ }
2313
+ else if (condition.min !== undefined && condition.max !== undefined) {
2314
+ // Aralık hariç tutma: değer aralık dışında olmalı
2315
+ return !(cellValue >= condition.min && cellValue <= condition.max);
2316
+ }
2317
+ }
2318
+ return false;
2197
2319
  });
2320
+ return passesAnyCondition;
2198
2321
  }
2199
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelImportBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2200
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ExcelImportBase, isStandalone: true, selector: "ntybase-excel-import-base", usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2201
- }
2202
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelImportBase, decorators: [{
2203
- type: Component,
2204
- args: [{ selector: 'ntybase-excel-import-base', imports: [], template: `` }]
2205
- }] });
2206
-
2207
- class Ntybase {
2208
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Ntybase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2209
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: Ntybase, isStandalone: false, selector: "lib-ntybase", ngImport: i0, template: `
2210
- <p>
2211
- ntybase works!
2212
- </p>
2213
- `, isInline: true, styles: [""] });
2322
+ isFilterActive() {
2323
+ return this.conditions.length > 0;
2324
+ }
2325
+ getModel() {
2326
+ if (this.isFilterActive()) {
2327
+ return {
2328
+ filterType: 'custom',
2329
+ filterText: this.filterText,
2330
+ conditions: this.conditions,
2331
+ };
2332
+ }
2333
+ return null;
2334
+ }
2335
+ setModel(model) {
2336
+ if (model && model.filterText) {
2337
+ this.filterText = model.filterText;
2338
+ this.conditions = model.conditions || [];
2339
+ }
2340
+ else {
2341
+ this.filterText = '';
2342
+ this.conditions = [];
2343
+ }
2344
+ }
2345
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeNumberFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2346
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeNumberFilter, isStandalone: true, selector: "ntybase-range-number-filter", host: { attributes: { "ntybase-id": "RangeNumberFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
2214
2347
  }
2215
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Ntybase, decorators: [{
2348
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeNumberFilter, decorators: [{
2216
2349
  type: Component,
2217
- args: [{ selector: 'lib-ntybase', standalone: false, template: `
2218
- <p>
2219
- ntybase works!
2220
- </p>
2221
- ` }]
2350
+ args: [{ selector: 'ntybase-range-number-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeNumberFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n" }]
2222
2351
  }] });
2223
2352
 
2224
- const credentialsKey = 'credentials';
2225
- class CredentialsService {
2226
- _credentials = null;
2227
- constructor() {
2228
- const savedCredentials = sessionStorage.getItem(credentialsKey) ||
2229
- localStorage.getItem(credentialsKey);
2230
- if (savedCredentials) {
2231
- this._credentials = JSON.parse(savedCredentials);
2232
- }
2233
- }
2234
- /**
2235
- * Checks is the user is authenticated.
2236
- * @return True if the user is authenticated.
2237
- */
2238
- isAuthenticated() {
2239
- return !!this.credentials;
2240
- }
2241
- /**
2242
- * Gets the user credentials.
2243
- * @return The user credentials or null if the user is not authenticated.
2244
- */
2245
- get credentials() {
2246
- return this._credentials;
2353
+ class RangeStringFilter {
2354
+ params;
2355
+ filterText = '';
2356
+ conditions = [];
2357
+ agInit(params) {
2358
+ this.params = params;
2247
2359
  }
2248
- get token() {
2249
- return this._credentials?.token ?? null;
2360
+ onFilterTextChanged(event) {
2361
+ this.filterText = event.target.value;
2362
+ this.parseFilterText();
2363
+ this.params.filterChangedCallback();
2250
2364
  }
2251
- /**
2252
- * Sets the user credentials.
2253
- * The credentials may be persisted across sessions by setting the `remember` parameter to true.
2254
- * Otherwise, the credentials are only persisted for the current session.
2255
- * @param credentials The user credentials.
2256
- * @param remember True to remember credentials across sessions.
2257
- */
2258
- setCredentials(credentials, remember) {
2259
- this._credentials = credentials || null;
2260
- if (credentials) {
2261
- const storage = remember ? localStorage : sessionStorage;
2262
- storage.setItem(credentialsKey, JSON.stringify(credentials));
2365
+ parseFilterText() {
2366
+ this.conditions = [];
2367
+ if (!this.filterText.trim()) {
2368
+ return;
2263
2369
  }
2264
- else {
2265
- sessionStorage.removeItem(credentialsKey);
2266
- localStorage.removeItem(credentialsKey);
2370
+ const parts = this.filterText
2371
+ .split(',')
2372
+ .map((part) => part.trim())
2373
+ .filter((part) => part !== '');
2374
+ for (const part of parts) {
2375
+ // "!" ile başlayan olumsuz koşul kontrolü
2376
+ if (part.startsWith('!')) {
2377
+ const positiveCondition = part.slice(1);
2378
+ const positiveParsed = this.parseSingleCondition(positiveCondition);
2379
+ if (positiveParsed) {
2380
+ this.conditions.push({
2381
+ type: 'not',
2382
+ condition: positiveParsed,
2383
+ });
2384
+ }
2385
+ continue;
2386
+ }
2387
+ const parsedCondition = this.parseSingleCondition(part);
2388
+ if (parsedCondition) {
2389
+ this.conditions.push(parsedCondition);
2390
+ }
2267
2391
  }
2268
2392
  }
2269
- /** Get Credentials
2270
- *
2271
- * @returns
2272
- */
2273
- getCredentials() {
2274
- let _credentialsString = sessionStorage.getItem(credentialsKey);
2275
- if (_credentialsString == null || _credentialsString == '') {
2276
- _credentialsString = localStorage.getItem(credentialsKey);
2393
+ parseSingleCondition(condition) {
2394
+ // Regex kontrolü ($$ ile başlıyorsa)
2395
+ if (condition.startsWith('$$')) {
2396
+ const regexPattern = condition.slice(2);
2397
+ if (regexPattern) {
2398
+ return {
2399
+ type: 'regex',
2400
+ pattern: regexPattern,
2401
+ };
2402
+ }
2277
2403
  }
2278
- return JSON.parse(_credentialsString ?? '');
2279
- }
2280
- /** Get the token if available otherwise return empty string
2281
- *
2282
- * @returns
2283
- */
2284
- getToken() {
2285
- try {
2286
- let _credentials = this.getCredentials();
2287
- return _credentials.token;
2404
+ // Aralık kontrolü (.. içeriyor mu) - ama $$.. şeklinde değilse
2405
+ if (condition.includes('..') && !condition.startsWith('$$')) {
2406
+ const rangeParts = condition.split('..');
2407
+ if (rangeParts.length === 2) {
2408
+ const start = rangeParts[0].trim();
2409
+ const end = rangeParts[1].trim();
2410
+ if (start && end) {
2411
+ return {
2412
+ type: 'range',
2413
+ start: start.toLowerCase(),
2414
+ end: end.toLowerCase(),
2415
+ };
2416
+ }
2417
+ }
2288
2418
  }
2289
- catch (error) {
2290
- return '';
2419
+ // Tek karakter kontrolü (? ile)
2420
+ else if (condition.includes('?') && !condition.startsWith('$$')) {
2421
+ // Eğer sadece normal karakterler varsa (özel karakter yoksa) exact match
2422
+ const hasSpecialChars = condition.includes('*') ||
2423
+ condition.includes('?') ||
2424
+ condition.includes('..');
2425
+ if (!hasSpecialChars) {
2426
+ return {
2427
+ type: 'exact',
2428
+ value: condition.toLowerCase(),
2429
+ };
2430
+ }
2431
+ // ? karakteri içeriyorsa singleChar kontrolü
2432
+ const value = condition.toLowerCase();
2433
+ if (value) {
2434
+ return {
2435
+ type: 'singleChar',
2436
+ value: value,
2437
+ };
2438
+ }
2291
2439
  }
2292
- }
2293
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2294
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, providedIn: 'root' });
2295
- }
2296
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, decorators: [{
2297
- type: Injectable,
2298
- args: [{
2299
- providedIn: 'root',
2300
- }]
2301
- }], ctorParameters: () => [] });
2302
-
2303
- class UrlHelperService {
2304
- router = inject(Router);
2305
- cleanUrl(url) {
2306
- let result = url
2307
- .replace('/mfalogin?redirect=', '')
2308
- .replace('/mfalogin?redirect=', '')
2309
- .replace('/mfalogin?redirect=', '')
2310
- .replace('/login?redirect=', '')
2311
- .replace('/login?redirect=', '')
2312
- .replace('/login?redirect=', '')
2313
- .replace(new RegExp('%25', 'g'), '%')
2314
- .replace(new RegExp('%25', 'g'), '%')
2315
- .replace(new RegExp('%25', 'g'), '%')
2316
- .replace(new RegExp('%25', 'g'), '%')
2317
- .replace(new RegExp('%25', 'g'), '%')
2318
- .replace(new RegExp('%25', 'g'), '%')
2319
- .replace(new RegExp('%22', 'g'), '"')
2320
- .replace(new RegExp('%3F', 'g'), '?')
2321
- .replace(new RegExp('%3D', 'g'), '=')
2322
- .replace(new RegExp('%2F', 'g'), '/')
2323
- .replace(new RegExp('%26', 'g'), '&')
2324
- .replace(new RegExp('/mfalogin?redirect=', 'g'), '')
2325
- .replace(new RegExp('/login?redirect=', 'g'), '');
2326
- console.log('url:', url);
2327
- console.log('result:', result);
2328
- // return url;
2329
- return result;
2330
- }
2331
- navigate(url) {
2332
- let urlParts = url.split('?');
2333
- if (urlParts.length == 1) {
2334
- return this.router.navigate(urlParts, { replaceUrl: true });
2440
+ // Başlangıç kontrolü (* sonunda)
2441
+ else if (condition.endsWith('*') &&
2442
+ !condition.startsWith('*') &&
2443
+ !condition.startsWith('$$')) {
2444
+ const value = condition.slice(0, -1).toLowerCase();
2445
+ if (value) {
2446
+ return {
2447
+ type: 'startsWith',
2448
+ value: value,
2449
+ };
2450
+ }
2335
2451
  }
2336
- let parameters = urlParts[1].split('&');
2337
- return this.router.navigate([urlParts[0]], {
2338
- queryParams: {
2339
- parameters: parameters[0]?.replace('parameters=', '') ?? '',
2340
- type: parameters[1]?.replace('type=', '') ?? '',
2341
- },
2342
- replaceUrl: true,
2343
- });
2452
+ // Bitiş kontrolü (* başında)
2453
+ else if (condition.startsWith('*') &&
2454
+ !condition.endsWith('*') &&
2455
+ !condition.startsWith('$$')) {
2456
+ const value = condition.slice(1).toLowerCase();
2457
+ if (value) {
2458
+ return {
2459
+ type: 'endsWith',
2460
+ value: value,
2461
+ };
2462
+ }
2463
+ }
2464
+ // İçeren kontrolü (* ile başlayıp * ile bitiyorsa)
2465
+ else if (condition.startsWith('*') &&
2466
+ condition.endsWith('*') &&
2467
+ !condition.startsWith('$$')) {
2468
+ const value = condition.slice(1, -1).toLowerCase();
2469
+ if (value) {
2470
+ return {
2471
+ type: 'contains',
2472
+ value: value,
2473
+ };
2474
+ }
2475
+ }
2476
+ // Normal exact match (hiçbir özel karakter yoksa)
2477
+ else if (!condition.startsWith('$$') &&
2478
+ !condition.includes('*') &&
2479
+ !condition.includes('?') &&
2480
+ !condition.includes('..')) {
2481
+ const value = condition.toLowerCase();
2482
+ if (value) {
2483
+ return {
2484
+ type: 'exact',
2485
+ value: value,
2486
+ };
2487
+ }
2488
+ }
2489
+ // Normal içeren kontrolü (varsayılan) - regex değilse
2490
+ else if (!condition.startsWith('$$')) {
2491
+ const value = condition.toLowerCase();
2492
+ if (value) {
2493
+ return {
2494
+ type: 'contains',
2495
+ value: value,
2496
+ };
2497
+ }
2498
+ }
2499
+ return null;
2344
2500
  }
2345
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2346
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, providedIn: 'root' });
2347
- }
2348
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, decorators: [{
2349
- type: Injectable,
2350
- args: [{
2351
- providedIn: 'root',
2352
- }]
2353
- }] });
2354
-
2355
- class AuthenticationInterceptor {
2356
- router = inject(Router);
2357
- credentialsService = inject(CredentialsService);
2358
- environmentProxy = inject(EnvironmentProxy);
2359
- urlHelperService = inject(UrlHelperService);
2360
- intercept(req, next) {
2361
- if (req.headers.get('No-Auth') == 'True')
2362
- return next.handle(req.clone());
2363
- let token = this.credentialsService.token;
2364
- if (token != null) {
2365
- let appName = this.environmentProxy.getApplicationName();
2366
- const clonedreq = req.clone({
2367
- headers: req.headers.set('Authorization', 'Bearer ' + token),
2368
- // .set("NettyAppName",appName)
2369
- });
2370
- return next.handle(clonedreq).pipe(catchError$1((error) => {
2371
- if (error instanceof HttpErrorResponse && error.status === 401) {
2372
- // Handle 401 error, e.g., navigate to the login page
2373
- this.router.navigate(['/login'], {
2374
- queryParams: {
2375
- redirect: this.urlHelperService.cleanUrl(this.router.url),
2376
- },
2377
- replaceUrl: true,
2378
- });
2379
- // Return an observable with a successful response
2380
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2501
+ doesFilterPass(params) {
2502
+ const field = this.params.colDef.field;
2503
+ if (!field)
2504
+ return true;
2505
+ const cellValue = params.data
2506
+ ? String(params.data[field] || '').toLowerCase()
2507
+ : '';
2508
+ // Eğer filtre yoksa tüm satırları göster
2509
+ if (this.conditions.length === 0) {
2510
+ return true;
2511
+ }
2512
+ // Hücre değeri boşsa filtrele
2513
+ if (!cellValue) {
2514
+ return false;
2515
+ }
2516
+ // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
2517
+ return this.conditions.some((condition) => {
2518
+ const conditionResult = this.checkSingleCondition(cellValue, condition);
2519
+ return condition.type === 'not' ? !conditionResult : conditionResult;
2520
+ });
2521
+ }
2522
+ checkSingleCondition(cellValue, condition) {
2523
+ switch (condition.type) {
2524
+ case 'contains':
2525
+ return condition.value ? cellValue.includes(condition.value) : false;
2526
+ case 'startsWith':
2527
+ return condition.value ? cellValue.startsWith(condition.value) : false;
2528
+ case 'endsWith':
2529
+ return condition.value ? cellValue.endsWith(condition.value) : false;
2530
+ case 'exact':
2531
+ return condition.value ? cellValue === condition.value : false;
2532
+ case 'range':
2533
+ if (condition.start && condition.end) {
2534
+ return cellValue >= condition.start && cellValue <= condition.end;
2381
2535
  }
2382
- if (error instanceof HttpErrorResponse && error.status === 403) {
2383
- this.router.navigate(['/forbidden'], {
2384
- state: { attemptedUrl: this.router.url }, // Orijinal URL'i state olarak geçme
2385
- });
2386
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2536
+ return false;
2537
+ case 'singleChar':
2538
+ if (condition.value) {
2539
+ // ? karakterini herhangi bir karakter olarak değerlendir
2540
+ const pattern = condition.value;
2541
+ if (cellValue.length !== pattern.length) {
2542
+ return false;
2543
+ }
2544
+ // Her karakteri tek tek kontrol et
2545
+ for (let i = 0; i < pattern.length; i++) {
2546
+ const patternChar = pattern[i];
2547
+ const cellChar = cellValue[i];
2548
+ // Eğer pattern'de ? değilse ve karakterler eşleşmiyorsa false
2549
+ if (patternChar !== '?' && patternChar !== cellChar) {
2550
+ return false;
2551
+ }
2552
+ }
2553
+ return true;
2387
2554
  }
2388
- if (error instanceof HttpErrorResponse && error.status === 428) {
2389
- // Handle 428 error, e.g., navigate to the login page
2390
- this.router.navigate(['/mfalogin'], {
2391
- queryParams: {
2392
- redirect: this.urlHelperService.cleanUrl(this.router.url),
2393
- },
2394
- replaceUrl: true,
2395
- });
2396
- // Return an observable with a successful response
2397
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2555
+ return false;
2556
+ case 'regex':
2557
+ if (condition.pattern) {
2558
+ try {
2559
+ const regex = new RegExp(condition.pattern, 'i'); // case-insensitive
2560
+ return regex.test(cellValue);
2561
+ }
2562
+ catch (e) {
2563
+ // Geçersiz regex patterni durumunda false döndür
2564
+ console.warn('Geçersiz regex patterni:', condition.pattern);
2565
+ return false;
2566
+ }
2398
2567
  }
2399
- // For other errors, re-throw the error to propagate it further
2400
- return throwError(() => error);
2401
- }));
2568
+ return false;
2569
+ case 'not':
2570
+ return this.checkSingleCondition(cellValue, condition.condition);
2571
+ default:
2572
+ return false;
2573
+ }
2574
+ }
2575
+ isFilterActive() {
2576
+ return this.conditions.length > 0;
2577
+ }
2578
+ getModel() {
2579
+ if (this.isFilterActive()) {
2580
+ return {
2581
+ filterType: 'custom',
2582
+ filterText: this.filterText,
2583
+ conditions: this.conditions,
2584
+ };
2585
+ }
2586
+ return null;
2587
+ }
2588
+ setModel(model) {
2589
+ if (model && model.filterText) {
2590
+ this.filterText = model.filterText;
2591
+ this.conditions = model.conditions || [];
2402
2592
  }
2403
2593
  else {
2404
- return next.handle(req.clone()).pipe(catchError$1((error) => {
2405
- if (error instanceof HttpErrorResponse && error.status === 401) {
2406
- // Handle 401 error, e.g., navigate to the login page
2407
- this.router.navigate(['/login'], {
2408
- queryParams: {
2409
- redirect: this.urlHelperService.cleanUrl(this.router.url),
2410
- },
2411
- replaceUrl: true,
2412
- });
2413
- // Return an observable with a successful response
2414
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2415
- }
2416
- if (error instanceof HttpErrorResponse && error.status === 403) {
2417
- this.router.navigate(['/forbidden'], {
2418
- state: { attemptedUrl: this.router.url }, // Orijinal URL'i state olarak geçme
2419
- });
2420
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2421
- }
2422
- if (error instanceof HttpErrorResponse && error.status === 428) {
2423
- // Handle 428 error, e.g., navigate to the login page
2424
- this.router.navigate(['/mfalogin'], {
2425
- queryParams: {
2426
- redirect: this.urlHelperService.cleanUrl(this.router.url),
2427
- },
2428
- replaceUrl: true,
2429
- });
2430
- // Return an observable with a successful response
2431
- return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2432
- }
2433
- // For other errors, re-throw the error to propagate it further
2434
- return throwError(() => error);
2435
- }));
2594
+ this.filterText = '';
2595
+ this.conditions = [];
2436
2596
  }
2437
2597
  }
2438
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2439
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor });
2598
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeStringFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2599
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeStringFilter, isStandalone: true, selector: "ntybase-range-string-filter", host: { attributes: { "ntybase-id": "RangeStringFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
2440
2600
  }
2441
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor, decorators: [{
2442
- type: Injectable
2601
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeStringFilter, decorators: [{
2602
+ type: Component,
2603
+ args: [{ selector: 'ntybase-range-string-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeStringFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n" }]
2443
2604
  }] });
2444
2605
 
2445
- class CanDeactivateGuard {
2446
- canDeactivate(component) {
2447
- return component.canDeactivate ? component.canDeactivate() : true;
2606
+ //-------------------------------
2607
+ //| Generated by NettyWizard V2 |
2608
+ //-------------------------------
2609
+ class ExcelLogViewer extends NettyAgGridListBase {
2610
+ /** Component Constructor */
2611
+ constructor() {
2612
+ super();
2448
2613
  }
2449
- }
2450
-
2451
- class NtybaseModule {
2452
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2453
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, declarations: [Ntybase], exports: [Ntybase] });
2454
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, providers: [
2455
- {
2456
- provide: HTTP_INTERCEPTORS,
2457
- useClass: AuthenticationInterceptor,
2458
- multi: true,
2459
- },
2460
- [CanDeactivateGuard],
2461
- DatePipe,
2462
- ] });
2463
- }
2464
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, decorators: [{
2465
- type: NgModule,
2466
- args: [{
2467
- declarations: [Ntybase],
2468
- imports: [],
2469
- exports: [Ntybase],
2470
- providers: [
2471
- {
2472
- provide: HTTP_INTERCEPTORS,
2473
- useClass: AuthenticationInterceptor,
2474
- multi: true,
2475
- },
2476
- [CanDeactivateGuard],
2477
- DatePipe,
2478
- ],
2479
- }]
2480
- }] });
2481
-
2482
- class Guid {
2483
- value = this.empty;
2484
- constructor(value) {
2485
- if (value) {
2486
- if (Guid.isValid(value)) {
2487
- this.value = value;
2614
+ /** Get the rowId */
2615
+ getRowId = (params) => params.data.rowIndex.toString();
2616
+ /** Get the entity type for the component */
2617
+ getEntityType = () => 'ParseLog';
2618
+ pkFieldName() { return 'rowIndex'; }
2619
+ loadData() { }
2620
+ setParseData(data) {
2621
+ data.forEach((item) => {
2622
+ if (item.messageKey) {
2623
+ item.message = this.translateService.instant(item.messageKey, item.messageParams);
2488
2624
  }
2489
- }
2490
- }
2491
- static newGuid() {
2492
- return new Guid('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2493
- const r = (Math.random() * 16) | 0;
2494
- const v = c == 'x' ? r : (r & 0x3) | 0x8;
2495
- return v.toString(16);
2496
- }));
2625
+ });
2626
+ super.setData(data);
2497
2627
  }
2498
- /**
2499
- * return all zeros '00000000-0000-0000-0000-000000000000'
2500
- */
2501
- static get empty() {
2502
- return '00000000-0000-0000-0000-000000000000';
2628
+ /** Initialize Ag-Grid specific settings */
2629
+ initAgGrid() {
2630
+ this.excelStyles = this.nettyAgGridService.getExcelStyles();
2631
+ this.columnDefs.set([
2632
+ { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.row'), field: 'rowIndex', cellClass: 'numberType', filter: this.customFilters() ? RangeNumberFilter : 'agNumberColumnFilter', type: "numericColumn", cellStyle: { textAlign: 'right' } },
2633
+ { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.message'), field: 'message', cellClass: 'text-format', filter: this.customFilters() ? RangeStringFilter : 'agSetColumnFilter', },
2634
+ { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.level'), field: 'level', cellClass: 'text-format', filter: this.customFilters() ? RangeStringFilter : 'agSetColumnFilter', },
2635
+ ]);
2636
+ this.initAgGrid_extension();
2503
2637
  }
2504
- get empty() {
2505
- return Guid.empty;
2638
+ popupClose() {
2639
+ super.popupClose();
2506
2640
  }
2507
- static isValid(str) {
2508
- const validRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i;
2509
- return validRegex.test(str);
2641
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelLogViewer, deps: [], target: i0.ɵɵFactoryTarget.Component });
2642
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ExcelLogViewer, isStandalone: true, selector: "app-excel-log-viewer", usesInheritance: true, ngImport: i0, template: "<div class='list-container'>\n <div class='list-menu-button-bar'>\n <ntyui-button type='menu' icon='settings_ethernet' [disableOnClick]='false' (clicked)='expandCollapse()' />\n <ntyui-button type='menu' icon='regular_expression'\n [toolTip]=\"(customFilters() ? '@customFilterActive' : '@defaultFilterActive') | translate\"\n [disableOnClick]='true' [disableDuration]='0'\n [ngClass]=\"{'custom-filter-mode': !customFilters(),'default-filter-mode': customFilters()}\"\n (clicked)='toggleFilterMode()' />\n <ntyui-filter-button icon='filter_alt' (isSearchOpen)=\"onFilterTextBoxVisibilityChange($event)\"\n [searchValue]='searchValue()' (onSearch)='quickSearch($event)' />\n <ntyui-button type='close' class='list-close-button' [toolTip]=\"'@close'|translate\" (clicked)='popupClose()' />\n </div>\n <div class='list-grid'>\n <ag-grid-angular #agGrid class='ag-theme-balham grid-form-grid-full' [rowData]='recordList()'\n [columnDefs]='columnDefs()' [gridOptions]='gridOptions' [rowSelection]='gridOptions.rowSelection'\n [components]='frameworkComponents' [suppressAggFuncInHeader]='true' [enableCellTextSelection]='true'\n (firstDataRendered)='onFirstDataRendered($event)' (columnMoved)='saveGrid($event)'\n (columnVisible)='saveGrid($event)' (columnResized)='saveGrid($event)' (gridReady)='onGridReady($event)'\n [statusBar]='statusBar'></ag-grid-angular>\n </div>\n</div>", styles: [""], dependencies: [{ kind: "component", type: AgGridAngular, selector: "ag-grid-angular", inputs: ["gridOptions", "modules", "statusBar", "sideBar", "suppressContextMenu", "preventDefaultOnContextMenu", "allowContextMenuWithControlKey", "columnMenu", "suppressMenuHide", "enableBrowserTooltips", "tooltipTrigger", "tooltipShowDelay", "tooltipSwitchShowDelay", "tooltipHideDelay", "tooltipMouseTrack", "tooltipShowMode", "tooltipInteraction", "popupParent", "copyHeadersToClipboard", "copyGroupHeadersToClipboard", "clipboardDelimiter", "suppressCopyRowsToClipboard", "suppressCopySingleCellRanges", "suppressLastEmptyLineOnPaste", "suppressClipboardPaste", "suppressClipboardApi", "suppressCutToClipboard", "columnDefs", "defaultColDef", "defaultColGroupDef", "columnTypes", "dataTypeDefinitions", "maintainColumnOrder", "enableStrictPivotColumnOrder", "suppressFieldDotNotation", "headerHeight", "groupHeaderHeight", "floatingFiltersHeight", "pivotHeaderHeight", "pivotGroupHeaderHeight", "hidePaddedHeaderRows", "allowDragFromColumnsToolPanel", "suppressMovableColumns", "suppressColumnMoveAnimation", "suppressMoveWhenColumnDragging", "suppressDragLeaveHidesColumns", "suppressGroupChangesColumnVisibility", "suppressMakeColumnVisibleAfterUnGroup", "suppressRowGroupHidesColumns", "colResizeDefault", "suppressAutoSize", "autoSizePadding", "skipHeaderOnAutoSize", "autoSizeStrategy", "animateColumnResizing", "components", "editType", "suppressStartEditOnTab", "getFullRowEditValidationErrors", "invalidEditValueMode", "singleClickEdit", "suppressClickEdit", "readOnlyEdit", "stopEditingWhenCellsLoseFocus", "enterNavigatesVertically", "enterNavigatesVerticallyAfterEdit", "enableCellEditingOnBackspace", "undoRedoCellEditing", "undoRedoCellEditingLimit", "defaultCsvExportParams", "suppressCsvExport", "defaultExcelExportParams", "suppressExcelExport", "excelStyles", "findSearchValue", "findOptions", "quickFilterText", "cacheQuickFilter", "includeHiddenColumnsInQuickFilter", "quickFilterParser", "quickFilterMatcher", "applyQuickFilterBeforePivotOrAgg", "excludeChildrenWhenTreeDataFiltering", "enableAdvancedFilter", "alwaysPassFilter", "includeHiddenColumnsInAdvancedFilter", "advancedFilterParent", "advancedFilterBuilderParams", "advancedFilterParams", "suppressAdvancedFilterEval", "suppressSetFilterByDefault", "enableFilterHandlers", "filterHandlers", "enableCharts", "chartThemes", "customChartThemes", "chartThemeOverrides", "chartToolPanelsDef", "chartMenuItems", "loadingCellRenderer", "loadingCellRendererParams", "loadingCellRendererSelector", "localeText", "masterDetail", "keepDetailRows", "keepDetailRowsCount", "detailCellRenderer", "detailCellRendererParams", "detailRowHeight", "detailRowAutoHeight", "context", "alignedGrids", "tabIndex", "rowBuffer", "valueCache", "valueCacheNeverExpires", "enableCellExpressions", "suppressTouch", "suppressFocusAfterRefresh", "suppressBrowserResizeObserver", "suppressPropertyNamesCheck", "suppressChangeDetection", "debug", "loading", "overlayLoadingTemplate", "loadingOverlayComponent", "loadingOverlayComponentParams", "suppressLoadingOverlay", "overlayNoRowsTemplate", "noRowsOverlayComponent", "noRowsOverlayComponentParams", "suppressNoRowsOverlay", "suppressOverlays", "overlayComponent", "overlayComponentParams", "overlayComponentSelector", "activeOverlay", "activeOverlayParams", "pagination", "paginationPageSize", "paginationPageSizeSelector", "paginationAutoPageSize", "paginateChildRows", "suppressPaginationPanel", "pivotMode", "pivotPanelShow", "pivotMaxGeneratedColumns", "pivotDefaultExpanded", "pivotColumnGroupTotals", "pivotRowTotals", "pivotSuppressAutoColumn", "suppressExpandablePivotGroups", "functionsReadOnly", "aggFuncs", "formulaDataSource", "formulaFuncs", "suppressAggFuncInHeader", "alwaysAggregateAtRootLevel", "aggregateOnlyChangedColumns", "suppressAggFilteredOnly", "removePivotHeaderRowWhenSingleValueColumn", "animateRows", "cellFlashDuration", "cellFadeDuration", "allowShowChangeAfterFilter", "domLayout", "ensureDomOrder", "enableCellSpan", "enableRtl", "suppressColumnVirtualisation", "suppressMaxRenderedRowRestriction", "suppressRowVirtualisation", "rowDragManaged", "refreshAfterGroupEdit", "rowDragInsertDelay", "suppressRowDrag", "suppressMoveWhenRowDragging", "rowDragEntireRow", "rowDragMultiRow", "rowDragText", "dragAndDropImageComponent", "dragAndDropImageComponentParams", "fullWidthCellRenderer", "fullWidthCellRendererParams", "embedFullWidthRows", "groupDisplayType", "groupDefaultExpanded", "autoGroupColumnDef", "groupMaintainOrder", "groupSelectsChildren", "groupLockGroupColumns", "groupAggFiltering", "groupTotalRow", "grandTotalRow", "suppressStickyTotalRow", "groupSuppressBlankHeader", "groupSelectsFiltered", "showOpenedGroup", "groupHideParentOfSingleChild", "groupRemoveSingleChildren", "groupRemoveLowestSingleChildren", "groupHideOpenParents", "groupAllowUnbalanced", "rowGroupPanelShow", "groupRowRenderer", "groupRowRendererParams", "treeData", "treeDataChildrenField", "treeDataParentIdField", "rowGroupPanelSuppressSort", "suppressGroupRowsSticky", "groupHierarchyConfig", "pinnedTopRowData", "pinnedBottomRowData", "enableRowPinning", "isRowPinnable", "isRowPinned", "rowModelType", "rowData", "asyncTransactionWaitMillis", "suppressModelUpdateAfterUpdateTransaction", "datasource", "cacheOverflowSize", "infiniteInitialRowCount", "serverSideInitialRowCount", "suppressServerSideFullWidthLoadingRow", "cacheBlockSize", "maxBlocksInCache", "maxConcurrentDatasourceRequests", "blockLoadDebounceMillis", "purgeClosedRowNodes", "serverSideDatasource", "serverSideSortAllLevels", "serverSideEnableClientSideSort", "serverSideOnlyRefreshFilteredGroups", "serverSidePivotResultFieldSeparator", "viewportDatasource", "viewportRowModelPageSize", "viewportRowModelBufferSize", "alwaysShowHorizontalScroll", "alwaysShowVerticalScroll", "debounceVerticalScrollbar", "suppressHorizontalScroll", "suppressScrollOnNewData", "suppressScrollWhenPopupsAreOpen", "suppressAnimationFrame", "suppressMiddleClickScrolls", "suppressPreventDefaultOnMouseWheel", "scrollbarWidth", "rowSelection", "cellSelection", "rowMultiSelectWithClick", "suppressRowDeselection", "suppressRowClickSelection", "suppressCellFocus", "suppressHeaderFocus", "selectionColumnDef", "rowNumbers", "suppressMultiRangeSelection", "enableCellTextSelection", "enableRangeSelection", "enableRangeHandle", "enableFillHandle", "fillHandleDirection", "suppressClearOnFillReduction", "sortingOrder", "accentedSort", "unSortIcon", "suppressMultiSort", "alwaysMultiSort", "multiSortKey", "suppressMaintainUnsortedOrder", "icons", "rowHeight", "rowStyle", "rowClass", "rowClassRules", "suppressRowHoverHighlight", "suppressRowTransform", "columnHoverHighlight", "gridId", "deltaSort", "treeDataDisplayType", "enableGroupEdit", "initialState", "theme", "loadThemeGoogleFonts", "themeCssLayer", "styleNonce", "themeStyleContainer", "getContextMenuItems", "getMainMenuItems", "postProcessPopup", "processUnpinnedColumns", "processCellForClipboard", "processHeaderForClipboard", "processGroupHeaderForClipboard", "processCellFromClipboard", "sendToClipboard", "processDataFromClipboard", "isExternalFilterPresent", "doesExternalFilterPass", "getChartToolbarItems", "createChartContainer", "focusGridInnerElement", "navigateToNextHeader", "tabToNextHeader", "navigateToNextCell", "tabToNextCell", "getLocaleText", "getDocument", "paginationNumberFormatter", "getGroupRowAgg", "isGroupOpenByDefault", "ssrmExpandAllAffectsAllRows", "initialGroupOrderComparator", "processPivotResultColDef", "processPivotResultColGroupDef", "getDataPath", "getChildCount", "getServerSideGroupLevelParams", "isServerSideGroupOpenByDefault", "isApplyServerSideTransaction", "isServerSideGroup", "getServerSideGroupKey", "getBusinessKeyForNode", "getRowId", "resetRowDataOnUpdate", "processRowPostCreate", "isRowSelectable", "isRowMaster", "fillOperation", "postSortRows", "getRowStyle", "getRowClass", "getRowHeight", "isFullWidthRow", "isRowValidDropPosition"], outputs: ["toolPanelVisibleChanged", "toolPanelSizeChanged", "columnMenuVisibleChanged", "contextMenuVisibleChanged", "cutStart", "cutEnd", "pasteStart", "pasteEnd", "columnVisible", "columnPinned", "columnResized", "columnMoved", "columnValueChanged", "columnPivotModeChanged", "columnPivotChanged", "columnGroupOpened", "newColumnsLoaded", "gridColumnsChanged", "displayedColumnsChanged", "virtualColumnsChanged", "columnEverythingChanged", "columnsReset", "columnHeaderMouseOver", "columnHeaderMouseLeave", "columnHeaderClicked", "columnHeaderContextMenu", "componentStateChanged", "cellValueChanged", "cellEditRequest", "rowValueChanged", "cellEditingStarted", "cellEditingStopped", "rowEditingStarted", "rowEditingStopped", "bulkEditingStarted", "bulkEditingStopped", "batchEditingStarted", "batchEditingStopped", "undoStarted", "undoEnded", "redoStarted", "redoEnded", "cellSelectionDeleteStart", "cellSelectionDeleteEnd", "rangeDeleteStart", "rangeDeleteEnd", "fillStart", "fillEnd", "filterOpened", "filterChanged", "filterModified", "filterUiChanged", "floatingFilterUiChanged", "advancedFilterBuilderVisibleChanged", "findChanged", "chartCreated", "chartRangeSelectionChanged", "chartOptionsChanged", "chartDestroyed", "cellKeyDown", "gridReady", "firstDataRendered", "gridSizeChanged", "modelUpdated", "virtualRowRemoved", "viewportChanged", "bodyScroll", "bodyScrollEnd", "dragStarted", "dragStopped", "dragCancelled", "stateUpdated", "paginationChanged", "rowDragEnter", "rowDragMove", "rowDragLeave", "rowDragEnd", "rowDragCancel", "rowResizeStarted", "rowResizeEnded", "columnRowGroupChanged", "rowGroupOpened", "expandOrCollapseAll", "pivotMaxColumnsExceeded", "pinnedRowDataChanged", "pinnedRowsChanged", "rowDataUpdated", "asyncTransactionsFlushed", "storeRefreshed", "headerFocused", "cellClicked", "cellDoubleClicked", "cellFocused", "cellMouseOver", "cellMouseOut", "cellMouseDown", "rowClicked", "rowDoubleClicked", "rowSelected", "selectionChanged", "cellContextMenu", "rangeSelectionChanged", "cellSelectionChanged", "tooltipShow", "tooltipHide", "sortChanged"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: NettyUIButton, selector: "ntyui-button", inputs: ["icon", "isFilled", "menuReference", "disableOnClick", "disableDuration", "waitingText", "type", "toolTip"], outputs: ["clicked"] }, { kind: "component", type: NettyUIFilterButton, selector: "ntyui-filter-button", inputs: ["icon", "waitingText", "searchValue"], outputs: ["clicked", "onSearch", "isSearchOpen"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
2643
+ }
2644
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelLogViewer, decorators: [{
2645
+ type: Component,
2646
+ args: [{ selector: 'app-excel-log-viewer', imports: [AgGridAngular, CommonModule, FormsModule, NettyUIButton, NettyUIFilterButton,
2647
+ FormsModule, TranslateModule], template: "<div class='list-container'>\n <div class='list-menu-button-bar'>\n <ntyui-button type='menu' icon='settings_ethernet' [disableOnClick]='false' (clicked)='expandCollapse()' />\n <ntyui-button type='menu' icon='regular_expression'\n [toolTip]=\"(customFilters() ? '@customFilterActive' : '@defaultFilterActive') | translate\"\n [disableOnClick]='true' [disableDuration]='0'\n [ngClass]=\"{'custom-filter-mode': !customFilters(),'default-filter-mode': customFilters()}\"\n (clicked)='toggleFilterMode()' />\n <ntyui-filter-button icon='filter_alt' (isSearchOpen)=\"onFilterTextBoxVisibilityChange($event)\"\n [searchValue]='searchValue()' (onSearch)='quickSearch($event)' />\n <ntyui-button type='close' class='list-close-button' [toolTip]=\"'@close'|translate\" (clicked)='popupClose()' />\n </div>\n <div class='list-grid'>\n <ag-grid-angular #agGrid class='ag-theme-balham grid-form-grid-full' [rowData]='recordList()'\n [columnDefs]='columnDefs()' [gridOptions]='gridOptions' [rowSelection]='gridOptions.rowSelection'\n [components]='frameworkComponents' [suppressAggFuncInHeader]='true' [enableCellTextSelection]='true'\n (firstDataRendered)='onFirstDataRendered($event)' (columnMoved)='saveGrid($event)'\n (columnVisible)='saveGrid($event)' (columnResized)='saveGrid($event)' (gridReady)='onGridReady($event)'\n [statusBar]='statusBar'></ag-grid-angular>\n </div>\n</div>" }]
2648
+ }], ctorParameters: () => [] });
2649
+
2650
+ class ExcelImportBase extends NettyAgGridListBase {
2651
+ isFileSelectionHidden = signal(false, ...(ngDevMode ? [{ debugName: "isFileSelectionHidden" }] : []));
2652
+ isFileValid = signal(false, ...(ngDevMode ? [{ debugName: "isFileValid" }] : []));
2653
+ logs = signal([], ...(ngDevMode ? [{ debugName: "logs" }] : []));
2654
+ hasLogs = computed(() => this.logs().length > 0, ...(ngDevMode ? [{ debugName: "hasLogs" }] : []));
2655
+ logDialog = inject(MatDialog);
2656
+ parser = new ExcelParser([]);
2657
+ // override methods
2658
+ onBtnClick(e) { }
2659
+ loadData() { }
2660
+ // Methods
2661
+ onFilesSelected(evt) {
2662
+ const files = Array.isArray(evt) ? evt : evt.target.files;
2663
+ if (!files || files.length !== 1) {
2664
+ return;
2665
+ }
2666
+ const file = files[0];
2667
+ if (file) {
2668
+ this.recordList.set([]);
2669
+ this.logs.set([]);
2670
+ this.parser.parse(file).then(result => {
2671
+ this.recordList.set(result.data);
2672
+ this.logs.set(result.logs);
2673
+ this.isFileSelectionHidden.set(true);
2674
+ if (result.logs.length > 0)
2675
+ this.showLogs();
2676
+ });
2677
+ }
2510
2678
  }
2511
- toString() {
2512
- return this.value;
2679
+ downloadSampleExcel() {
2680
+ this.parser.generateSampleExcel();
2513
2681
  }
2514
- toJSON() {
2515
- return this.value;
2682
+ showLogs() {
2683
+ const dialogRef = this.logDialog.open(ExcelLogViewer, {
2684
+ height: '70%',
2685
+ width: '90%',
2686
+ maxWidth: '100vw',
2687
+ maxHeight: '100vh'
2688
+ });
2689
+ dialogRef.componentInstance.setParseData(this.logs());
2690
+ dialogRef.componentInstance.selectedElement.subscribe((element) => {
2691
+ dialogRef.close();
2692
+ });
2693
+ }
2694
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelImportBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2695
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ExcelImportBase, isStandalone: true, selector: "ntybase-excel-import-base", usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2696
+ }
2697
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelImportBase, decorators: [{
2698
+ type: Component,
2699
+ args: [{ selector: 'ntybase-excel-import-base', imports: [], template: `` }]
2700
+ }] });
2701
+
2702
+ class Ntybase {
2703
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Ntybase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2704
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: Ntybase, isStandalone: false, selector: "lib-ntybase", ngImport: i0, template: `
2705
+ <p>
2706
+ ntybase works!
2707
+ </p>
2708
+ `, isInline: true, styles: [""] });
2709
+ }
2710
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Ntybase, decorators: [{
2711
+ type: Component,
2712
+ args: [{ selector: 'lib-ntybase', standalone: false, template: `
2713
+ <p>
2714
+ ntybase works!
2715
+ </p>
2716
+ ` }]
2717
+ }] });
2718
+
2719
+ const credentialsKey = 'credentials';
2720
+ class CredentialsService {
2721
+ _credentials = null;
2722
+ constructor() {
2723
+ const savedCredentials = sessionStorage.getItem(credentialsKey) ||
2724
+ localStorage.getItem(credentialsKey);
2725
+ if (savedCredentials) {
2726
+ this._credentials = JSON.parse(savedCredentials);
2727
+ }
2516
2728
  }
2517
2729
  /**
2518
- * True is guid is empty or not valid
2519
- * @param str
2520
- * @returns
2730
+ * Checks is the user is authenticated.
2731
+ * @return True if the user is authenticated.
2521
2732
  */
2522
- static isNullOrEmpty(str) {
2523
- if (str == null || str == undefined || str.trim() == '' || str == Guid.empty) {
2524
- return true;
2733
+ isAuthenticated() {
2734
+ return !!this.credentials;
2735
+ }
2736
+ /**
2737
+ * Gets the user credentials.
2738
+ * @return The user credentials or null if the user is not authenticated.
2739
+ */
2740
+ get credentials() {
2741
+ return this._credentials;
2742
+ }
2743
+ get token() {
2744
+ return this._credentials?.token ?? null;
2745
+ }
2746
+ /**
2747
+ * Sets the user credentials.
2748
+ * The credentials may be persisted across sessions by setting the `remember` parameter to true.
2749
+ * Otherwise, the credentials are only persisted for the current session.
2750
+ * @param credentials The user credentials.
2751
+ * @param remember True to remember credentials across sessions.
2752
+ */
2753
+ setCredentials(credentials, remember) {
2754
+ this._credentials = credentials || null;
2755
+ if (credentials) {
2756
+ const storage = remember ? localStorage : sessionStorage;
2757
+ storage.setItem(credentialsKey, JSON.stringify(credentials));
2525
2758
  }
2526
- if (!Guid.isValid(str)) {
2527
- return true;
2759
+ else {
2760
+ sessionStorage.removeItem(credentialsKey);
2761
+ localStorage.removeItem(credentialsKey);
2528
2762
  }
2529
- return false;
2530
2763
  }
2531
- /**
2532
- * True if the guid is valid and not all zeros (empty)
2533
- * @param str
2764
+ /** Get Credentials
2765
+ *
2534
2766
  * @returns
2535
2767
  */
2536
- static isValidAndNotEmpty(str) {
2537
- return !Guid.isNullOrEmpty(str);
2768
+ getCredentials() {
2769
+ let _credentialsString = sessionStorage.getItem(credentialsKey);
2770
+ if (_credentialsString == null || _credentialsString == '') {
2771
+ _credentialsString = localStorage.getItem(credentialsKey);
2772
+ }
2773
+ return JSON.parse(_credentialsString ?? '');
2538
2774
  }
2539
- /**
2540
- * Return empty guid if the given guid is not valid
2541
- * @param guid
2775
+ /** Get the token if available otherwise return empty string
2776
+ *
2542
2777
  * @returns
2543
2778
  */
2544
- static emptyWhenNull(guid) {
2545
- if (Guid.isValidAndNotEmpty(guid)) {
2546
- return guid;
2779
+ getToken() {
2780
+ try {
2781
+ let _credentials = this.getCredentials();
2782
+ return _credentials.token;
2783
+ }
2784
+ catch (error) {
2785
+ return '';
2547
2786
  }
2548
- return Guid.empty;
2549
2787
  }
2788
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2789
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, providedIn: 'root' });
2550
2790
  }
2791
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: CredentialsService, decorators: [{
2792
+ type: Injectable,
2793
+ args: [{
2794
+ providedIn: 'root',
2795
+ }]
2796
+ }], ctorParameters: () => [] });
2551
2797
 
2552
- ModuleRegistry.registerModules([AllCommunityModule, StatusBarModule, ClientSideRowModelModule, ClipboardModule, ExcelExportModule, ColumnMenuModule,
2553
- ContextMenuModule, CellSelectionModule, HighlightChangesModule, RowSelectionModule,]);
2554
- // AgGrid Dark Mode Row Style
2555
- class NettyAgGridListFilterBase extends NettyAgGridListBase {
2556
- // ********************************************
2557
- // *** INPUTS ***
2558
- // ********************************************
2559
- // Filter section
2560
- displayFilter = input(true, ...(ngDevMode ? [{ debugName: "displayFilter" }] : [])); // Does the component display it's filter section when embadded
2561
- _displayFilter = computed(() => this.displayFilter() ?? true, ...(ngDevMode ? [{ debugName: "_displayFilter" }] : [])); // Computed version of displayFilter to prevent undefined
2562
- isFilterValid = signal(true, ...(ngDevMode ? [{ debugName: "isFilterValid" }] : [])); // Can the filter be used
2563
- isFilterExpanded = linkedSignal({ ...(ngDevMode ? { debugName: "isFilterExpanded" } : {}), // Is the filter component expanded
2564
- source: () => ({
2565
- embedded: this._isEmbedded(),
2566
- displayFilter: this._displayFilter(),
2567
- valid: this.isFilterValid(),
2568
- }),
2569
- computation: (s) => {
2570
- if (s.embedded || !s.displayFilter)
2571
- return false;
2572
- return s.valid;
2573
- } });
2574
- filterRefreshTrigger = signal(0, ...(ngDevMode ? [{ debugName: "filterRefreshTrigger" }] : []));
2575
- constructor() {
2576
- super();
2577
- effect(() => {
2578
- if (this.hasValidValue(this.parameterGUID())) {
2579
- this.isFilterExpanded.set(false);
2580
- this.setFilter();
2581
- this.loadData();
2582
- }
2583
- });
2584
- }
2585
- async ngOnInit() {
2586
- await super.ngOnInit();
2798
+ class UrlHelperService {
2799
+ router = inject(Router);
2800
+ cleanUrl(url) {
2801
+ let result = url
2802
+ .replace('/mfalogin?redirect=', '')
2803
+ .replace('/mfalogin?redirect=', '')
2804
+ .replace('/mfalogin?redirect=', '')
2805
+ .replace('/login?redirect=', '')
2806
+ .replace('/login?redirect=', '')
2807
+ .replace('/login?redirect=', '')
2808
+ .replace(new RegExp('%25', 'g'), '%')
2809
+ .replace(new RegExp('%25', 'g'), '%')
2810
+ .replace(new RegExp('%25', 'g'), '%')
2811
+ .replace(new RegExp('%25', 'g'), '%')
2812
+ .replace(new RegExp('%25', 'g'), '%')
2813
+ .replace(new RegExp('%25', 'g'), '%')
2814
+ .replace(new RegExp('%22', 'g'), '"')
2815
+ .replace(new RegExp('%3F', 'g'), '?')
2816
+ .replace(new RegExp('%3D', 'g'), '=')
2817
+ .replace(new RegExp('%2F', 'g'), '/')
2818
+ .replace(new RegExp('%26', 'g'), '&')
2819
+ .replace(new RegExp('/mfalogin?redirect=', 'g'), '')
2820
+ .replace(new RegExp('/login?redirect=', 'g'), '');
2821
+ console.log('url:', url);
2822
+ console.log('result:', result);
2823
+ // return url;
2824
+ return result;
2587
2825
  }
2588
- // *********************************************************
2589
- // *** Data Management Functions ***
2590
- // *********************************************************
2591
- loadData() {
2592
- if (Guid.isNullOrEmpty(this.parameterGUID())) {
2593
- this.setData([], true);
2594
- return;
2826
+ navigate(url) {
2827
+ let urlParts = url.split('?');
2828
+ if (urlParts.length == 1) {
2829
+ return this.router.navigate(urlParts, { replaceUrl: true });
2595
2830
  }
2596
- this.nettyAppsProxy.select(this.record).subscribe({
2597
- next: (data) => {
2598
- this.setData(data, false);
2831
+ let parameters = urlParts[1].split('&');
2832
+ return this.router.navigate([urlParts[0]], {
2833
+ queryParams: {
2834
+ parameters: parameters[0]?.replace('parameters=', '') ?? '',
2835
+ type: parameters[1]?.replace('type=', '') ?? '',
2599
2836
  },
2600
- error: (err) => this.alertService.showError('@dataLoadFailed', err),
2837
+ replaceUrl: true,
2601
2838
  });
2602
2839
  }
2603
- async refreshData() {
2604
- try {
2605
- this.refreshFilterData();
2606
- }
2607
- catch (err) {
2608
- this.alertService.showError(err);
2840
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2841
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, providedIn: 'root' });
2842
+ }
2843
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: UrlHelperService, decorators: [{
2844
+ type: Injectable,
2845
+ args: [{
2846
+ providedIn: 'root',
2847
+ }]
2848
+ }] });
2849
+
2850
+ class AuthenticationInterceptor {
2851
+ router = inject(Router);
2852
+ credentialsService = inject(CredentialsService);
2853
+ environmentProxy = inject(EnvironmentProxy);
2854
+ urlHelperService = inject(UrlHelperService);
2855
+ intercept(req, next) {
2856
+ if (req.headers.get('No-Auth') == 'True')
2857
+ return next.handle(req.clone());
2858
+ let token = this.credentialsService.token;
2859
+ if (token != null) {
2860
+ let appName = this.environmentProxy.getApplicationName();
2861
+ const clonedreq = req.clone({
2862
+ headers: req.headers.set('Authorization', 'Bearer ' + token),
2863
+ // .set("NettyAppName",appName)
2864
+ });
2865
+ return next.handle(clonedreq).pipe(catchError$1((error) => {
2866
+ if (error instanceof HttpErrorResponse && error.status === 401) {
2867
+ // Handle 401 error, e.g., navigate to the login page
2868
+ this.router.navigate(['/login'], {
2869
+ queryParams: {
2870
+ redirect: this.urlHelperService.cleanUrl(this.router.url),
2871
+ },
2872
+ replaceUrl: true,
2873
+ });
2874
+ // Return an observable with a successful response
2875
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2876
+ }
2877
+ if (error instanceof HttpErrorResponse && error.status === 403) {
2878
+ this.router.navigate(['/forbidden'], {
2879
+ state: { attemptedUrl: this.router.url }, // Orijinal URL'i state olarak geçme
2880
+ });
2881
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2882
+ }
2883
+ if (error instanceof HttpErrorResponse && error.status === 428) {
2884
+ // Handle 428 error, e.g., navigate to the login page
2885
+ this.router.navigate(['/mfalogin'], {
2886
+ queryParams: {
2887
+ redirect: this.urlHelperService.cleanUrl(this.router.url),
2888
+ },
2889
+ replaceUrl: true,
2890
+ });
2891
+ // Return an observable with a successful response
2892
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2893
+ }
2894
+ // For other errors, re-throw the error to propagate it further
2895
+ return throwError(() => error);
2896
+ }));
2609
2897
  }
2610
- }
2611
- /**
2612
- * Triggers the filter component to refresh its data
2613
- */
2614
- refreshFilterData() {
2615
- this.filterRefreshTrigger.update(val => val > 10000 ? 1 : val + 1);
2616
- }
2617
- onReverseIsFilterValid() {
2618
- this.isFilterValid.update((a) => !a);
2619
- }
2620
- // *****************************************
2621
- // *** Logging Functions ***
2622
- // *****************************************
2623
- logInputs(message) {
2624
- if (!message || message.length < 1) {
2625
- message = 'AgGridListFilterBase - Inputs log';
2898
+ else {
2899
+ return next.handle(req.clone()).pipe(catchError$1((error) => {
2900
+ if (error instanceof HttpErrorResponse && error.status === 401) {
2901
+ // Handle 401 error, e.g., navigate to the login page
2902
+ this.router.navigate(['/login'], {
2903
+ queryParams: {
2904
+ redirect: this.urlHelperService.cleanUrl(this.router.url),
2905
+ },
2906
+ replaceUrl: true,
2907
+ });
2908
+ // Return an observable with a successful response
2909
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2910
+ }
2911
+ if (error instanceof HttpErrorResponse && error.status === 403) {
2912
+ this.router.navigate(['/forbidden'], {
2913
+ state: { attemptedUrl: this.router.url }, // Orijinal URL'i state olarak geçme
2914
+ });
2915
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2916
+ }
2917
+ if (error instanceof HttpErrorResponse && error.status === 428) {
2918
+ // Handle 428 error, e.g., navigate to the login page
2919
+ this.router.navigate(['/mfalogin'], {
2920
+ queryParams: {
2921
+ redirect: this.urlHelperService.cleanUrl(this.router.url),
2922
+ },
2923
+ replaceUrl: true,
2924
+ });
2925
+ // Return an observable with a successful response
2926
+ return of(new HttpResponse({ status: 200, body: { message: 'Success' } }));
2927
+ }
2928
+ // For other errors, re-throw the error to propagate it further
2929
+ return throwError(() => error);
2930
+ }));
2626
2931
  }
2627
- const inputs = {
2628
- "popupFilterValid": this.popupFilterValid(),
2629
- "_isPopupFilterValid": this._isPopupFilterValid(),
2630
- "popupValid": this.popupValid(),
2631
- "_isPopupValid": this._isPopupValid(),
2632
- "componantParameterGUID": this.componantParameterGUID(),
2633
- "componantParameterType": this.componantParameterType(),
2634
- "embedded": this.embedded(),
2635
- "_isEmbedded": this._isEmbedded(),
2636
- "displayFilter": this.displayFilter(),
2637
- "_displayFilter": this._displayFilter(),
2638
- "isFilterValid": this.isFilterValid(),
2639
- "isFilterExpanded": this.isFilterExpanded(),
2640
- };
2641
- console.log(message, inputs);
2642
2932
  }
2643
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridListFilterBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
2644
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: NettyAgGridListFilterBase, isStandalone: true, selector: "ntybase-ag-grid-list-filter-base", inputs: { displayFilter: { classPropertyName: "displayFilter", publicName: "displayFilter", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ntybase-id": "NettyAgGridListFilterBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2933
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
2934
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor });
2645
2935
  }
2646
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridListFilterBase, decorators: [{
2647
- type: Component,
2648
- args: [{ selector: 'ntybase-ag-grid-list-filter-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridListFilterBase' } }]
2649
- }], ctorParameters: () => [], propDecorators: { displayFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFilter", required: false }] }] } });
2936
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: AuthenticationInterceptor, decorators: [{
2937
+ type: Injectable
2938
+ }] });
2650
2939
 
2651
- class NettyAgGridLogBase extends NettyAgGridBase {
2652
- // ---------------------------------------------------
2653
- // --- RECORD LIST ---
2654
- // ---------------------------------------------------
2655
- nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
2656
- /**
2657
- * Component initialization lifecycle hook
2658
- */
2659
- async ngOnInit() {
2660
- this.nettyAppsProxy.setURLPath(this.componentName());
2661
- await this.setAccessRights(true);
2662
- const savedSearchValue = sessionStorage.getItem(this.searchValueName());
2663
- if (savedSearchValue) {
2664
- this.searchValue.set(savedSearchValue);
2665
- }
2666
- this.loadData();
2667
- // Load user grid preferences
2668
- await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
2669
- await this.AfterOnInit();
2940
+ class CanDeactivateGuard {
2941
+ canDeactivate(component) {
2942
+ return component.canDeactivate ? component.canDeactivate() : true;
2670
2943
  }
2671
- loadData() {
2672
- this.nettyAppsProxy.selectLog(this.record).subscribe({
2673
- next: (data) => {
2674
- this.setData(data, false);
2944
+ }
2945
+
2946
+ class NtybaseModule {
2947
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2948
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, declarations: [Ntybase], exports: [Ntybase] });
2949
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, providers: [
2950
+ {
2951
+ provide: HTTP_INTERCEPTORS,
2952
+ useClass: AuthenticationInterceptor,
2953
+ multi: true,
2675
2954
  },
2676
- error: (err) => this.alertService.showError('@dataLoadFailed', err),
2677
- });
2678
- }
2679
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridLogBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
2680
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: NettyAgGridLogBase, isStandalone: true, selector: "ntybase-ag-grid-log-base", host: { attributes: { "ntybase-id": "NettyAgGridLogBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
2955
+ [CanDeactivateGuard],
2956
+ DatePipe,
2957
+ ] });
2681
2958
  }
2682
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridLogBase, decorators: [{
2683
- type: Component,
2684
- args: [{ selector: 'ntybase-ag-grid-log-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridLogBase' } }]
2959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NtybaseModule, decorators: [{
2960
+ type: NgModule,
2961
+ args: [{
2962
+ declarations: [Ntybase],
2963
+ imports: [],
2964
+ exports: [Ntybase],
2965
+ providers: [
2966
+ {
2967
+ provide: HTTP_INTERCEPTORS,
2968
+ useClass: AuthenticationInterceptor,
2969
+ multi: true,
2970
+ },
2971
+ [CanDeactivateGuard],
2972
+ DatePipe,
2973
+ ],
2974
+ }]
2685
2975
  }] });
2686
2976
 
2687
- class NettyAgGridSaveBase extends NettyAppsBase {
2688
- // Services
2689
- router = inject(Router);
2690
- route = inject(ActivatedRoute);
2691
- commonService = inject(CommonService);
2692
- environment = inject(EnvironmentProxy);
2693
- dialog = inject(MatDialog);
2694
- viewMode = signal('sidenav', ...(ngDevMode ? [{ debugName: "viewMode" }] : []));
2695
- // Input signals
2696
- parameters = input('', ...(ngDevMode ? [{ debugName: "parameters" }] : []));
2697
- // ---------------------------------------------------
2698
- // --- RECORD LIST ---
2699
- // ---------------------------------------------------
2700
- nettyAppsProxy = injectNettyStandardProxy('');
2701
- recordType = signal('', ...(ngDevMode ? [{ debugName: "recordType" }] : []));
2702
- currentItem = signal({}, ...(ngDevMode ? [{ debugName: "currentItem" }] : []));
2703
- initialItem = {};
2704
- // Form tracking
2705
- formChanged = false;
2706
- saveForm;
2707
- // Dialog related properties
2708
- dialogRef = inject((MatDialogRef), { optional: true });
2709
- dialogData = inject(MAT_DIALOG_DATA, { optional: true });
2710
- constructor() {
2711
- super();
2712
- effect(() => {
2713
- this.parameters();
2714
- this.loadDetailData();
2715
- });
2977
+ class Guid {
2978
+ value = this.empty;
2979
+ constructor(value) {
2980
+ if (value) {
2981
+ if (Guid.isValid(value)) {
2982
+ this.value = value;
2983
+ }
2984
+ }
2716
2985
  }
2717
- // Controls the visibility of additional editable fields (e.g., password, extra settings)
2718
- // When true, certain input fields become visible for editing
2719
- updateValid = signal(false, ...(ngDevMode ? [{ debugName: "updateValid" }] : []));
2720
- setUpdateValid(value) {
2721
- this.updateValid.set(value);
2986
+ static newGuid() {
2987
+ return new Guid('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
2988
+ const r = (Math.random() * 16) | 0;
2989
+ const v = c == 'x' ? r : (r & 0x3) | 0x8;
2990
+ return v.toString(16);
2991
+ }));
2722
2992
  }
2723
2993
  /**
2724
- * Initialize parameters. This method is called in ngOnInit or constructor
2994
+ * return all zeros '00000000-0000-0000-0000-000000000000'
2725
2995
  */
2726
- initParameters(urlPath) {
2727
- this.nettyAppsProxy.setURLPath(urlPath);
2728
- this.recordType.set(urlPath);
2996
+ static get empty() {
2997
+ return '00000000-0000-0000-0000-000000000000';
2729
2998
  }
2730
- /**
2731
- * Determine view mode based on current route
2732
- */
2733
- determineViewMode() {
2734
- if (this.embedded() || this.dialogData?.embedded) {
2735
- this.viewMode.set('dialog');
2736
- }
2737
- else if (this.router.url.includes('(rightSidenav:')) {
2738
- this.viewMode.set('sidenav');
2739
- }
2740
- else {
2741
- this.viewMode.set('fullscreen');
2742
- }
2743
- }
2744
- /**
2745
- * Set data to the form while preserving any unsaved changes
2746
- * @param item - Data object of type T to populate the form
2747
- */
2748
- initializeFormData(item) {
2749
- // Merge incoming data with current form state to preserve unsaved changes
2750
- const currentItem = this.currentItem();
2751
- const updatedItem = { ...currentItem, ...item };
2752
- // Create a new instance using the factory method
2753
- const newItem = this.createItemInstance(updatedItem);
2754
- this.currentItem.set(newItem);
2755
- // Update initial item reference for change detection
2756
- this.initialItem = this.createItemInstance(updatedItem);
2757
- // Reset form changed flag
2758
- this.formChanged = false;
2999
+ get empty() {
3000
+ return Guid.empty;
2759
3001
  }
2760
- /**
2761
- * @param data - Data to populate the new instance
2762
- */
2763
- createItemInstance(data) {
2764
- const instance = this.createNewRecord();
2765
- Object.assign(instance, data);
2766
- return instance;
3002
+ static isValid(str) {
3003
+ const validRegex = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i;
3004
+ return validRegex.test(str);
2767
3005
  }
2768
- /**
2769
- * Check for form changes
2770
- */
2771
- ngDoCheck() {
2772
- this.formChanged = !this.isEqual(this.currentItem(), this.initialItem);
3006
+ toString() {
3007
+ return this.value;
2773
3008
  }
2774
- isEqual(item1, item2) {
2775
- return JSON.stringify(item1) === JSON.stringify(item2);
3009
+ toJSON() {
3010
+ return this.value;
2776
3011
  }
2777
3012
  /**
2778
- * Check if can deactivate component
3013
+ * True is guid is empty or not valid
3014
+ * @param str
3015
+ * @returns
2779
3016
  */
2780
- async canDeactivate() {
2781
- if (this.formChanged) {
2782
- const confirmed = await this.alertService.showConfirm('@unsavedChangesConfirm');
2783
- if (!confirmed) {
2784
- return false;
2785
- }
3017
+ static isNullOrEmpty(str) {
3018
+ if (str == null || str == undefined || str.trim() == '' || str == Guid.empty) {
2786
3019
  return true;
2787
3020
  }
2788
- return true;
2789
- }
2790
- getGuidFromParameters() {
2791
- if (this.viewMode() === 'dialog' && this.dialogData) {
2792
- return this.dialogData.parameters || '';
2793
- }
2794
- if (this.parameters()) {
2795
- try {
2796
- return JSON.parse(this.parameters());
2797
- }
2798
- catch (e) {
2799
- return this.parameters();
2800
- }
3021
+ if (!Guid.isValid(str)) {
3022
+ return true;
2801
3023
  }
2802
- return '';
3024
+ return false;
2803
3025
  }
2804
3026
  /**
2805
- * Close sidenav or navigate back
3027
+ * True if the guid is valid and not all zeros (empty)
3028
+ * @param str
3029
+ * @returns
2806
3030
  */
2807
- async closeSidenav() {
2808
- const canDeactivate = await this.canDeactivate();
2809
- if (canDeactivate) {
2810
- if (this.viewMode() === 'dialog' && this.dialogRef) {
2811
- this.dialogRef.close('saved');
2812
- }
2813
- else if (this.viewMode() === 'sidenav') {
2814
- this.formChanged = false;
2815
- this.commonService.clearOutlet();
2816
- }
2817
- else {
2818
- const cleanPath = this.commonService.getCleanUrlPath();
2819
- this.router.navigate([cleanPath]);
2820
- }
2821
- }
3031
+ static isValidAndNotEmpty(str) {
3032
+ return !Guid.isNullOrEmpty(str);
2822
3033
  }
2823
3034
  /**
2824
- * Back button clicked
3035
+ * Return empty guid if the given guid is not valid
3036
+ * @param guid
3037
+ * @returns
2825
3038
  */
2826
- async backClicked() {
2827
- const canDeactivate = await this.canDeactivate();
2828
- if (canDeactivate) {
2829
- if (this.viewMode() === 'dialog' && this.dialogRef) {
2830
- this.dialogRef.close('back');
2831
- }
2832
- else {
2833
- this.commonService.goBack();
2834
- }
3039
+ static emptyWhenNull(guid) {
3040
+ if (Guid.isValidAndNotEmpty(guid)) {
3041
+ return guid;
2835
3042
  }
3043
+ return Guid.empty;
2836
3044
  }
2837
- validateSaveRecord(recordGUID) {
2838
- if (this.saveForm && this.saveForm.invalid) {
2839
- Object.keys(this.saveForm.controls).forEach((key) => {
2840
- const control = this.saveForm.controls[key];
2841
- control.markAsTouched();
2842
- control.markAsDirty();
2843
- });
2844
- this.alertService.showError('@pleaseFillRequiredFields');
2845
- return false;
2846
- }
2847
- // First check if there are any visual form changes
2848
- if (!this.formChanged && recordGUID) {
2849
- this.alertService.showAlert('@noChangesDetected');
2850
- // if (this.closeAfterSave()) {
2851
- // this.closeSidenav();
2852
- // }
2853
- return false;
2854
- }
2855
- return true;
3045
+ }
3046
+
3047
+ ModuleRegistry.registerModules([AllCommunityModule, StatusBarModule, ClientSideRowModelModule, ClipboardModule, ExcelExportModule, ColumnMenuModule,
3048
+ ContextMenuModule, CellSelectionModule, HighlightChangesModule, RowSelectionModule,]);
3049
+ // AgGrid Dark Mode Row Style
3050
+ class NettyAgGridListFilterBase extends NettyAgGridListBase {
3051
+ // ********************************************
3052
+ // *** INPUTS ***
3053
+ // ********************************************
3054
+ // Filter section
3055
+ displayFilter = input(true, ...(ngDevMode ? [{ debugName: "displayFilter" }] : [])); // Does the component display it's filter section when embadded
3056
+ _displayFilter = computed(() => this.displayFilter() ?? true, ...(ngDevMode ? [{ debugName: "_displayFilter" }] : [])); // Computed version of displayFilter to prevent undefined
3057
+ isFilterValid = signal(true, ...(ngDevMode ? [{ debugName: "isFilterValid" }] : [])); // Can the filter be used
3058
+ isFilterExpanded = linkedSignal({ ...(ngDevMode ? { debugName: "isFilterExpanded" } : {}), // Is the filter component expanded
3059
+ source: () => ({
3060
+ embedded: this._isEmbedded(),
3061
+ displayFilter: this._displayFilter(),
3062
+ valid: this.isFilterValid(),
3063
+ }),
3064
+ computation: (s) => {
3065
+ if (s.embedded || !s.displayFilter)
3066
+ return false;
3067
+ return s.valid;
3068
+ } });
3069
+ filterRefreshTrigger = signal(0, ...(ngDevMode ? [{ debugName: "filterRefreshTrigger" }] : []));
3070
+ constructor() {
3071
+ super();
3072
+ effect(() => {
3073
+ if (this.hasValidValue(this.parameterGUID())) {
3074
+ this.isFilterExpanded.set(false);
3075
+ this.setFilter();
3076
+ this.loadData();
3077
+ }
3078
+ });
2856
3079
  }
2857
- /**
2858
- * Save data to API
2859
- * Handles both create and update operations based on record existence
2860
- */
2861
- saveRecord() {
2862
- if (!this.validateSaveRecord(this.currentItem().getPK())) {
2863
- return;
2864
- }
2865
- if (this.currentItem().getPK()) {
2866
- this.updateRecord();
3080
+ async ngOnInit() {
3081
+ await super.ngOnInit();
3082
+ }
3083
+ // *********************************************************
3084
+ // *** Data Management Functions ***
3085
+ // *********************************************************
3086
+ loadData() {
3087
+ if (Guid.isNullOrEmpty(this.parameterGUID())) {
3088
+ this.setData([], true);
2867
3089
  return;
2868
3090
  }
2869
- this.insertRecord();
2870
- }
2871
- /**
2872
- * Create new record
2873
- */
2874
- insertRecord() {
2875
- const createData = {};
2876
- const currentItem = this.currentItem();
2877
- Object.keys(currentItem).forEach((key) => {
2878
- if (currentItem[key] !== undefined && currentItem[key] !== null && currentItem[key] !== '') {
2879
- createData[key] = currentItem[key];
2880
- }
2881
- });
2882
- this.nettyAppsProxy.insert(createData).subscribe({
2883
- next: (newRecord) => {
2884
- this.initializeFormData(newRecord);
2885
- this.commonService.notifyUpdate(this.recordType(), 'add', newRecord);
2886
- this.closeSidenav();
2887
- this.alertService.showSuccess('@recordCreatedSuccessfully');
3091
+ this.nettyAppsProxy.select(this.record).subscribe({
3092
+ next: (data) => {
3093
+ this.setData(data, false);
2888
3094
  },
2889
- error: (err) => this.alertService.showError('@creationFailed', err),
3095
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
2890
3096
  });
2891
3097
  }
2892
- /**
2893
- * Update record
2894
- */
2895
- updateRecord() {
2896
- const changes = this.initialItem.compare(this.currentItem());
2897
- const updateData = this.createNewRecord();
2898
- Object.assign(updateData, changes);
2899
- updateData.setPK(this.currentItem().getPK());
2900
- this.nettyAppsProxy.update(updateData).subscribe({
2901
- next: (updatedRecord) => {
2902
- this.initializeFormData(updatedRecord);
2903
- this.commonService.notifyUpdate(this.recordType(), 'update', updatedRecord);
2904
- this.closeSidenav();
2905
- this.alertService.showSuccess('@recordUpdatedSuccessfully');
2906
- },
2907
- error: (err) => this.alertService.showError('@updateFailed', err),
2908
- });
3098
+ async refreshData() {
3099
+ try {
3100
+ this.refreshFilterData();
3101
+ }
3102
+ catch (err) {
3103
+ this.alertService.showError(err);
3104
+ }
2909
3105
  }
2910
3106
  /**
2911
- * Create new record
3107
+ * Triggers the filter component to refresh its data
2912
3108
  */
2913
- async createNewData() {
2914
- // If no GUID provided, initialize a new record
2915
- let newRecord = this.createNewRecord();
2916
- newRecord = await lastValueFrom(this.nettyAppsProxy.initRecord(newRecord))
2917
- .catch((er) => {
2918
- this.alertService.showError('@initRecordFailed:', er);
2919
- return this.createNewRecord();
2920
- });
2921
- this.initializeFormData(newRecord);
2922
- this.updateValid.set(true);
3109
+ refreshFilterData() {
3110
+ this.filterRefreshTrigger.update(val => val > 10000 ? 1 : val + 1);
2923
3111
  }
2924
- /**
2925
- * Load data from API based on GUID
2926
- * Handles both new record creation and existing record editing
2927
- * guid - Unique identifier of the record
2928
- */
2929
- async loadDetailData() {
2930
- const guid = this.getGuidFromParameters();
2931
- if (!guid) {
2932
- await this.createNewData();
2933
- return;
2934
- }
2935
- // Fetch existing record from API
2936
- this.nettyAppsProxy.selectGUID(guid).subscribe({
2937
- next: (data) => {
2938
- const record = this.createItemInstance(data);
2939
- if (!record || !record.getPK()) {
2940
- this.alertService.showError('@recordNotFound');
2941
- const cleanPath = this.commonService.getCleanUrlPath();
2942
- this.router.navigate([cleanPath]);
2943
- return;
2944
- }
2945
- this.initializeFormData(record);
2946
- this.alertService.showSuccess('@dataLoadSuccess');
2947
- // Ensure sidenav is visible when in sidenav mode
2948
- if (this.viewMode() === 'sidenav') {
2949
- this.commonService.toggleRightSidenav(true);
2950
- }
2951
- },
2952
- error: (err) => {
2953
- this.alertService.showError('@dataLoadFailed');
2954
- this.commonService.toggleRightSidenav(false);
2955
- // Redirect to user list on error in fullscreen mode
2956
- if (this.viewMode() === 'fullscreen') {
2957
- const cleanPath = this.commonService.getCleanUrlPath();
2958
- this.router.navigate([cleanPath]);
2959
- }
2960
- },
2961
- });
3112
+ onReverseIsFilterValid() {
3113
+ this.isFilterValid.update((a) => !a);
2962
3114
  }
2963
- // ***************************************************
2964
- // *** gotoURL Methods ***
2965
- // ***************************************************
2966
- gotoURL(routePrefix, rightSidenav = [], parameters, type, dialogComponent = null, isNewTab = false, isPopup = this._isEmbedded()) {
2967
- const baseHref = this.environment.getBaseHref().endsWith('/')
2968
- ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
2969
- : this.environment.getBaseHref();
2970
- const navigationExtras = {
2971
- queryParams: {
2972
- parameters: JSON.stringify(parameters),
2973
- ...(type && { type }),
2974
- isNewTab: isNewTab || undefined,
2975
- },
2976
- queryParamsHandling: 'merge',
2977
- };
2978
- if (isNewTab) {
2979
- const fullUrl = this.router
2980
- .createUrlTree([baseHref, ...routePrefix, ...rightSidenav], navigationExtras)
2981
- .toString();
2982
- window.open(fullUrl, '_blank');
2983
- return;
2984
- }
2985
- if (isPopup && dialogComponent) {
2986
- this.dialog
2987
- .open(dialogComponent, {
2988
- data: {
2989
- parameters: parameters,
2990
- mode: type || 'edit',
2991
- embedded: true,
2992
- },
2993
- maxWidth: '100vw',
2994
- disableClose: true,
2995
- hasBackdrop: false,
2996
- })
2997
- .afterClosed();
2998
- return;
2999
- }
3000
- // Log control
3001
- if (rightSidenav.length == 0 || rightSidenav[0] === 'log') {
3002
- this.router.navigate([baseHref, ...routePrefix, ...rightSidenav], navigationExtras);
3003
- return;
3115
+ // *****************************************
3116
+ // *** Logging Functions ***
3117
+ // *****************************************
3118
+ logInputs(message) {
3119
+ if (!message || message.length < 1) {
3120
+ message = 'AgGridListFilterBase - Inputs log';
3004
3121
  }
3005
- // In all other cases, open the side menu
3006
- this.router
3007
- .navigate([
3008
- {
3009
- outlets: {
3010
- primary: routePrefix,
3011
- rightSidenav: [...routePrefix, ...rightSidenav],
3012
- },
3013
- },
3014
- ], navigationExtras)
3015
- .then(() => {
3016
- // Ensure sidenav is opened after navigation
3017
- this.commonService.toggleRightSidenav(true);
3018
- });
3019
- }
3020
- popupGotoURL(urlSegments) {
3021
- const baseHref = this.environment.getBaseHref().endsWith('/')
3022
- ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
3023
- : this.environment.getBaseHref();
3024
- this.router.navigate([
3025
- {
3026
- outlets: {
3027
- primary: [baseHref, ...urlSegments],
3028
- rightSidenav: null,
3029
- },
3030
- },
3031
- ]);
3122
+ const inputs = {
3123
+ "popupFilterValid": this.popupFilterValid(),
3124
+ "_isPopupFilterValid": this._isPopupFilterValid(),
3125
+ "popupValid": this.popupValid(),
3126
+ "_isPopupValid": this._isPopupValid(),
3127
+ "componantParameterGUID": this.componantParameterGUID(),
3128
+ "componantParameterType": this.componantParameterType(),
3129
+ "embedded": this.embedded(),
3130
+ "_isEmbedded": this._isEmbedded(),
3131
+ "displayFilter": this.displayFilter(),
3132
+ "_displayFilter": this._displayFilter(),
3133
+ "isFilterValid": this.isFilterValid(),
3134
+ "isFilterExpanded": this.isFilterExpanded(),
3135
+ };
3136
+ console.log(message, inputs);
3032
3137
  }
3033
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridSaveBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
3034
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: NettyAgGridSaveBase, isStandalone: true, selector: "ntybase-ag-grid-save-base", inputs: { parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "saveForm", first: true, predicate: ["saveForm"], descendants: true }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
3138
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridListFilterBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
3139
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: NettyAgGridListFilterBase, isStandalone: true, selector: "ntybase-ag-grid-list-filter-base", inputs: { displayFilter: { classPropertyName: "displayFilter", publicName: "displayFilter", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ntybase-id": "NettyAgGridListFilterBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
3035
3140
  }
3036
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridSaveBase, decorators: [{
3141
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridListFilterBase, decorators: [{
3037
3142
  type: Component,
3038
- args: [{ selector: 'ntybase-ag-grid-save-base', imports: [], template: `` }]
3039
- }], ctorParameters: () => [], propDecorators: { parameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameters", required: false }] }], saveForm: [{
3040
- type: ViewChild,
3041
- args: ['saveForm']
3042
- }] } });
3143
+ args: [{ selector: 'ntybase-ag-grid-list-filter-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridListFilterBase' } }]
3144
+ }], ctorParameters: () => [], propDecorators: { displayFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayFilter", required: false }] }] } });
3043
3145
 
3044
- class RangeDateTimeFilter {
3045
- params;
3046
- filterText = '';
3047
- conditions = [];
3048
- // Dil servisini inject edin
3049
- i18nService = inject(I18nService);
3050
- translateService = inject(TranslateService);
3051
- // Türkçe ve İngilizce özel anahtar kelimeler
3052
- specialKeywords = {
3053
- today: 'today',
3054
- bugün: 'today',
3055
- yesterday: 'yesterday',
3056
- dün: 'yesterday',
3057
- thisweek: 'thisWeek',
3058
- 'bu hafta': 'thisWeek',
3059
- thismonth: 'thisMonth',
3060
- 'bu ay': 'thisMonth',
3061
- };
3062
- agInit(params) {
3063
- this.params = params;
3064
- }
3065
- onFilterTextChanged(event) {
3066
- this.filterText = event.target.value;
3067
- this.parseFilterText();
3068
- this.params.filterChangedCallback();
3069
- }
3070
- parseFilterText() {
3071
- this.conditions = [];
3072
- if (!this.filterText.trim()) {
3073
- return;
3074
- }
3075
- // Virgülle ayrılmış parçaları al ve temizle
3076
- const parts = this.filterText
3077
- .split(',')
3078
- .map((part) => part.trim())
3079
- .filter((part) => part !== '');
3080
- for (const part of parts) {
3081
- // Aralık kontrolü (.. içeriyor mu) - ÖNCE aralık kontrolü yap
3082
- if (part.includes('..')) {
3083
- const rangeParts = part.split('..');
3084
- if (rangeParts.length === 2) {
3085
- const startStr = rangeParts[0].trim();
3086
- const endStr = rangeParts[1].trim();
3087
- const startDate = this.parseDateForRange(startStr, false);
3088
- const endDate = this.parseDateForRange(endStr, true);
3089
- if (startDate && endDate) {
3090
- // Tarihleri doğru sırala (küçükten büyüğe)
3091
- const sortedStart = startDate < endDate ? startDate : endDate;
3092
- const sortedEnd = startDate < endDate ? endDate : startDate;
3093
- this.conditions.push({
3094
- type: 'range',
3095
- start: sortedStart,
3096
- end: sortedEnd,
3097
- });
3098
- }
3099
- }
3100
- }
3101
- else {
3102
- // Özel anahtar kelime kontrolü (Türkçe ve İngilizce)
3103
- const normalizedPart = part.toLowerCase();
3104
- if (this.specialKeywords[normalizedPart]) {
3105
- this.conditions.push({
3106
- type: 'special',
3107
- special: this.specialKeywords[normalizedPart],
3108
- });
3109
- continue;
3110
- }
3111
- // Tek tarih kontrolü
3112
- const date = this.parseDate(part);
3113
- if (date) {
3114
- this.conditions.push({
3115
- type: 'date',
3116
- date: date,
3117
- });
3118
- }
3119
- }
3120
- }
3121
- }
3122
- parseDateForRange(dateString, isEndDate) {
3123
- if (!dateString)
3124
- return null;
3125
- // Özel anahtar kelimeler için tarih dönüşümü
3126
- const normalizedString = dateString.toLowerCase();
3127
- if (this.specialKeywords[normalizedString]) {
3128
- const specialType = this.specialKeywords[normalizedString];
3129
- const range = this.getSpecialDateRange(specialType);
3130
- return isEndDate ? range.end : range.start;
3146
+ class NettyAgGridLogBase extends NettyAgGridBase {
3147
+ // ---------------------------------------------------
3148
+ // --- RECORD LIST ---
3149
+ // ---------------------------------------------------
3150
+ nettyAppsProxy = injectNettyStandardLogProxy(this.componentName());
3151
+ /**
3152
+ * Component initialization lifecycle hook
3153
+ */
3154
+ async ngOnInit() {
3155
+ this.nettyAppsProxy.setURLPath(this.componentName());
3156
+ await this.setAccessRights(true);
3157
+ const savedSearchValue = sessionStorage.getItem(this.searchValueName());
3158
+ if (savedSearchValue) {
3159
+ this.searchValue.set(savedSearchValue);
3131
3160
  }
3132
- return this.parseDate(dateString);
3161
+ this.loadData();
3162
+ // Load user grid preferences
3163
+ await this.nettyAgGridService.copyGridUserPereferenceToLocal(this.preferenceType());
3164
+ await this.AfterOnInit();
3133
3165
  }
3134
- // Mevcut dili kontrol eden yardımcı metod
3135
- isTurkish() {
3136
- const currentLang = this.i18nService.language.toLowerCase();
3137
- return (currentLang === 'tr' ||
3138
- currentLang === 'türkçe' ||
3139
- currentLang === 'tr-tr');
3166
+ loadData() {
3167
+ this.nettyAppsProxy.selectLog(this.record).subscribe({
3168
+ next: (data) => {
3169
+ this.setData(data, false);
3170
+ },
3171
+ error: (err) => this.alertService.showError('@dataLoadFailed', err),
3172
+ });
3140
3173
  }
3141
- parseDate(dateString) {
3142
- if (!dateString)
3143
- return null;
3144
- // Mevcut dile göre formatları belirle
3145
- const isTurkish = this.isTurkish();
3146
- // Tarih formatları - ÖNCE saat içeren formatlar
3147
- const formats = [
3148
- // ISO format: YYYY-AA-GG SS:DD (her dilde aynı)
3149
- /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{2})$/,
3150
- // Dile göre formatlar
3151
- ...(isTurkish
3152
- ? [
3153
- // Türkçe format: GG.AA.YYYY SS:DD (., /, - ile)
3154
- /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4}) (\d{1,2}):(\d{2})$/,
3155
- // Türkçe format: GG.AA.YYYY (., /, - ile)
3156
- /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4})$/,
3157
- ]
3158
- : [
3159
- // İngilizce/USA format: AA/GG/YYYY SS:DD (/, ., - ile)
3160
- /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4}) (\d{1,2}):(\d{2})$/,
3161
- // İngilizce/USA format: AA/GG/YYYY (/, ., - ile)
3162
- /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4})$/,
3163
- ]),
3164
- // Sadece tarih formatları (saat yok)
3165
- /^(\d{4})-(\d{1,2})-(\d{1,2})$/, // YYYY-AA-GG (ISO)
3166
- ];
3167
- for (const format of formats) {
3168
- const match = dateString.match(format);
3169
- if (match) {
3170
- let year, month, day, hours = 0, minutes = 0;
3171
- if (format === formats[0]) {
3172
- // ISO: YYYY-AA-GG SS:DD
3173
- year = parseInt(match[1], 10);
3174
- month = parseInt(match[2], 10) - 1;
3175
- day = parseInt(match[3], 10);
3176
- hours = parseInt(match[4], 10);
3177
- minutes = parseInt(match[5], 10);
3178
- }
3179
- else if (isTurkish && format === formats[1]) {
3180
- // Türkçe: GG.AA.YYYY SS:DD
3181
- day = parseInt(match[1], 10);
3182
- month = parseInt(match[2], 10) - 1;
3183
- year = parseInt(match[3], 10);
3184
- hours = parseInt(match[4], 10);
3185
- minutes = parseInt(match[5], 10);
3186
- }
3187
- else if (!isTurkish && format === formats[1]) {
3188
- // İngilizce: AA/GG/YYYY SS:DD
3189
- month = parseInt(match[1], 10) - 1;
3190
- day = parseInt(match[2], 10);
3191
- year = parseInt(match[3], 10);
3192
- hours = parseInt(match[4], 10);
3193
- minutes = parseInt(match[5], 10);
3194
- }
3195
- else if (isTurkish && format === formats[2]) {
3196
- // Türkçe: GG.AA.YYYY
3197
- day = parseInt(match[1], 10);
3198
- month = parseInt(match[2], 10) - 1;
3199
- year = parseInt(match[3], 10);
3200
- }
3201
- else if (!isTurkish && format === formats[2]) {
3202
- // İngilizce: AA/GG/YYYY
3203
- month = parseInt(match[1], 10) - 1;
3204
- day = parseInt(match[2], 10);
3205
- year = parseInt(match[3], 10);
3206
- }
3207
- else if (format === formats[3]) {
3208
- // ISO: YYYY-AA-GG
3209
- year = parseInt(match[1], 10);
3210
- month = parseInt(match[2], 10) - 1;
3211
- day = parseInt(match[3], 10);
3212
- }
3213
- else {
3214
- continue;
3215
- }
3216
- // Tarih geçerlilik kontrolü
3217
- const date = new Date(year, month, day, hours, minutes);
3218
- if (date.getFullYear() === year &&
3219
- date.getMonth() === month &&
3220
- date.getDate() === day &&
3221
- date.getHours() === hours &&
3222
- date.getMinutes() === minutes) {
3223
- return date;
3224
- }
3225
- }
3226
- }
3227
- return null;
3174
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridLogBase, deps: null, target: i0.ɵɵFactoryTarget.Component });
3175
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: NettyAgGridLogBase, isStandalone: true, selector: "ntybase-ag-grid-log-base", host: { attributes: { "ntybase-id": "NettyAgGridLogBase" } }, usesInheritance: true, ngImport: i0, template: ``, isInline: true });
3176
+ }
3177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridLogBase, decorators: [{
3178
+ type: Component,
3179
+ args: [{ selector: 'ntybase-ag-grid-log-base', imports: [], template: ``, host: { 'ntybase-id': 'NettyAgGridLogBase' } }]
3180
+ }] });
3181
+
3182
+ class NettyAgGridSaveBase extends NettyAppsBase {
3183
+ // Services
3184
+ router = inject(Router);
3185
+ route = inject(ActivatedRoute);
3186
+ commonService = inject(CommonService);
3187
+ environment = inject(EnvironmentProxy);
3188
+ dialog = inject(MatDialog);
3189
+ viewMode = signal('sidenav', ...(ngDevMode ? [{ debugName: "viewMode" }] : []));
3190
+ // Input signals
3191
+ parameters = input('', ...(ngDevMode ? [{ debugName: "parameters" }] : []));
3192
+ // ---------------------------------------------------
3193
+ // --- RECORD LIST ---
3194
+ // ---------------------------------------------------
3195
+ nettyAppsProxy = injectNettyStandardProxy('');
3196
+ recordType = signal('', ...(ngDevMode ? [{ debugName: "recordType" }] : []));
3197
+ currentItem = signal({}, ...(ngDevMode ? [{ debugName: "currentItem" }] : []));
3198
+ initialItem = {};
3199
+ // Form tracking
3200
+ formChanged = false;
3201
+ saveForm;
3202
+ // Dialog related properties
3203
+ dialogRef = inject((MatDialogRef), { optional: true });
3204
+ dialogData = inject(MAT_DIALOG_DATA, { optional: true });
3205
+ constructor() {
3206
+ super();
3207
+ effect(() => {
3208
+ this.parameters();
3209
+ this.loadDetailData();
3210
+ });
3228
3211
  }
3229
- getSpecialDateRange(special) {
3230
- const now = new Date();
3231
- const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
3232
- switch (special) {
3233
- case 'today':
3234
- const tomorrow = new Date(today);
3235
- tomorrow.setDate(tomorrow.getDate() + 1);
3236
- return { start: today, end: tomorrow };
3237
- case 'yesterday':
3238
- const yesterday = new Date(today);
3239
- yesterday.setDate(yesterday.getDate() - 1);
3240
- const yesterdayEnd = new Date(yesterday);
3241
- yesterdayEnd.setDate(yesterdayEnd.getDate() + 1);
3242
- return { start: yesterday, end: yesterdayEnd };
3243
- case 'thisWeek':
3244
- const startOfWeek = new Date(today);
3245
- startOfWeek.setDate(today.getDate() - today.getDay());
3246
- const endOfWeek = new Date(startOfWeek);
3247
- endOfWeek.setDate(startOfWeek.getDate() + 7);
3248
- return { start: startOfWeek, end: endOfWeek };
3249
- case 'thisMonth':
3250
- const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
3251
- const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
3252
- return { start: startOfMonth, end: endOfMonth };
3253
- default:
3254
- return { start: today, end: today };
3255
- }
3212
+ // Controls the visibility of additional editable fields (e.g., password, extra settings)
3213
+ // When true, certain input fields become visible for editing
3214
+ updateValid = signal(false, ...(ngDevMode ? [{ debugName: "updateValid" }] : []));
3215
+ setUpdateValid(value) {
3216
+ this.updateValid.set(value);
3256
3217
  }
3257
- doesFilterPass(params) {
3258
- const field = this.params.colDef.field;
3259
- if (!field)
3260
- return true;
3261
- const cellValue = params.data ? params.data[field] : null;
3262
- // Eğer filtre yoksa tüm satırları göster
3263
- if (this.conditions.length === 0) {
3264
- return true;
3265
- }
3266
- // Hücre değeri null/undefined ise filtrele
3267
- if (!cellValue) {
3268
- return false;
3269
- }
3270
- // Hücre değerini Date'e dönüştür
3271
- let cellDate;
3272
- if (cellValue instanceof Date) {
3273
- cellDate = cellValue;
3218
+ /**
3219
+ * Initialize parameters. This method is called in ngOnInit or constructor
3220
+ */
3221
+ initParameters(urlPath) {
3222
+ this.nettyAppsProxy.setURLPath(urlPath);
3223
+ this.recordType.set(urlPath);
3224
+ }
3225
+ /**
3226
+ * Determine view mode based on current route
3227
+ */
3228
+ determineViewMode() {
3229
+ if (this.embedded() || this.dialogData?.embedded) {
3230
+ this.viewMode.set('dialog');
3274
3231
  }
3275
- else if (typeof cellValue === 'string') {
3276
- // String ise Date'e parse et
3277
- cellDate = new Date(cellValue);
3278
- if (isNaN(cellDate.getTime())) {
3279
- return false; // Geçersiz tarih
3280
- }
3232
+ else if (this.router.url.includes('(rightSidenav:')) {
3233
+ this.viewMode.set('sidenav');
3281
3234
  }
3282
3235
  else {
3283
- return false; // Desteklenmeyen tip
3236
+ this.viewMode.set('fullscreen');
3284
3237
  }
3285
- const cellTime = cellDate.getTime();
3286
- // Koşullardan herhangi birini sağlıyor mu kontrol et
3287
- return this.conditions.some((condition) => {
3288
- switch (condition.type) {
3289
- case 'date':
3290
- if (!condition.date)
3291
- return false;
3292
- const conditionTime = condition.date.getTime();
3293
- const nextDay = new Date(condition.date);
3294
- nextDay.setDate(nextDay.getDate() + 1);
3295
- return cellTime >= conditionTime && cellTime < nextDay.getTime();
3296
- case 'range':
3297
- if (!condition.start || !condition.end)
3298
- return false;
3299
- const startTime = condition.start.getTime();
3300
- const endTime = condition.end.getTime();
3301
- return cellTime >= startTime && cellTime < endTime;
3302
- case 'special':
3303
- if (!condition.special)
3304
- return false;
3305
- const range = this.getSpecialDateRange(condition.special);
3306
- return (cellTime >= range.start.getTime() && cellTime < range.end.getTime());
3307
- default:
3308
- return false;
3309
- }
3310
- });
3311
3238
  }
3312
- isFilterActive() {
3313
- return this.conditions.length > 0;
3239
+ /**
3240
+ * Set data to the form while preserving any unsaved changes
3241
+ * @param item - Data object of type T to populate the form
3242
+ */
3243
+ initializeFormData(item) {
3244
+ // Merge incoming data with current form state to preserve unsaved changes
3245
+ const currentItem = this.currentItem();
3246
+ const updatedItem = { ...currentItem, ...item };
3247
+ // Create a new instance using the factory method
3248
+ const newItem = this.createItemInstance(updatedItem);
3249
+ this.currentItem.set(newItem);
3250
+ // Update initial item reference for change detection
3251
+ this.initialItem = this.createItemInstance(updatedItem);
3252
+ // Reset form changed flag
3253
+ this.formChanged = false;
3314
3254
  }
3315
- getModel() {
3316
- if (this.isFilterActive()) {
3317
- return {
3318
- filterType: 'custom',
3319
- filterText: this.filterText,
3320
- conditions: this.conditions,
3321
- };
3322
- }
3323
- return null;
3255
+ /**
3256
+ * @param data - Data to populate the new instance
3257
+ */
3258
+ createItemInstance(data) {
3259
+ const instance = this.createNewRecord();
3260
+ Object.assign(instance, data);
3261
+ return instance;
3324
3262
  }
3325
- setModel(model) {
3326
- if (model && model.filterText) {
3327
- this.filterText = model.filterText;
3328
- this.parseFilterText(); // Modelden set ederken koşulları tekrar parse et
3329
- }
3330
- else {
3331
- this.filterText = '';
3332
- this.conditions = [];
3333
- }
3263
+ /**
3264
+ * Check for form changes
3265
+ */
3266
+ ngDoCheck() {
3267
+ this.formChanged = !this.isEqual(this.currentItem(), this.initialItem);
3334
3268
  }
3335
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeDateTimeFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3336
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeDateTimeFilter, isStandalone: true, selector: "ntybase-range-date-time-filter", host: { attributes: { "ntybase-id": "RangeDateTimeFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3337
- }
3338
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeDateTimeFilter, decorators: [{
3339
- type: Component,
3340
- args: [{ selector: 'ntybase-range-date-time-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeDateTimeFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n" }]
3341
- }] });
3342
-
3343
- class RangeNumberFilter {
3344
- params;
3345
- filterText = '';
3346
- conditions = [];
3347
- agInit(params) {
3348
- this.params = params;
3269
+ isEqual(item1, item2) {
3270
+ return JSON.stringify(item1) === JSON.stringify(item2);
3349
3271
  }
3350
- onFilterTextChanged(event) {
3351
- this.filterText = event.target.value;
3352
- this.parseFilterText();
3353
- this.params.filterChangedCallback();
3272
+ /**
3273
+ * Check if can deactivate component
3274
+ */
3275
+ async canDeactivate() {
3276
+ if (this.formChanged) {
3277
+ const confirmed = await this.alertService.showConfirm('@unsavedChangesConfirm');
3278
+ if (!confirmed) {
3279
+ return false;
3280
+ }
3281
+ return true;
3282
+ }
3283
+ return true;
3354
3284
  }
3355
- parseFilterText() {
3356
- this.conditions = [];
3357
- if (!this.filterText.trim()) {
3358
- return;
3285
+ getGuidFromParameters() {
3286
+ if (this.viewMode() === 'dialog' && this.dialogData) {
3287
+ return this.dialogData.parameters || '';
3359
3288
  }
3360
- const parts = this.filterText
3361
- .split(',')
3362
- .map((part) => part.trim())
3363
- .filter((part) => part !== '');
3364
- for (const part of parts) {
3365
- // Hariç tutma kontrolü (! ile başlıyor mu)
3366
- if (part.startsWith('!')) {
3367
- const excludePart = part.substring(1).trim();
3368
- // Hariç tutma için aralık kontrolü
3369
- if (excludePart.includes('..')) {
3370
- const rangeParts = excludePart.split('..');
3371
- if (rangeParts.length === 2) {
3372
- const minStr = rangeParts[0].trim();
3373
- const maxStr = rangeParts[1].trim();
3374
- // !..10 formatı (max hariç)
3375
- if (minStr === '' && maxStr !== '') {
3376
- const max = Number(maxStr);
3377
- if (!isNaN(max)) {
3378
- this.conditions.push({
3379
- type: 'exclude',
3380
- min: -Infinity,
3381
- max: max,
3382
- });
3383
- }
3384
- }
3385
- // !10.. formatı (min hariç)
3386
- else if (minStr !== '' && maxStr === '') {
3387
- const min = Number(minStr);
3388
- if (!isNaN(min)) {
3389
- this.conditions.push({
3390
- type: 'exclude',
3391
- min: min,
3392
- max: Infinity,
3393
- });
3394
- }
3395
- }
3396
- // !min..max formatı (aralık hariç)
3397
- else if (minStr !== '' && maxStr !== '') {
3398
- const min = Number(minStr);
3399
- const max = Number(maxStr);
3400
- if (!isNaN(min) && !isNaN(max)) {
3401
- this.conditions.push({
3402
- type: 'exclude',
3403
- min: Math.min(min, max),
3404
- max: Math.max(min, max),
3405
- });
3406
- }
3407
- }
3408
- }
3409
- }
3410
- else {
3411
- // Tek değer hariç tutma
3412
- const value = Number(excludePart);
3413
- if (!isNaN(value)) {
3414
- this.conditions.push({
3415
- type: 'exclude',
3416
- value: value,
3417
- });
3418
- }
3419
- }
3289
+ if (this.parameters()) {
3290
+ try {
3291
+ return JSON.parse(this.parameters());
3292
+ }
3293
+ catch (e) {
3294
+ return this.parameters();
3295
+ }
3296
+ }
3297
+ return '';
3298
+ }
3299
+ /**
3300
+ * Close sidenav or navigate back
3301
+ */
3302
+ async closeSidenav() {
3303
+ const canDeactivate = await this.canDeactivate();
3304
+ if (canDeactivate) {
3305
+ if (this.viewMode() === 'dialog' && this.dialogRef) {
3306
+ this.dialogRef.close('saved');
3420
3307
  }
3421
- // Aralık kontrolü (.. içeriyor mu)
3422
- else if (part.includes('..')) {
3423
- const rangeParts = part.split('..');
3424
- if (rangeParts.length === 2) {
3425
- const minStr = rangeParts[0].trim();
3426
- const maxStr = rangeParts[1].trim();
3427
- // ..10 formatı (max belirtilmiş)
3428
- if (minStr === '' && maxStr !== '') {
3429
- const max = Number(maxStr);
3430
- if (!isNaN(max)) {
3431
- this.conditions.push({
3432
- type: 'range',
3433
- min: -Infinity,
3434
- max: max,
3435
- });
3436
- }
3437
- }
3438
- // 10.. formatı (min belirtilmiş)
3439
- else if (minStr !== '' && maxStr === '') {
3440
- const min = Number(minStr);
3441
- if (!isNaN(min)) {
3442
- this.conditions.push({
3443
- type: 'range',
3444
- min: min,
3445
- max: Infinity,
3446
- });
3447
- }
3448
- }
3449
- // min..max formatı
3450
- else if (minStr !== '' && maxStr !== '') {
3451
- const min = Number(minStr);
3452
- const max = Number(maxStr);
3453
- if (!isNaN(min) && !isNaN(max)) {
3454
- this.conditions.push({
3455
- type: 'range',
3456
- min: Math.min(min, max),
3457
- max: Math.max(min, max),
3458
- });
3459
- }
3460
- }
3461
- }
3308
+ else if (this.viewMode() === 'sidenav') {
3309
+ this.formChanged = false;
3310
+ this.commonService.clearOutlet();
3462
3311
  }
3463
3312
  else {
3464
- // Tek değer kontrolü
3465
- const value = Number(part);
3466
- if (!isNaN(value)) {
3467
- this.conditions.push({
3468
- type: 'value',
3469
- value: value,
3470
- });
3471
- }
3313
+ const cleanPath = this.commonService.getCleanUrlPath();
3314
+ this.router.navigate([cleanPath]);
3472
3315
  }
3473
3316
  }
3474
3317
  }
3475
- doesFilterPass(params) {
3476
- const cellValue = this.params.getValue(params.node);
3477
- // Eğer filtre yoksa tüm satırları göster
3478
- if (this.conditions.length === 0) {
3479
- return true;
3318
+ /**
3319
+ * Back button clicked
3320
+ */
3321
+ async backClicked() {
3322
+ const canDeactivate = await this.canDeactivate();
3323
+ if (canDeactivate) {
3324
+ if (this.viewMode() === 'dialog' && this.dialogRef) {
3325
+ this.dialogRef.close('back');
3326
+ }
3327
+ else {
3328
+ this.commonService.goBack();
3329
+ }
3480
3330
  }
3481
- // Hücre değeri null/undefined ise veya sayı değilse filtrele
3482
- if (cellValue == null || typeof cellValue !== 'number') {
3331
+ }
3332
+ validateSaveRecord(recordGUID) {
3333
+ if (this.saveForm && this.saveForm.invalid) {
3334
+ Object.keys(this.saveForm.controls).forEach((key) => {
3335
+ const control = this.saveForm.controls[key];
3336
+ control.markAsTouched();
3337
+ control.markAsDirty();
3338
+ });
3339
+ this.alertService.showError('@pleaseFillRequiredFields');
3483
3340
  return false;
3484
3341
  }
3485
- // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
3486
- const passesAnyCondition = this.conditions.some((condition) => {
3487
- if (condition.type === 'range' &&
3488
- condition.min !== undefined &&
3489
- condition.max !== undefined) {
3490
- // Aralık koşulu: değer aralık içinde olmalı
3491
- return cellValue >= condition.min && cellValue <= condition.max;
3492
- }
3493
- else if (condition.type === 'value' && condition.value !== undefined) {
3494
- // Değer koşulu: değer eşit olmalı
3495
- return cellValue === condition.value;
3496
- }
3497
- else if (condition.type === 'exclude') {
3498
- if (condition.value !== undefined) {
3499
- // Tek değer hariç tutma: değer eşit olmamalı
3500
- return cellValue !== condition.value;
3501
- }
3502
- else if (condition.min !== undefined && condition.max !== undefined) {
3503
- // Aralık hariç tutma: değer aralık dışında olmalı
3504
- return !(cellValue >= condition.min && cellValue <= condition.max);
3505
- }
3506
- }
3342
+ // First check if there are any visual form changes
3343
+ if (!this.formChanged && recordGUID) {
3344
+ this.alertService.showAlert('@noChangesDetected');
3345
+ // if (this.closeAfterSave()) {
3346
+ // this.closeSidenav();
3347
+ // }
3507
3348
  return false;
3349
+ }
3350
+ return true;
3351
+ }
3352
+ /**
3353
+ * Save data to API
3354
+ * Handles both create and update operations based on record existence
3355
+ */
3356
+ saveRecord() {
3357
+ if (!this.validateSaveRecord(this.currentItem().getPK())) {
3358
+ return;
3359
+ }
3360
+ if (this.currentItem().getPK()) {
3361
+ this.updateRecord();
3362
+ return;
3363
+ }
3364
+ this.insertRecord();
3365
+ }
3366
+ /**
3367
+ * Create new record
3368
+ */
3369
+ insertRecord() {
3370
+ const createData = {};
3371
+ const currentItem = this.currentItem();
3372
+ Object.keys(currentItem).forEach((key) => {
3373
+ if (currentItem[key] !== undefined && currentItem[key] !== null && currentItem[key] !== '') {
3374
+ createData[key] = currentItem[key];
3375
+ }
3376
+ });
3377
+ this.nettyAppsProxy.insert(createData).subscribe({
3378
+ next: (newRecord) => {
3379
+ this.initializeFormData(newRecord);
3380
+ this.commonService.notifyUpdate(this.recordType(), 'add', newRecord);
3381
+ this.closeSidenav();
3382
+ this.alertService.showSuccess('@recordCreatedSuccessfully');
3383
+ },
3384
+ error: (err) => this.alertService.showError('@creationFailed', err),
3508
3385
  });
3509
- return passesAnyCondition;
3510
3386
  }
3511
- isFilterActive() {
3512
- return this.conditions.length > 0;
3387
+ /**
3388
+ * Update record
3389
+ */
3390
+ updateRecord() {
3391
+ const changes = this.initialItem.compare(this.currentItem());
3392
+ const updateData = this.createNewRecord();
3393
+ Object.assign(updateData, changes);
3394
+ updateData.setPK(this.currentItem().getPK());
3395
+ this.nettyAppsProxy.update(updateData).subscribe({
3396
+ next: (updatedRecord) => {
3397
+ this.initializeFormData(updatedRecord);
3398
+ this.commonService.notifyUpdate(this.recordType(), 'update', updatedRecord);
3399
+ this.closeSidenav();
3400
+ this.alertService.showSuccess('@recordUpdatedSuccessfully');
3401
+ },
3402
+ error: (err) => this.alertService.showError('@updateFailed', err),
3403
+ });
3513
3404
  }
3514
- getModel() {
3515
- if (this.isFilterActive()) {
3516
- return {
3517
- filterType: 'custom',
3518
- filterText: this.filterText,
3519
- conditions: this.conditions,
3520
- };
3405
+ /**
3406
+ * Create new record
3407
+ */
3408
+ async createNewData() {
3409
+ // If no GUID provided, initialize a new record
3410
+ let newRecord = this.createNewRecord();
3411
+ newRecord = await lastValueFrom(this.nettyAppsProxy.initRecord(newRecord))
3412
+ .catch((er) => {
3413
+ this.alertService.showError('@initRecordFailed:', er);
3414
+ return this.createNewRecord();
3415
+ });
3416
+ this.initializeFormData(newRecord);
3417
+ this.updateValid.set(true);
3418
+ }
3419
+ /**
3420
+ * Load data from API based on GUID
3421
+ * Handles both new record creation and existing record editing
3422
+ * guid - Unique identifier of the record
3423
+ */
3424
+ async loadDetailData() {
3425
+ const guid = this.getGuidFromParameters();
3426
+ if (!guid) {
3427
+ await this.createNewData();
3428
+ return;
3521
3429
  }
3522
- return null;
3430
+ // Fetch existing record from API
3431
+ this.nettyAppsProxy.selectGUID(guid).subscribe({
3432
+ next: (data) => {
3433
+ const record = this.createItemInstance(data);
3434
+ if (!record || !record.getPK()) {
3435
+ this.alertService.showError('@recordNotFound');
3436
+ const cleanPath = this.commonService.getCleanUrlPath();
3437
+ this.router.navigate([cleanPath]);
3438
+ return;
3439
+ }
3440
+ this.initializeFormData(record);
3441
+ this.alertService.showSuccess('@dataLoadSuccess');
3442
+ // Ensure sidenav is visible when in sidenav mode
3443
+ if (this.viewMode() === 'sidenav') {
3444
+ this.commonService.toggleRightSidenav(true);
3445
+ }
3446
+ },
3447
+ error: (err) => {
3448
+ this.alertService.showError('@dataLoadFailed');
3449
+ this.commonService.toggleRightSidenav(false);
3450
+ // Redirect to user list on error in fullscreen mode
3451
+ if (this.viewMode() === 'fullscreen') {
3452
+ const cleanPath = this.commonService.getCleanUrlPath();
3453
+ this.router.navigate([cleanPath]);
3454
+ }
3455
+ },
3456
+ });
3523
3457
  }
3524
- setModel(model) {
3525
- if (model && model.filterText) {
3526
- this.filterText = model.filterText;
3527
- this.conditions = model.conditions || [];
3458
+ // ***************************************************
3459
+ // *** gotoURL Methods ***
3460
+ // ***************************************************
3461
+ gotoURL(routePrefix, rightSidenav = [], parameters, type, dialogComponent = null, isNewTab = false, isPopup = this._isEmbedded()) {
3462
+ const baseHref = this.environment.getBaseHref().endsWith('/')
3463
+ ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
3464
+ : this.environment.getBaseHref();
3465
+ const navigationExtras = {
3466
+ queryParams: {
3467
+ parameters: JSON.stringify(parameters),
3468
+ ...(type && { type }),
3469
+ isNewTab: isNewTab || undefined,
3470
+ },
3471
+ queryParamsHandling: 'merge',
3472
+ };
3473
+ if (isNewTab) {
3474
+ const fullUrl = this.router
3475
+ .createUrlTree([baseHref, ...routePrefix, ...rightSidenav], navigationExtras)
3476
+ .toString();
3477
+ window.open(fullUrl, '_blank');
3478
+ return;
3528
3479
  }
3529
- else {
3530
- this.filterText = '';
3531
- this.conditions = [];
3480
+ if (isPopup && dialogComponent) {
3481
+ this.dialog
3482
+ .open(dialogComponent, {
3483
+ data: {
3484
+ parameters: parameters,
3485
+ mode: type || 'edit',
3486
+ embedded: true,
3487
+ },
3488
+ maxWidth: '100vw',
3489
+ disableClose: true,
3490
+ hasBackdrop: false,
3491
+ })
3492
+ .afterClosed();
3493
+ return;
3494
+ }
3495
+ // Log control
3496
+ if (rightSidenav.length == 0 || rightSidenav[0] === 'log') {
3497
+ this.router.navigate([baseHref, ...routePrefix, ...rightSidenav], navigationExtras);
3498
+ return;
3532
3499
  }
3500
+ // In all other cases, open the side menu
3501
+ this.router
3502
+ .navigate([
3503
+ {
3504
+ outlets: {
3505
+ primary: routePrefix,
3506
+ rightSidenav: [...routePrefix, ...rightSidenav],
3507
+ },
3508
+ },
3509
+ ], navigationExtras)
3510
+ .then(() => {
3511
+ // Ensure sidenav is opened after navigation
3512
+ this.commonService.toggleRightSidenav(true);
3513
+ });
3533
3514
  }
3534
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeNumberFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3535
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeNumberFilter, isStandalone: true, selector: "ntybase-range-number-filter", host: { attributes: { "ntybase-id": "RangeNumberFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3515
+ popupGotoURL(urlSegments) {
3516
+ const baseHref = this.environment.getBaseHref().endsWith('/')
3517
+ ? this.environment.getBaseHref().slice(0, -1) // Sondaki / işaretini kaldır
3518
+ : this.environment.getBaseHref();
3519
+ this.router.navigate([
3520
+ {
3521
+ outlets: {
3522
+ primary: [baseHref, ...urlSegments],
3523
+ rightSidenav: null,
3524
+ },
3525
+ },
3526
+ ]);
3527
+ }
3528
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridSaveBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
3529
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.2", type: NettyAgGridSaveBase, isStandalone: true, selector: "ntybase-ag-grid-save-base", inputs: { parameters: { classPropertyName: "parameters", publicName: "parameters", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "saveForm", first: true, predicate: ["saveForm"], descendants: true }], usesInheritance: true, ngImport: i0, template: ``, isInline: true });
3536
3530
  }
3537
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeNumberFilter, decorators: [{
3531
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NettyAgGridSaveBase, decorators: [{
3538
3532
  type: Component,
3539
- args: [{ selector: 'ntybase-range-number-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeNumberFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n" }]
3540
- }] });
3533
+ args: [{ selector: 'ntybase-ag-grid-save-base', imports: [], template: `` }]
3534
+ }], ctorParameters: () => [], propDecorators: { parameters: [{ type: i0.Input, args: [{ isSignal: true, alias: "parameters", required: false }] }], saveForm: [{
3535
+ type: ViewChild,
3536
+ args: ['saveForm']
3537
+ }] } });
3541
3538
 
3542
- class RangeStringFilter {
3539
+ class RangeDateTimeFilter {
3543
3540
  params;
3544
3541
  filterText = '';
3545
3542
  conditions = [];
3543
+ // Dil servisini inject edin
3544
+ i18nService = inject(I18nService);
3545
+ translateService = inject(TranslateService);
3546
+ // Türkçe ve İngilizce özel anahtar kelimeler
3547
+ specialKeywords = {
3548
+ today: 'today',
3549
+ bugün: 'today',
3550
+ yesterday: 'yesterday',
3551
+ dün: 'yesterday',
3552
+ thisweek: 'thisWeek',
3553
+ 'bu hafta': 'thisWeek',
3554
+ thismonth: 'thisMonth',
3555
+ 'bu ay': 'thisMonth',
3556
+ };
3546
3557
  agInit(params) {
3547
3558
  this.params = params;
3548
3559
  }
@@ -3556,210 +3567,242 @@ class RangeStringFilter {
3556
3567
  if (!this.filterText.trim()) {
3557
3568
  return;
3558
3569
  }
3570
+ // Virgülle ayrılmış parçaları al ve temizle
3559
3571
  const parts = this.filterText
3560
3572
  .split(',')
3561
3573
  .map((part) => part.trim())
3562
3574
  .filter((part) => part !== '');
3563
3575
  for (const part of parts) {
3564
- // "!" ile başlayan olumsuz koşul kontrolü
3565
- if (part.startsWith('!')) {
3566
- const positiveCondition = part.slice(1);
3567
- const positiveParsed = this.parseSingleCondition(positiveCondition);
3568
- if (positiveParsed) {
3576
+ // Aralık kontrolü (.. içeriyor mu) - ÖNCE aralık kontrolü yap
3577
+ if (part.includes('..')) {
3578
+ const rangeParts = part.split('..');
3579
+ if (rangeParts.length === 2) {
3580
+ const startStr = rangeParts[0].trim();
3581
+ const endStr = rangeParts[1].trim();
3582
+ const startDate = this.parseDateForRange(startStr, false);
3583
+ const endDate = this.parseDateForRange(endStr, true);
3584
+ if (startDate && endDate) {
3585
+ // Tarihleri doğru sırala (küçükten büyüğe)
3586
+ const sortedStart = startDate < endDate ? startDate : endDate;
3587
+ const sortedEnd = startDate < endDate ? endDate : startDate;
3588
+ this.conditions.push({
3589
+ type: 'range',
3590
+ start: sortedStart,
3591
+ end: sortedEnd,
3592
+ });
3593
+ }
3594
+ }
3595
+ }
3596
+ else {
3597
+ // Özel anahtar kelime kontrolü (Türkçe ve İngilizce)
3598
+ const normalizedPart = part.toLowerCase();
3599
+ if (this.specialKeywords[normalizedPart]) {
3569
3600
  this.conditions.push({
3570
- type: 'not',
3571
- condition: positiveParsed,
3601
+ type: 'special',
3602
+ special: this.specialKeywords[normalizedPart],
3572
3603
  });
3604
+ continue;
3573
3605
  }
3574
- continue;
3575
- }
3576
- const parsedCondition = this.parseSingleCondition(part);
3577
- if (parsedCondition) {
3578
- this.conditions.push(parsedCondition);
3579
- }
3580
- }
3581
- }
3582
- parseSingleCondition(condition) {
3583
- // Regex kontrolü ($$ ile başlıyorsa)
3584
- if (condition.startsWith('$$')) {
3585
- const regexPattern = condition.slice(2);
3586
- if (regexPattern) {
3587
- return {
3588
- type: 'regex',
3589
- pattern: regexPattern,
3590
- };
3591
- }
3592
- }
3593
- // Aralık kontrolü (.. içeriyor mu) - ama $$.. şeklinde değilse
3594
- if (condition.includes('..') && !condition.startsWith('$$')) {
3595
- const rangeParts = condition.split('..');
3596
- if (rangeParts.length === 2) {
3597
- const start = rangeParts[0].trim();
3598
- const end = rangeParts[1].trim();
3599
- if (start && end) {
3600
- return {
3601
- type: 'range',
3602
- start: start.toLowerCase(),
3603
- end: end.toLowerCase(),
3604
- };
3606
+ // Tek tarih kontrolü
3607
+ const date = this.parseDate(part);
3608
+ if (date) {
3609
+ this.conditions.push({
3610
+ type: 'date',
3611
+ date: date,
3612
+ });
3605
3613
  }
3606
3614
  }
3607
3615
  }
3608
- // Tek karakter kontrolü (? ile)
3609
- else if (condition.includes('?') && !condition.startsWith('$$')) {
3610
- // Eğer sadece normal karakterler varsa (özel karakter yoksa) exact match
3611
- const hasSpecialChars = condition.includes('*') ||
3612
- condition.includes('?') ||
3613
- condition.includes('..');
3614
- if (!hasSpecialChars) {
3615
- return {
3616
- type: 'exact',
3617
- value: condition.toLowerCase(),
3618
- };
3619
- }
3620
- // ? karakteri içeriyorsa singleChar kontrolü
3621
- const value = condition.toLowerCase();
3622
- if (value) {
3623
- return {
3624
- type: 'singleChar',
3625
- value: value,
3626
- };
3627
- }
3628
- }
3629
- // Başlangıç kontrolü (* sonunda)
3630
- else if (condition.endsWith('*') &&
3631
- !condition.startsWith('*') &&
3632
- !condition.startsWith('$$')) {
3633
- const value = condition.slice(0, -1).toLowerCase();
3634
- if (value) {
3635
- return {
3636
- type: 'startsWith',
3637
- value: value,
3638
- };
3639
- }
3640
- }
3641
- // Bitiş kontrolü (* başında)
3642
- else if (condition.startsWith('*') &&
3643
- !condition.endsWith('*') &&
3644
- !condition.startsWith('$$')) {
3645
- const value = condition.slice(1).toLowerCase();
3646
- if (value) {
3647
- return {
3648
- type: 'endsWith',
3649
- value: value,
3650
- };
3651
- }
3652
- }
3653
- // İçeren kontrolü (* ile başlayıp * ile bitiyorsa)
3654
- else if (condition.startsWith('*') &&
3655
- condition.endsWith('*') &&
3656
- !condition.startsWith('$$')) {
3657
- const value = condition.slice(1, -1).toLowerCase();
3658
- if (value) {
3659
- return {
3660
- type: 'contains',
3661
- value: value,
3662
- };
3663
- }
3664
- }
3665
- // Normal exact match (hiçbir özel karakter yoksa)
3666
- else if (!condition.startsWith('$$') &&
3667
- !condition.includes('*') &&
3668
- !condition.includes('?') &&
3669
- !condition.includes('..')) {
3670
- const value = condition.toLowerCase();
3671
- if (value) {
3672
- return {
3673
- type: 'exact',
3674
- value: value,
3675
- };
3676
- }
3616
+ }
3617
+ parseDateForRange(dateString, isEndDate) {
3618
+ if (!dateString)
3619
+ return null;
3620
+ // Özel anahtar kelimeler için tarih dönüşümü
3621
+ const normalizedString = dateString.toLowerCase();
3622
+ if (this.specialKeywords[normalizedString]) {
3623
+ const specialType = this.specialKeywords[normalizedString];
3624
+ const range = this.getSpecialDateRange(specialType);
3625
+ return isEndDate ? range.end : range.start;
3677
3626
  }
3678
- // Normal içeren kontrolü (varsayılan) - regex değilse
3679
- else if (!condition.startsWith('$$')) {
3680
- const value = condition.toLowerCase();
3681
- if (value) {
3682
- return {
3683
- type: 'contains',
3684
- value: value,
3685
- };
3627
+ return this.parseDate(dateString);
3628
+ }
3629
+ // Mevcut dili kontrol eden yardımcı metod
3630
+ isTurkish() {
3631
+ const currentLang = this.i18nService.language.toLowerCase();
3632
+ return (currentLang === 'tr' ||
3633
+ currentLang === 'türkçe' ||
3634
+ currentLang === 'tr-tr');
3635
+ }
3636
+ parseDate(dateString) {
3637
+ if (!dateString)
3638
+ return null;
3639
+ // Mevcut dile göre formatları belirle
3640
+ const isTurkish = this.isTurkish();
3641
+ // Tarih formatları - ÖNCE saat içeren formatlar
3642
+ const formats = [
3643
+ // ISO format: YYYY-AA-GG SS:DD (her dilde aynı)
3644
+ /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{2})$/,
3645
+ // Dile göre formatlar
3646
+ ...(isTurkish
3647
+ ? [
3648
+ // Türkçe format: GG.AA.YYYY SS:DD (., /, - ile)
3649
+ /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4}) (\d{1,2}):(\d{2})$/,
3650
+ // Türkçe format: GG.AA.YYYY (., /, - ile)
3651
+ /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4})$/,
3652
+ ]
3653
+ : [
3654
+ // İngilizce/USA format: AA/GG/YYYY SS:DD (/, ., - ile)
3655
+ /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4}) (\d{1,2}):(\d{2})$/,
3656
+ // İngilizce/USA format: AA/GG/YYYY (/, ., - ile)
3657
+ /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4})$/,
3658
+ ]),
3659
+ // Sadece tarih formatları (saat yok)
3660
+ /^(\d{4})-(\d{1,2})-(\d{1,2})$/, // YYYY-AA-GG (ISO)
3661
+ ];
3662
+ for (const format of formats) {
3663
+ const match = dateString.match(format);
3664
+ if (match) {
3665
+ let year, month, day, hours = 0, minutes = 0;
3666
+ if (format === formats[0]) {
3667
+ // ISO: YYYY-AA-GG SS:DD
3668
+ year = parseInt(match[1], 10);
3669
+ month = parseInt(match[2], 10) - 1;
3670
+ day = parseInt(match[3], 10);
3671
+ hours = parseInt(match[4], 10);
3672
+ minutes = parseInt(match[5], 10);
3673
+ }
3674
+ else if (isTurkish && format === formats[1]) {
3675
+ // Türkçe: GG.AA.YYYY SS:DD
3676
+ day = parseInt(match[1], 10);
3677
+ month = parseInt(match[2], 10) - 1;
3678
+ year = parseInt(match[3], 10);
3679
+ hours = parseInt(match[4], 10);
3680
+ minutes = parseInt(match[5], 10);
3681
+ }
3682
+ else if (!isTurkish && format === formats[1]) {
3683
+ // İngilizce: AA/GG/YYYY SS:DD
3684
+ month = parseInt(match[1], 10) - 1;
3685
+ day = parseInt(match[2], 10);
3686
+ year = parseInt(match[3], 10);
3687
+ hours = parseInt(match[4], 10);
3688
+ minutes = parseInt(match[5], 10);
3689
+ }
3690
+ else if (isTurkish && format === formats[2]) {
3691
+ // Türkçe: GG.AA.YYYY
3692
+ day = parseInt(match[1], 10);
3693
+ month = parseInt(match[2], 10) - 1;
3694
+ year = parseInt(match[3], 10);
3695
+ }
3696
+ else if (!isTurkish && format === formats[2]) {
3697
+ // İngilizce: AA/GG/YYYY
3698
+ month = parseInt(match[1], 10) - 1;
3699
+ day = parseInt(match[2], 10);
3700
+ year = parseInt(match[3], 10);
3701
+ }
3702
+ else if (format === formats[3]) {
3703
+ // ISO: YYYY-AA-GG
3704
+ year = parseInt(match[1], 10);
3705
+ month = parseInt(match[2], 10) - 1;
3706
+ day = parseInt(match[3], 10);
3707
+ }
3708
+ else {
3709
+ continue;
3710
+ }
3711
+ // Tarih geçerlilik kontrolü
3712
+ const date = new Date(year, month, day, hours, minutes);
3713
+ if (date.getFullYear() === year &&
3714
+ date.getMonth() === month &&
3715
+ date.getDate() === day &&
3716
+ date.getHours() === hours &&
3717
+ date.getMinutes() === minutes) {
3718
+ return date;
3719
+ }
3686
3720
  }
3687
3721
  }
3688
3722
  return null;
3689
3723
  }
3724
+ getSpecialDateRange(special) {
3725
+ const now = new Date();
3726
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
3727
+ switch (special) {
3728
+ case 'today':
3729
+ const tomorrow = new Date(today);
3730
+ tomorrow.setDate(tomorrow.getDate() + 1);
3731
+ return { start: today, end: tomorrow };
3732
+ case 'yesterday':
3733
+ const yesterday = new Date(today);
3734
+ yesterday.setDate(yesterday.getDate() - 1);
3735
+ const yesterdayEnd = new Date(yesterday);
3736
+ yesterdayEnd.setDate(yesterdayEnd.getDate() + 1);
3737
+ return { start: yesterday, end: yesterdayEnd };
3738
+ case 'thisWeek':
3739
+ const startOfWeek = new Date(today);
3740
+ startOfWeek.setDate(today.getDate() - today.getDay());
3741
+ const endOfWeek = new Date(startOfWeek);
3742
+ endOfWeek.setDate(startOfWeek.getDate() + 7);
3743
+ return { start: startOfWeek, end: endOfWeek };
3744
+ case 'thisMonth':
3745
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
3746
+ const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
3747
+ return { start: startOfMonth, end: endOfMonth };
3748
+ default:
3749
+ return { start: today, end: today };
3750
+ }
3751
+ }
3690
3752
  doesFilterPass(params) {
3691
3753
  const field = this.params.colDef.field;
3692
3754
  if (!field)
3693
3755
  return true;
3694
- const cellValue = params.data
3695
- ? String(params.data[field] || '').toLowerCase()
3696
- : '';
3756
+ const cellValue = params.data ? params.data[field] : null;
3697
3757
  // Eğer filtre yoksa tüm satırları göster
3698
3758
  if (this.conditions.length === 0) {
3699
3759
  return true;
3700
3760
  }
3701
- // Hücre değeri boşsa filtrele
3761
+ // Hücre değeri null/undefined ise filtrele
3702
3762
  if (!cellValue) {
3703
3763
  return false;
3704
3764
  }
3705
- // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
3765
+ // Hücre değerini Date'e dönüştür
3766
+ let cellDate;
3767
+ if (cellValue instanceof Date) {
3768
+ cellDate = cellValue;
3769
+ }
3770
+ else if (typeof cellValue === 'string') {
3771
+ // String ise Date'e parse et
3772
+ cellDate = new Date(cellValue);
3773
+ if (isNaN(cellDate.getTime())) {
3774
+ return false; // Geçersiz tarih
3775
+ }
3776
+ }
3777
+ else {
3778
+ return false; // Desteklenmeyen tip
3779
+ }
3780
+ const cellTime = cellDate.getTime();
3781
+ // Koşullardan herhangi birini sağlıyor mu kontrol et
3706
3782
  return this.conditions.some((condition) => {
3707
- const conditionResult = this.checkSingleCondition(cellValue, condition);
3708
- return condition.type === 'not' ? !conditionResult : conditionResult;
3709
- });
3710
- }
3711
- checkSingleCondition(cellValue, condition) {
3712
- switch (condition.type) {
3713
- case 'contains':
3714
- return condition.value ? cellValue.includes(condition.value) : false;
3715
- case 'startsWith':
3716
- return condition.value ? cellValue.startsWith(condition.value) : false;
3717
- case 'endsWith':
3718
- return condition.value ? cellValue.endsWith(condition.value) : false;
3719
- case 'exact':
3720
- return condition.value ? cellValue === condition.value : false;
3721
- case 'range':
3722
- if (condition.start && condition.end) {
3723
- return cellValue >= condition.start && cellValue <= condition.end;
3724
- }
3725
- return false;
3726
- case 'singleChar':
3727
- if (condition.value) {
3728
- // ? karakterini herhangi bir karakter olarak değerlendir
3729
- const pattern = condition.value;
3730
- if (cellValue.length !== pattern.length) {
3783
+ switch (condition.type) {
3784
+ case 'date':
3785
+ if (!condition.date)
3731
3786
  return false;
3732
- }
3733
- // Her karakteri tek tek kontrol et
3734
- for (let i = 0; i < pattern.length; i++) {
3735
- const patternChar = pattern[i];
3736
- const cellChar = cellValue[i];
3737
- // Eğer pattern'de ? değilse ve karakterler eşleşmiyorsa false
3738
- if (patternChar !== '?' && patternChar !== cellChar) {
3739
- return false;
3740
- }
3741
- }
3742
- return true;
3743
- }
3744
- return false;
3745
- case 'regex':
3746
- if (condition.pattern) {
3747
- try {
3748
- const regex = new RegExp(condition.pattern, 'i'); // case-insensitive
3749
- return regex.test(cellValue);
3750
- }
3751
- catch (e) {
3752
- // Geçersiz regex patterni durumunda false döndür
3753
- console.warn('Geçersiz regex patterni:', condition.pattern);
3787
+ const conditionTime = condition.date.getTime();
3788
+ const nextDay = new Date(condition.date);
3789
+ nextDay.setDate(nextDay.getDate() + 1);
3790
+ return cellTime >= conditionTime && cellTime < nextDay.getTime();
3791
+ case 'range':
3792
+ if (!condition.start || !condition.end)
3754
3793
  return false;
3755
- }
3756
- }
3757
- return false;
3758
- case 'not':
3759
- return this.checkSingleCondition(cellValue, condition.condition);
3760
- default:
3761
- return false;
3762
- }
3794
+ const startTime = condition.start.getTime();
3795
+ const endTime = condition.end.getTime();
3796
+ return cellTime >= startTime && cellTime < endTime;
3797
+ case 'special':
3798
+ if (!condition.special)
3799
+ return false;
3800
+ const range = this.getSpecialDateRange(condition.special);
3801
+ return (cellTime >= range.start.getTime() && cellTime < range.end.getTime());
3802
+ default:
3803
+ return false;
3804
+ }
3805
+ });
3763
3806
  }
3764
3807
  isFilterActive() {
3765
3808
  return this.conditions.length > 0;
@@ -3777,19 +3820,19 @@ class RangeStringFilter {
3777
3820
  setModel(model) {
3778
3821
  if (model && model.filterText) {
3779
3822
  this.filterText = model.filterText;
3780
- this.conditions = model.conditions || [];
3823
+ this.parseFilterText(); // Modelden set ederken koşulları tekrar parse et
3781
3824
  }
3782
3825
  else {
3783
3826
  this.filterText = '';
3784
3827
  this.conditions = [];
3785
3828
  }
3786
3829
  }
3787
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeStringFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3788
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeStringFilter, isStandalone: true, selector: "ntybase-range-string-filter", host: { attributes: { "ntybase-id": "RangeStringFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3830
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeDateTimeFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
3831
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: RangeDateTimeFilter, isStandalone: true, selector: "ntybase-range-date-time-filter", host: { attributes: { "ntybase-id": "RangeDateTimeFilter" } }, ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
3789
3832
  }
3790
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeStringFilter, decorators: [{
3833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: RangeDateTimeFilter, decorators: [{
3791
3834
  type: Component,
3792
- args: [{ selector: 'ntybase-range-string-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeStringFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n" }]
3835
+ args: [{ selector: 'ntybase-range-date-time-filter', imports: [TranslateModule], host: { 'ntybase-id': 'RangeDateTimeFilter' }, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n" }]
3793
3836
  }] });
3794
3837
 
3795
3838
  class AuthenticationGuard {
@@ -4300,7 +4343,7 @@ class Login extends AuthBase {
4300
4343
  });
4301
4344
  }
4302
4345
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Login, deps: null, target: i0.ɵɵFactoryTarget.Component });
4303
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: Login, isStandalone: true, selector: "ntybase-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4346
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: Login, isStandalone: true, selector: "ntybase-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n formControlName=\"username\"\n [placeholder]=\"'@username' | translate\"\n required\n />\n @if (loginForm.controls['username'].invalid &&\n loginForm.controls['username'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'username is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"password\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"password\"\n formControlName=\"password\"\n [placeholder]=\"'@password' | translate\"\n required\n />\n @if (loginForm.controls['password'].invalid &&\n loginForm.controls['password'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </div>\n }\n </div>\n\n <div class=\"form-group remember\">\n <input type=\"checkbox\" id=\"remember\" formControlName=\"remember\" />\n <label for=\"remember\">{{ '@rememberMe' | translate }}</label>\n <a class=\"forgot-password\" (click)=\"onForgotPassword()\"\n >{{ '@forgotPassword' | translate }}</a\n >\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading()\"\n >\n {{ '@login' | translate }}\n </button>\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n @if(version() && version() !== '?.?'){\n <div class=\"version\">{{ version() }}</div>\n }\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$5.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$5.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$5.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$5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$5.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4304
4347
  }
4305
4348
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: Login, decorators: [{
4306
4349
  type: Component,
@@ -4404,7 +4447,7 @@ class MfaLogin extends AuthBase {
4404
4447
  clearInterval(this.countdownInterval);
4405
4448
  }
4406
4449
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MfaLogin, deps: null, target: i0.ɵɵFactoryTarget.Component });
4407
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: MfaLogin, isStandalone: true, selector: "ntybase-mfa-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"mfaCode\">{{'mfaCode' | translate}}</label>\n <input\n type=\"text\"\n id=\"mfaCode\"\n formControlName=\"mfaCode\"\n [placeholder]=\"'mfaCode' | translate\"\n required\n />\n @if (loginForm.controls['mfaCode'].invalid &&\n loginForm.controls['mfaCode'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n }\n\n <!-- Time -->\n @if (!resendable()) {\n <div class=\"time-remaining\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading() || !resendable()\"\n >\n {{ '@login' | translate }}\n </button>\n\n @if (resendable()) {\n <div class=\"resend-container\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n }\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--mfa-login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}.invalid-input{border:1px solid #dc3545!important}.invalid-input:focus{box-shadow:0 0 0 .2rem #dc354540}.resend-container{margin-top:15px;text-align:center}.resend-container .resend-link{color:#007bff;cursor:pointer;text-decoration:underline;font-size:13px}.resend-container .resend-link:hover{color:#0056b3}.time-remaining{margin-top:16px;font-size:1rem;color:#f5f5f5}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4450
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: MfaLogin, isStandalone: true, selector: "ntybase-mfa-login", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form (ngSubmit)=\"login()\" [formGroup]=\"loginForm\" novalidate>\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"mfaCode\">{{'mfaCode' | translate}}</label>\n <input\n type=\"text\"\n id=\"mfaCode\"\n formControlName=\"mfaCode\"\n [placeholder]=\"'mfaCode' | translate\"\n required\n />\n @if (loginForm.controls['mfaCode'].invalid &&\n loginForm.controls['mfaCode'].touched) {\n <div class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'mfaCode is required' | translate }}\n </div>\n }\n\n <!-- Time -->\n @if (!resendable()) {\n <div class=\"time-remaining\">\n {{ '@tokenCount' | translate }}: {{ getFormattedTime() }}\n </div>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"loginForm.invalid || isLoading() || !resendable()\"\n >\n {{ '@login' | translate }}\n </button>\n\n @if (resendable()) {\n <div class=\"resend-container\">\n <span (click)=\"onResendMFACode()\" class=\"resend-link\">\n {{ 'resend MFACode' | translate }}\n </span>\n </div>\n }\n </form>\n } @else {\n <div class=\"loading-spinner\">\n <span>{{ '@loggingIn' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--mfa-login-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}.invalid-input{border:1px solid #dc3545!important}.invalid-input:focus{box-shadow:0 0 0 .2rem #dc354540}.resend-container{margin-top:15px;text-align:center}.resend-container .resend-link{color:#007bff;cursor:pointer;text-decoration:underline;font-size:13px}.resend-container .resend-link:hover{color:#0056b3}.time-remaining{margin-top:16px;font-size:1rem;color:#f5f5f5}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$5.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$5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$5.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$5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$5.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4408
4451
  }
4409
4452
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: MfaLogin, decorators: [{
4410
4453
  type: Component,
@@ -4578,7 +4621,7 @@ class ForgotPassword extends AuthBase {
4578
4621
  });
4579
4622
  }
4580
4623
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ForgotPassword, deps: [], target: i0.ɵɵFactoryTarget.Component });
4581
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: ForgotPassword, isStandalone: true, selector: "ntybase-forgot-password", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$4.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$4.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$4.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4624
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.2", type: ForgotPassword, isStandalone: true, selector: "ntybase-forgot-password", usesInheritance: true, ngImport: i0, template: "<div class=\"login-page-container\">\n <div class=\"login-image-container\"></div>\n\n <div class=\"login-container glass-effect\">\n <!-- Language Button -->\n <div class=\"language-toggle\">\n @if (icon()) {\n <button mat-icon-button [matMenuTriggerFor]=\"languageMenu\">\n <span class=\"{{ getCurrentLanguageIcon() }}\"></span>\n </button>\n } @else {\n <button\n mat-raised-button\n color=\"primary\"\n [matMenuTriggerFor]=\"languageMenu\"\n >\n {{ currentLanguage }}\n </button>\n }\n </div>\n\n <h2>{{'app_name' | translate }}</h2>\n\n <!-- Language Menu -->\n <mat-menu #languageMenu=\"matMenu\">\n @for (language of languages; track language) {\n <button mat-menu-item (click)=\"setLanguage(language)\">\n <span class=\"{{ getLanguageIcon(language) }}\"></span>\n {{ language }}\n </button>\n }\n </mat-menu>\n\n @if (!isLoading()) {\n <form\n (ngSubmit)=\"updatePassword()\"\n [formGroup]=\"updatePasswordForm\"\n novalidate\n >\n @if (error()) {\n <div class=\"error-message\">\n <span class=\"error-icon\">!</span>\n {{ error() }}\n </div>\n }\n\n <div class=\"form-group\">\n <label for=\"username\">{{'@username' | translate}}</label>\n <input\n type=\"text\"\n id=\"username\"\n [placeholder]=\"'@username' | translate\"\n formControlName=\"username\"\n required\n />\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPassword\">{{'@password' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPassword\"\n [placeholder]=\"'@password' | translate\"\n formControlName=\"newPassword\"\n required\n />\n @if (updatePasswordForm.controls['newPassword'].invalid &&\n updatePasswordForm.controls['newPassword'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <div class=\"form-group\">\n <label for=\"newPasswordCheck\">{{'@passwordCheck' | translate}}</label>\n <input\n type=\"password\"\n id=\"newPasswordCheck\"\n [placeholder]=\"'@passwordCheck' | translate\"\n formControlName=\"newPasswordCheck\"\n required\n />\n @if (updatePasswordForm.controls['newPasswordCheck'].invalid &&\n updatePasswordForm.controls['newPasswordCheck'].touched) {\n <mat-error class=\"validation-error\">\n <span class=\"error-icon\">!</span>\n {{ 'password is required' | translate }}\n </mat-error>\n }\n </div>\n\n <button\n type=\"submit\"\n class=\"login-button\"\n [disabled]=\"updatePasswordForm.invalid\"\n >\n {{ '@setPassword' | translate }}\n </button>\n </form>\n } @else {\n <!-- Burada eski #loading template'inin i\u00E7eri\u011Fi direkt olarak kullan\u0131l\u0131yor -->\n <div class=\"loading-spinner\">\n <span>{{ '@updatingPassword' | translate }}</span>\n </div>\n }\n\n <div class=\"footer\">\n <span class=\"version\">v{{version}}</span>\n </div>\n </div>\n</div>\n", styles: [".login-page-container{position:relative;display:flex;height:100vh;background-image:var(--forgot-password-bg-image, url(https://images.unsplash.com/photo-1519681393784-d120267933ba?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1124&q=100));background-position:center;background-repeat:no-repeat;background-size:cover;background-attachment:fixed;justify-content:flex-end;padding-right:5%}.login-image-container{display:none}.login-container{width:100%;max-width:400px;padding:2.5rem;display:flex;flex-direction:column;justify-content:center;background:#ffffff1a;border-radius:16px;box-shadow:0 8px 32px #0003;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,.2);margin:20px;height:fit-content;align-self:center}.login-container h2{color:#fff;text-align:center;margin-bottom:2rem;font-size:1.8rem;font-weight:600;text-shadow:0 2px 4px rgba(0,0,0,.3)}.form-group{margin-bottom:1.5rem}.form-group label{display:block;font-weight:500;color:#fff;font-size:.9rem;text-shadow:0 1px 2px rgba(0,0,0,.3)}.form-group input[type=text],.form-group input[type=password]{width:100%;padding:.85rem 1rem;margin-top:.5rem;border:1px solid rgba(255,255,255,.3);border-radius:8px;font-size:.95rem;background-color:#ffffff26;color:#fff}.form-group input::placeholder{color:#ffffffb3}.form-group input[type=text]:focus,.form-group input[type=password]:focus{outline:none;border-color:#ffffff80;background-color:#ffffff40;box-shadow:0 0 0 3px #ffffff1a}.remember{display:flex;align-items:center;margin-bottom:1.5rem}.remember input{width:18px;height:18px;margin-right:.75rem;cursor:pointer}.remember label{color:#fff;font-size:.9rem;cursor:pointer;-webkit-user-select:none;user-select:none;text-shadow:0 1px 2px rgba(0,0,0,.3)}.forgot-password{margin-left:auto;color:#ffffffe6;font-size:.85rem;text-decoration:none}.forgot-password:hover{text-decoration:underline}.login-button{width:100%;padding:1rem;background-color:#fff3;color:#fff;border:1px solid rgba(255,255,255,.4);border-radius:8px;font-size:1rem;font-weight:500;cursor:pointer;transition:all .2s}.login-button:hover{background-color:#ffffff4d}.loading-spinner{text-align:center;padding:2rem}.loading-spinner p{margin-top:1rem;color:#fff}.footer{margin-top:2rem;text-align:center}.version{color:#ffffffb3;font-size:.8rem;display:block;text-shadow:0 1px 2px rgba(0,0,0,.3)}@media(max-width:768px){.login-page-container{justify-content:center;padding-right:0;align-items:center}.login-container{max-width:90%;margin:20px auto}}.language-toggle{position:absolute;top:20px;right:20px;z-index:10}.language-toggle button{background:#fff3;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border:1px solid rgba(255,255,255,.3);cursor:pointer}.language-toggle button:hover{background:#ffffff4d}.language-toggle button mat-icon{color:#fff}.login-container h2{margin-top:.5rem}.flag-icon{width:24px;height:16px;margin-right:8px;border:1px solid #ddd}.error-message{background-color:#f8d7da;color:#721c24;padding:12px 15px;border-radius:4px;margin-bottom:20px;display:flex;align-items:center;border:1px solid #f5c6cb;font-size:14px;animation:fadeIn .3s ease-in-out}.error-message .error-icon{display:inline-block;width:20px;height:20px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:20px;margin-right:10px;font-weight:700;font-size:12px}.validation-error{color:#dc3545;font-size:12px;margin-top:5px;display:flex;align-items:center;animation:fadeIn .3s ease-in-out}.validation-error .error-icon{display:inline-block;width:16px;height:16px;background-color:#dc3545;color:#fff;border-radius:50%;text-align:center;line-height:16px;margin-right:6px;font-weight:700;font-size:10px}input.ng-invalid.ng-touched{border:1px solid #dc3545!important}@keyframes fadeIn{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$5.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$5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$5.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$5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$5.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i2$3.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i2$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i2$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4582
4625
  }
4583
4626
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ForgotPassword, decorators: [{
4584
4627
  type: Component,
@@ -4846,50 +4889,6 @@ const toEnum = (v, enumObj) => {
4846
4889
  return enumObj[key] ?? null;
4847
4890
  };
4848
4891
 
4849
- //-------------------------------
4850
- //| Generated by NettyWizard V2 |
4851
- //-------------------------------
4852
- class ExcelLogViewer extends NettyAgGridListBase {
4853
- /** Component Constructor */
4854
- constructor() {
4855
- super();
4856
- }
4857
- /** Get the rowId */
4858
- getRowId = (params) => params.data.rowIndex.toString();
4859
- /** Get the entity type for the component */
4860
- getEntityType = () => 'ParseLog';
4861
- pkFieldName() { return 'rowIndex'; }
4862
- loadData() { }
4863
- setParseData(data) {
4864
- data.forEach((item) => {
4865
- if (item.messageKey) {
4866
- item.message = this.translateService.instant(item.messageKey, item.messageParams);
4867
- }
4868
- });
4869
- super.setData(data);
4870
- }
4871
- /** Initialize Ag-Grid specific settings */
4872
- initAgGrid() {
4873
- this.excelStyles = this.nettyAgGridService.getExcelStyles();
4874
- this.columnDefs.set([
4875
- { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.row'), field: 'rowIndex', cellClass: 'numberType', filter: this.customFilters() ? RangeNumberFilter : 'agNumberColumnFilter', type: "numericColumn", cellStyle: { textAlign: 'right' } },
4876
- { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.message'), field: 'message', cellClass: 'text-format', filter: this.customFilters() ? RangeStringFilter : 'agSetColumnFilter', },
4877
- { headerName: this.translateService.instant('@EXCEL_PARSER_LOG.level'), field: 'level', cellClass: 'text-format', filter: this.customFilters() ? RangeStringFilter : 'agSetColumnFilter', },
4878
- ]);
4879
- this.initAgGrid_extension();
4880
- }
4881
- popupClose() {
4882
- super.popupClose();
4883
- }
4884
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelLogViewer, deps: [], target: i0.ɵɵFactoryTarget.Component });
4885
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.2", type: ExcelLogViewer, isStandalone: true, selector: "app-excel-log-viewer", usesInheritance: true, ngImport: i0, template: "<div class='list-container'>\n <div class='list-menu-button-bar'>\n <ntyui-button type='menu' icon='settings_ethernet' [disableOnClick]='false' (clicked)='expandCollapse()' />\n <ntyui-button type='menu' icon='regular_expression'\n [toolTip]=\"(customFilters() ? '@customFilterActive' : '@defaultFilterActive') | translate\"\n [disableOnClick]='true' [disableDuration]='0'\n [ngClass]=\"{'custom-filter-mode': !customFilters(),'default-filter-mode': customFilters()}\"\n (clicked)='toggleFilterMode()' />\n <ntyui-filter-button icon='filter_alt' (isSearchOpen)=\"onFilterTextBoxVisibilityChange($event)\"\n [searchValue]='searchValue()' (onSearch)='quickSearch($event)' />\n <ntyui-button type='close' class='list-close-button' [toolTip]=\"'@close'|translate\" (clicked)='popupClose()' />\n </div>\n <div class='list-grid'>\n <ag-grid-angular #agGrid class='ag-theme-balham grid-form-grid-full' [rowData]='recordList()'\n [columnDefs]='columnDefs()' [gridOptions]='gridOptions' [rowSelection]='gridOptions.rowSelection'\n [components]='frameworkComponents' [suppressAggFuncInHeader]='true' [enableCellTextSelection]='true'\n (firstDataRendered)='onFirstDataRendered($event)' (columnMoved)='saveGrid($event)'\n (columnVisible)='saveGrid($event)' (columnResized)='saveGrid($event)' (gridReady)='onGridReady($event)'\n [statusBar]='statusBar'></ag-grid-angular>\n </div>\n</div>", styles: [""], dependencies: [{ kind: "component", type: AgGridAngular, selector: "ag-grid-angular", inputs: ["gridOptions", "modules", "statusBar", "sideBar", "suppressContextMenu", "preventDefaultOnContextMenu", "allowContextMenuWithControlKey", "columnMenu", "suppressMenuHide", "enableBrowserTooltips", "tooltipTrigger", "tooltipShowDelay", "tooltipSwitchShowDelay", "tooltipHideDelay", "tooltipMouseTrack", "tooltipShowMode", "tooltipInteraction", "popupParent", "copyHeadersToClipboard", "copyGroupHeadersToClipboard", "clipboardDelimiter", "suppressCopyRowsToClipboard", "suppressCopySingleCellRanges", "suppressLastEmptyLineOnPaste", "suppressClipboardPaste", "suppressClipboardApi", "suppressCutToClipboard", "columnDefs", "defaultColDef", "defaultColGroupDef", "columnTypes", "dataTypeDefinitions", "maintainColumnOrder", "enableStrictPivotColumnOrder", "suppressFieldDotNotation", "headerHeight", "groupHeaderHeight", "floatingFiltersHeight", "pivotHeaderHeight", "pivotGroupHeaderHeight", "hidePaddedHeaderRows", "allowDragFromColumnsToolPanel", "suppressMovableColumns", "suppressColumnMoveAnimation", "suppressMoveWhenColumnDragging", "suppressDragLeaveHidesColumns", "suppressGroupChangesColumnVisibility", "suppressMakeColumnVisibleAfterUnGroup", "suppressRowGroupHidesColumns", "colResizeDefault", "suppressAutoSize", "autoSizePadding", "skipHeaderOnAutoSize", "autoSizeStrategy", "animateColumnResizing", "components", "editType", "suppressStartEditOnTab", "getFullRowEditValidationErrors", "invalidEditValueMode", "singleClickEdit", "suppressClickEdit", "readOnlyEdit", "stopEditingWhenCellsLoseFocus", "enterNavigatesVertically", "enterNavigatesVerticallyAfterEdit", "enableCellEditingOnBackspace", "undoRedoCellEditing", "undoRedoCellEditingLimit", "defaultCsvExportParams", "suppressCsvExport", "defaultExcelExportParams", "suppressExcelExport", "excelStyles", "findSearchValue", "findOptions", "quickFilterText", "cacheQuickFilter", "includeHiddenColumnsInQuickFilter", "quickFilterParser", "quickFilterMatcher", "applyQuickFilterBeforePivotOrAgg", "excludeChildrenWhenTreeDataFiltering", "enableAdvancedFilter", "alwaysPassFilter", "includeHiddenColumnsInAdvancedFilter", "advancedFilterParent", "advancedFilterBuilderParams", "advancedFilterParams", "suppressAdvancedFilterEval", "suppressSetFilterByDefault", "enableFilterHandlers", "filterHandlers", "enableCharts", "chartThemes", "customChartThemes", "chartThemeOverrides", "chartToolPanelsDef", "chartMenuItems", "loadingCellRenderer", "loadingCellRendererParams", "loadingCellRendererSelector", "localeText", "masterDetail", "keepDetailRows", "keepDetailRowsCount", "detailCellRenderer", "detailCellRendererParams", "detailRowHeight", "detailRowAutoHeight", "context", "alignedGrids", "tabIndex", "rowBuffer", "valueCache", "valueCacheNeverExpires", "enableCellExpressions", "suppressTouch", "suppressFocusAfterRefresh", "suppressBrowserResizeObserver", "suppressPropertyNamesCheck", "suppressChangeDetection", "debug", "loading", "overlayLoadingTemplate", "loadingOverlayComponent", "loadingOverlayComponentParams", "suppressLoadingOverlay", "overlayNoRowsTemplate", "noRowsOverlayComponent", "noRowsOverlayComponentParams", "suppressNoRowsOverlay", "suppressOverlays", "overlayComponent", "overlayComponentParams", "overlayComponentSelector", "activeOverlay", "activeOverlayParams", "pagination", "paginationPageSize", "paginationPageSizeSelector", "paginationAutoPageSize", "paginateChildRows", "suppressPaginationPanel", "pivotMode", "pivotPanelShow", "pivotMaxGeneratedColumns", "pivotDefaultExpanded", "pivotColumnGroupTotals", "pivotRowTotals", "pivotSuppressAutoColumn", "suppressExpandablePivotGroups", "functionsReadOnly", "aggFuncs", "formulaDataSource", "formulaFuncs", "suppressAggFuncInHeader", "alwaysAggregateAtRootLevel", "aggregateOnlyChangedColumns", "suppressAggFilteredOnly", "removePivotHeaderRowWhenSingleValueColumn", "animateRows", "cellFlashDuration", "cellFadeDuration", "allowShowChangeAfterFilter", "domLayout", "ensureDomOrder", "enableCellSpan", "enableRtl", "suppressColumnVirtualisation", "suppressMaxRenderedRowRestriction", "suppressRowVirtualisation", "rowDragManaged", "refreshAfterGroupEdit", "rowDragInsertDelay", "suppressRowDrag", "suppressMoveWhenRowDragging", "rowDragEntireRow", "rowDragMultiRow", "rowDragText", "dragAndDropImageComponent", "dragAndDropImageComponentParams", "fullWidthCellRenderer", "fullWidthCellRendererParams", "embedFullWidthRows", "groupDisplayType", "groupDefaultExpanded", "autoGroupColumnDef", "groupMaintainOrder", "groupSelectsChildren", "groupLockGroupColumns", "groupAggFiltering", "groupTotalRow", "grandTotalRow", "suppressStickyTotalRow", "groupSuppressBlankHeader", "groupSelectsFiltered", "showOpenedGroup", "groupHideParentOfSingleChild", "groupRemoveSingleChildren", "groupRemoveLowestSingleChildren", "groupHideOpenParents", "groupAllowUnbalanced", "rowGroupPanelShow", "groupRowRenderer", "groupRowRendererParams", "treeData", "treeDataChildrenField", "treeDataParentIdField", "rowGroupPanelSuppressSort", "suppressGroupRowsSticky", "groupHierarchyConfig", "pinnedTopRowData", "pinnedBottomRowData", "enableRowPinning", "isRowPinnable", "isRowPinned", "rowModelType", "rowData", "asyncTransactionWaitMillis", "suppressModelUpdateAfterUpdateTransaction", "datasource", "cacheOverflowSize", "infiniteInitialRowCount", "serverSideInitialRowCount", "suppressServerSideFullWidthLoadingRow", "cacheBlockSize", "maxBlocksInCache", "maxConcurrentDatasourceRequests", "blockLoadDebounceMillis", "purgeClosedRowNodes", "serverSideDatasource", "serverSideSortAllLevels", "serverSideEnableClientSideSort", "serverSideOnlyRefreshFilteredGroups", "serverSidePivotResultFieldSeparator", "viewportDatasource", "viewportRowModelPageSize", "viewportRowModelBufferSize", "alwaysShowHorizontalScroll", "alwaysShowVerticalScroll", "debounceVerticalScrollbar", "suppressHorizontalScroll", "suppressScrollOnNewData", "suppressScrollWhenPopupsAreOpen", "suppressAnimationFrame", "suppressMiddleClickScrolls", "suppressPreventDefaultOnMouseWheel", "scrollbarWidth", "rowSelection", "cellSelection", "rowMultiSelectWithClick", "suppressRowDeselection", "suppressRowClickSelection", "suppressCellFocus", "suppressHeaderFocus", "selectionColumnDef", "rowNumbers", "suppressMultiRangeSelection", "enableCellTextSelection", "enableRangeSelection", "enableRangeHandle", "enableFillHandle", "fillHandleDirection", "suppressClearOnFillReduction", "sortingOrder", "accentedSort", "unSortIcon", "suppressMultiSort", "alwaysMultiSort", "multiSortKey", "suppressMaintainUnsortedOrder", "icons", "rowHeight", "rowStyle", "rowClass", "rowClassRules", "suppressRowHoverHighlight", "suppressRowTransform", "columnHoverHighlight", "gridId", "deltaSort", "treeDataDisplayType", "enableGroupEdit", "initialState", "theme", "loadThemeGoogleFonts", "themeCssLayer", "styleNonce", "themeStyleContainer", "getContextMenuItems", "getMainMenuItems", "postProcessPopup", "processUnpinnedColumns", "processCellForClipboard", "processHeaderForClipboard", "processGroupHeaderForClipboard", "processCellFromClipboard", "sendToClipboard", "processDataFromClipboard", "isExternalFilterPresent", "doesExternalFilterPass", "getChartToolbarItems", "createChartContainer", "focusGridInnerElement", "navigateToNextHeader", "tabToNextHeader", "navigateToNextCell", "tabToNextCell", "getLocaleText", "getDocument", "paginationNumberFormatter", "getGroupRowAgg", "isGroupOpenByDefault", "ssrmExpandAllAffectsAllRows", "initialGroupOrderComparator", "processPivotResultColDef", "processPivotResultColGroupDef", "getDataPath", "getChildCount", "getServerSideGroupLevelParams", "isServerSideGroupOpenByDefault", "isApplyServerSideTransaction", "isServerSideGroup", "getServerSideGroupKey", "getBusinessKeyForNode", "getRowId", "resetRowDataOnUpdate", "processRowPostCreate", "isRowSelectable", "isRowMaster", "fillOperation", "postSortRows", "getRowStyle", "getRowClass", "getRowHeight", "isFullWidthRow", "isRowValidDropPosition"], outputs: ["toolPanelVisibleChanged", "toolPanelSizeChanged", "columnMenuVisibleChanged", "contextMenuVisibleChanged", "cutStart", "cutEnd", "pasteStart", "pasteEnd", "columnVisible", "columnPinned", "columnResized", "columnMoved", "columnValueChanged", "columnPivotModeChanged", "columnPivotChanged", "columnGroupOpened", "newColumnsLoaded", "gridColumnsChanged", "displayedColumnsChanged", "virtualColumnsChanged", "columnEverythingChanged", "columnsReset", "columnHeaderMouseOver", "columnHeaderMouseLeave", "columnHeaderClicked", "columnHeaderContextMenu", "componentStateChanged", "cellValueChanged", "cellEditRequest", "rowValueChanged", "cellEditingStarted", "cellEditingStopped", "rowEditingStarted", "rowEditingStopped", "bulkEditingStarted", "bulkEditingStopped", "batchEditingStarted", "batchEditingStopped", "undoStarted", "undoEnded", "redoStarted", "redoEnded", "cellSelectionDeleteStart", "cellSelectionDeleteEnd", "rangeDeleteStart", "rangeDeleteEnd", "fillStart", "fillEnd", "filterOpened", "filterChanged", "filterModified", "filterUiChanged", "floatingFilterUiChanged", "advancedFilterBuilderVisibleChanged", "findChanged", "chartCreated", "chartRangeSelectionChanged", "chartOptionsChanged", "chartDestroyed", "cellKeyDown", "gridReady", "firstDataRendered", "gridSizeChanged", "modelUpdated", "virtualRowRemoved", "viewportChanged", "bodyScroll", "bodyScrollEnd", "dragStarted", "dragStopped", "dragCancelled", "stateUpdated", "paginationChanged", "rowDragEnter", "rowDragMove", "rowDragLeave", "rowDragEnd", "rowDragCancel", "rowResizeStarted", "rowResizeEnded", "columnRowGroupChanged", "rowGroupOpened", "expandOrCollapseAll", "pivotMaxColumnsExceeded", "pinnedRowDataChanged", "pinnedRowsChanged", "rowDataUpdated", "asyncTransactionsFlushed", "storeRefreshed", "headerFocused", "cellClicked", "cellDoubleClicked", "cellFocused", "cellMouseOver", "cellMouseOut", "cellMouseDown", "rowClicked", "rowDoubleClicked", "rowSelected", "selectionChanged", "cellContextMenu", "rangeSelectionChanged", "cellSelectionChanged", "tooltipShow", "tooltipHide", "sortChanged"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: NettyUIButton, selector: "ntyui-button", inputs: ["icon", "isFilled", "menuReference", "disableOnClick", "disableDuration", "waitingText", "type", "toolTip"], outputs: ["clicked"] }, { kind: "component", type: NettyUIFilterButton, selector: "ntyui-filter-button", inputs: ["icon", "waitingText", "searchValue"], outputs: ["clicked", "onSearch", "isSearchOpen"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
4886
- }
4887
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: ExcelLogViewer, decorators: [{
4888
- type: Component,
4889
- args: [{ selector: 'app-excel-log-viewer', imports: [AgGridAngular, CommonModule, FormsModule, NettyUIButton, NettyUIFilterButton,
4890
- FormsModule, TranslateModule], template: "<div class='list-container'>\n <div class='list-menu-button-bar'>\n <ntyui-button type='menu' icon='settings_ethernet' [disableOnClick]='false' (clicked)='expandCollapse()' />\n <ntyui-button type='menu' icon='regular_expression'\n [toolTip]=\"(customFilters() ? '@customFilterActive' : '@defaultFilterActive') | translate\"\n [disableOnClick]='true' [disableDuration]='0'\n [ngClass]=\"{'custom-filter-mode': !customFilters(),'default-filter-mode': customFilters()}\"\n (clicked)='toggleFilterMode()' />\n <ntyui-filter-button icon='filter_alt' (isSearchOpen)=\"onFilterTextBoxVisibilityChange($event)\"\n [searchValue]='searchValue()' (onSearch)='quickSearch($event)' />\n <ntyui-button type='close' class='list-close-button' [toolTip]=\"'@close'|translate\" (clicked)='popupClose()' />\n </div>\n <div class='list-grid'>\n <ag-grid-angular #agGrid class='ag-theme-balham grid-form-grid-full' [rowData]='recordList()'\n [columnDefs]='columnDefs()' [gridOptions]='gridOptions' [rowSelection]='gridOptions.rowSelection'\n [components]='frameworkComponents' [suppressAggFuncInHeader]='true' [enableCellTextSelection]='true'\n (firstDataRendered)='onFirstDataRendered($event)' (columnMoved)='saveGrid($event)'\n (columnVisible)='saveGrid($event)' (columnResized)='saveGrid($event)' (gridReady)='onGridReady($event)'\n [statusBar]='statusBar'></ag-grid-angular>\n </div>\n</div>" }]
4891
- }], ctorParameters: () => [] });
4892
-
4893
4892
  /*
4894
4893
  * Public API Surface of ntybase
4895
4894
  */