@nettyapps/ntybase 0.1.22 → 0.1.24

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.
@@ -30,12 +30,12 @@ import { MatTooltipModule } from '@angular/material/tooltip';
30
30
  import * as i2$3 from '@angular/material/menu';
31
31
  import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu';
32
32
  import * as XLSX from 'xlsx';
33
+ import { I18nService } from '@nettyapps/ntyi18n';
33
34
  import * as i1$3 from '@angular/forms';
34
35
  import { FormBuilder, Validators, FormsModule, ReactiveFormsModule, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
35
36
  import * as i1$4 from '@angular/material/input';
36
37
  import { MatInputModule } from '@angular/material/input';
37
38
  import { MatFormFieldModule } from '@angular/material/form-field';
38
- import { I18nService } from '@nettyapps/ntyi18n';
39
39
  import * as i3$2 from '@angular/material/list';
40
40
  import { MatListModule } from '@angular/material/list';
41
41
  import { NettyUISearchInput, UiBase } from '@nettyapps/ntyui';
@@ -1189,6 +1189,7 @@ const myTheme = themeQuartz.withParams({
1189
1189
  backgroundColor: 'black',
1190
1190
  browserColorScheme: 'dark',
1191
1191
  }, 'dark');
1192
+ const FILTER_MODE_KEY = 'nettyapps_filter_mode';
1192
1193
  class NettyAgGridBase {
1193
1194
  // Input signals
1194
1195
  readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : []));
@@ -1200,6 +1201,8 @@ class NettyAgGridBase {
1200
1201
  // Parameters pass when the component is embeded into an other
1201
1202
  componantParameterGUID = input('', ...(ngDevMode ? [{ debugName: "componantParameterGUID" }] : []));
1202
1203
  componantParameterType = input('', ...(ngDevMode ? [{ debugName: "componantParameterType" }] : []));
1204
+ // AG Grid Filter
1205
+ customFilters = signal(this.getStoredFilterMode(), ...(ngDevMode ? [{ debugName: "customFilters" }] : []));
1203
1206
  // Authentication
1204
1207
  authenticationList = [];
1205
1208
  // User access writes
@@ -1398,6 +1401,32 @@ class NettyAgGridBase {
1398
1401
  { statusPanel: 'agAggregationComponent' },
1399
1402
  ],
1400
1403
  };
1404
+ /**
1405
+ * Filter mode change
1406
+ */
1407
+ toggleFilterMode() {
1408
+ const newMode = !this.customFilters();
1409
+ this.customFilters.set(newMode);
1410
+ localStorage.setItem(FILTER_MODE_KEY, JSON.stringify(newMode));
1411
+ this.initAgGrid();
1412
+ if (this.gridApi) {
1413
+ this.gridApi.refreshHeader();
1414
+ this.gridApi.setFilterModel(null);
1415
+ const message = this.customFilters()
1416
+ ? '@customFilterModeEnabled'
1417
+ : '@defaultFilterModeEnabled';
1418
+ this.alertService.showAlert(this.translateService.instant(message));
1419
+ }
1420
+ }
1421
+ getStoredFilterMode() {
1422
+ try {
1423
+ const stored = localStorage.getItem(FILTER_MODE_KEY);
1424
+ return stored !== null ? JSON.parse(stored) : true;
1425
+ }
1426
+ catch {
1427
+ return true;
1428
+ }
1429
+ }
1401
1430
  /**
1402
1431
  * Component initialization lifecycle hook
1403
1432
  */
@@ -1798,7 +1827,9 @@ class NettyAgGridBase {
1798
1827
  this.menuValid.set(!isOpen);
1799
1828
  }
1800
1829
  setFilter() { } //override this to set a filter
1801
- popupClose() { this.selectedElement.emit(null); }
1830
+ popupClose() {
1831
+ this.selectedElement.emit(null);
1832
+ }
1802
1833
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: NettyAgGridBase, deps: [], target: i0.ɵɵFactoryTarget.Component });
1803
1834
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.11", type: NettyAgGridBase, isStandalone: true, selector: "ntybase-ag-grid-base", inputs: { readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, popupFilterValid: { classPropertyName: "popupFilterValid", publicName: "popupFilterValid", isSignal: true, isRequired: false, transformFunction: null }, popupValid: { classPropertyName: "popupValid", publicName: "popupValid", isSignal: true, isRequired: false, transformFunction: null }, isEmbedded: { classPropertyName: "isEmbedded", publicName: "isEmbedded", isSignal: true, isRequired: false, transformFunction: null }, componantParameterGUID: { classPropertyName: "componantParameterGUID", publicName: "componantParameterGUID", isSignal: true, isRequired: false, transformFunction: null }, componantParameterType: { classPropertyName: "componantParameterType", publicName: "componantParameterType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedElement: "selectedElement" }, ngImport: i0, template: "<p>ag-grid-base works!</p>\n", styles: [""] });
1804
1835
  }
@@ -1887,7 +1918,11 @@ class NettyAgGridSaveBase {
1887
1918
  */
1888
1919
  async canDeactivate() {
1889
1920
  if (this.formChanged) {
1890
- return await this.alertService.showConfirm('@unsavedChangesConfirm');
1921
+ const confirmed = await this.alertService.showConfirm('@unsavedChangesConfirm');
1922
+ if (!confirmed) {
1923
+ return false;
1924
+ }
1925
+ return true;
1891
1926
  }
1892
1927
  return true;
1893
1928
  }
@@ -1913,24 +1948,34 @@ class NettyAgGridSaveBase {
1913
1948
  /**
1914
1949
  * Close sidenav or navigate back
1915
1950
  */
1916
- closeSidenav() {
1917
- if (this.viewMode() === 'dialog' && this.dialogRef) {
1918
- this.dialogRef.close('saved');
1919
- }
1920
- else if (this.viewMode() === 'sidenav') {
1921
- this.commonService.clearOutlet();
1922
- }
1923
- else {
1924
- const cleanPath = this.commonService.getCleanUrlPath();
1925
- this.router.navigate([cleanPath]);
1951
+ async closeSidenav() {
1952
+ const canDeactivate = await this.canDeactivate();
1953
+ if (canDeactivate) {
1954
+ if (this.viewMode() === 'dialog' && this.dialogRef) {
1955
+ this.dialogRef.close('saved');
1956
+ }
1957
+ else if (this.viewMode() === 'sidenav') {
1958
+ this.formChanged = false;
1959
+ this.commonService.clearOutlet();
1960
+ }
1961
+ else {
1962
+ const cleanPath = this.commonService.getCleanUrlPath();
1963
+ this.router.navigate([cleanPath]);
1964
+ }
1926
1965
  }
1927
1966
  }
1928
- backClicked() {
1929
- if (this.viewMode() === 'dialog' && this.dialogRef) {
1930
- this.dialogRef.close('back');
1931
- }
1932
- else {
1933
- this.commonService.goBack();
1967
+ /**
1968
+ * Back button clicked
1969
+ */
1970
+ async backClicked() {
1971
+ const canDeactivate = await this.canDeactivate();
1972
+ if (canDeactivate) {
1973
+ if (this.viewMode() === 'dialog' && this.dialogRef) {
1974
+ this.dialogRef.close('back');
1975
+ }
1976
+ else {
1977
+ this.commonService.goBack();
1978
+ }
1934
1979
  }
1935
1980
  }
1936
1981
  validateSaveRecord(recordGUID) {
@@ -2000,6 +2045,757 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImpo
2000
2045
  args: [{ selector: 'ntybase-excel-import-base', imports: [], template: "<p>excel-import-base works!</p>\n" }]
2001
2046
  }] });
2002
2047
 
2048
+ class RangeDateTimeFilter {
2049
+ params;
2050
+ filterText = '';
2051
+ conditions = [];
2052
+ // Dil servisini inject edin
2053
+ i18nService = inject(I18nService);
2054
+ translateService = inject(TranslateService);
2055
+ // Türkçe ve İngilizce özel anahtar kelimeler
2056
+ specialKeywords = {
2057
+ today: 'today',
2058
+ bugün: 'today',
2059
+ yesterday: 'yesterday',
2060
+ dün: 'yesterday',
2061
+ thisweek: 'thisWeek',
2062
+ 'bu hafta': 'thisWeek',
2063
+ thismonth: 'thisMonth',
2064
+ 'bu ay': 'thisMonth',
2065
+ };
2066
+ agInit(params) {
2067
+ this.params = params;
2068
+ }
2069
+ onFilterTextChanged(event) {
2070
+ this.filterText = event.target.value;
2071
+ this.parseFilterText();
2072
+ this.params.filterChangedCallback();
2073
+ }
2074
+ parseFilterText() {
2075
+ this.conditions = [];
2076
+ if (!this.filterText.trim()) {
2077
+ return;
2078
+ }
2079
+ // Virgülle ayrılmış parçaları al ve temizle
2080
+ const parts = this.filterText
2081
+ .split(',')
2082
+ .map((part) => part.trim())
2083
+ .filter((part) => part !== '');
2084
+ for (const part of parts) {
2085
+ // Aralık kontrolü (.. içeriyor mu) - ÖNCE aralık kontrolü yap
2086
+ if (part.includes('..')) {
2087
+ const rangeParts = part.split('..');
2088
+ if (rangeParts.length === 2) {
2089
+ const startStr = rangeParts[0].trim();
2090
+ const endStr = rangeParts[1].trim();
2091
+ const startDate = this.parseDateForRange(startStr, false);
2092
+ const endDate = this.parseDateForRange(endStr, true);
2093
+ if (startDate && endDate) {
2094
+ // Tarihleri doğru sırala (küçükten büyüğe)
2095
+ const sortedStart = startDate < endDate ? startDate : endDate;
2096
+ const sortedEnd = startDate < endDate ? endDate : startDate;
2097
+ this.conditions.push({
2098
+ type: 'range',
2099
+ start: sortedStart,
2100
+ end: sortedEnd,
2101
+ });
2102
+ }
2103
+ }
2104
+ }
2105
+ else {
2106
+ // Özel anahtar kelime kontrolü (Türkçe ve İngilizce)
2107
+ const normalizedPart = part.toLowerCase();
2108
+ if (this.specialKeywords[normalizedPart]) {
2109
+ this.conditions.push({
2110
+ type: 'special',
2111
+ special: this.specialKeywords[normalizedPart],
2112
+ });
2113
+ continue;
2114
+ }
2115
+ // Tek tarih kontrolü
2116
+ const date = this.parseDate(part);
2117
+ if (date) {
2118
+ this.conditions.push({
2119
+ type: 'date',
2120
+ date: date,
2121
+ });
2122
+ }
2123
+ }
2124
+ }
2125
+ }
2126
+ parseDateForRange(dateString, isEndDate) {
2127
+ if (!dateString)
2128
+ return null;
2129
+ // Özel anahtar kelimeler için tarih dönüşümü
2130
+ const normalizedString = dateString.toLowerCase();
2131
+ if (this.specialKeywords[normalizedString]) {
2132
+ const specialType = this.specialKeywords[normalizedString];
2133
+ const range = this.getSpecialDateRange(specialType);
2134
+ return isEndDate ? range.end : range.start;
2135
+ }
2136
+ return this.parseDate(dateString);
2137
+ }
2138
+ // Mevcut dili kontrol eden yardımcı metod
2139
+ isTurkish() {
2140
+ const currentLang = this.i18nService.language.toLowerCase();
2141
+ return (currentLang === 'tr' ||
2142
+ currentLang === 'türkçe' ||
2143
+ currentLang === 'tr-tr');
2144
+ }
2145
+ parseDate(dateString) {
2146
+ if (!dateString)
2147
+ return null;
2148
+ // Mevcut dile göre formatları belirle
2149
+ const isTurkish = this.isTurkish();
2150
+ // Tarih formatları - ÖNCE saat içeren formatlar
2151
+ const formats = [
2152
+ // ISO format: YYYY-AA-GG SS:DD (her dilde aynı)
2153
+ /^(\d{4})-(\d{1,2})-(\d{1,2}) (\d{1,2}):(\d{2})$/,
2154
+ // Dile göre formatlar
2155
+ ...(isTurkish
2156
+ ? [
2157
+ // Türkçe format: GG.AA.YYYY SS:DD (., /, - ile)
2158
+ /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4}) (\d{1,2}):(\d{2})$/,
2159
+ // Türkçe format: GG.AA.YYYY (., /, - ile)
2160
+ /^(\d{1,2})[\.\/-](\d{1,2})[\.\/-](\d{4})$/,
2161
+ ]
2162
+ : [
2163
+ // İngilizce/USA format: AA/GG/YYYY SS:DD (/, ., - ile)
2164
+ /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4}) (\d{1,2}):(\d{2})$/,
2165
+ // İngilizce/USA format: AA/GG/YYYY (/, ., - ile)
2166
+ /^(\d{1,2})[\/\.-](\d{1,2})[\/\.-](\d{4})$/,
2167
+ ]),
2168
+ // Sadece tarih formatları (saat yok)
2169
+ /^(\d{4})-(\d{1,2})-(\d{1,2})$/, // YYYY-AA-GG (ISO)
2170
+ ];
2171
+ for (const format of formats) {
2172
+ const match = dateString.match(format);
2173
+ if (match) {
2174
+ let year, month, day, hours = 0, minutes = 0;
2175
+ if (format === formats[0]) {
2176
+ // ISO: YYYY-AA-GG SS:DD
2177
+ year = parseInt(match[1], 10);
2178
+ month = parseInt(match[2], 10) - 1;
2179
+ day = parseInt(match[3], 10);
2180
+ hours = parseInt(match[4], 10);
2181
+ minutes = parseInt(match[5], 10);
2182
+ }
2183
+ else if (isTurkish && format === formats[1]) {
2184
+ // Türkçe: GG.AA.YYYY SS:DD
2185
+ day = parseInt(match[1], 10);
2186
+ month = parseInt(match[2], 10) - 1;
2187
+ year = parseInt(match[3], 10);
2188
+ hours = parseInt(match[4], 10);
2189
+ minutes = parseInt(match[5], 10);
2190
+ }
2191
+ else if (!isTurkish && format === formats[1]) {
2192
+ // İngilizce: AA/GG/YYYY SS:DD
2193
+ month = parseInt(match[1], 10) - 1;
2194
+ day = parseInt(match[2], 10);
2195
+ year = parseInt(match[3], 10);
2196
+ hours = parseInt(match[4], 10);
2197
+ minutes = parseInt(match[5], 10);
2198
+ }
2199
+ else if (isTurkish && format === formats[2]) {
2200
+ // Türkçe: GG.AA.YYYY
2201
+ day = parseInt(match[1], 10);
2202
+ month = parseInt(match[2], 10) - 1;
2203
+ year = parseInt(match[3], 10);
2204
+ }
2205
+ else if (!isTurkish && format === formats[2]) {
2206
+ // İngilizce: AA/GG/YYYY
2207
+ month = parseInt(match[1], 10) - 1;
2208
+ day = parseInt(match[2], 10);
2209
+ year = parseInt(match[3], 10);
2210
+ }
2211
+ else if (format === formats[3]) {
2212
+ // ISO: YYYY-AA-GG
2213
+ year = parseInt(match[1], 10);
2214
+ month = parseInt(match[2], 10) - 1;
2215
+ day = parseInt(match[3], 10);
2216
+ }
2217
+ else {
2218
+ continue;
2219
+ }
2220
+ // Tarih geçerlilik kontrolü
2221
+ const date = new Date(year, month, day, hours, minutes);
2222
+ if (date.getFullYear() === year &&
2223
+ date.getMonth() === month &&
2224
+ date.getDate() === day &&
2225
+ date.getHours() === hours &&
2226
+ date.getMinutes() === minutes) {
2227
+ return date;
2228
+ }
2229
+ }
2230
+ }
2231
+ return null;
2232
+ }
2233
+ getSpecialDateRange(special) {
2234
+ const now = new Date();
2235
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
2236
+ switch (special) {
2237
+ case 'today':
2238
+ const tomorrow = new Date(today);
2239
+ tomorrow.setDate(tomorrow.getDate() + 1);
2240
+ return { start: today, end: tomorrow };
2241
+ case 'yesterday':
2242
+ const yesterday = new Date(today);
2243
+ yesterday.setDate(yesterday.getDate() - 1);
2244
+ const yesterdayEnd = new Date(yesterday);
2245
+ yesterdayEnd.setDate(yesterdayEnd.getDate() + 1);
2246
+ return { start: yesterday, end: yesterdayEnd };
2247
+ case 'thisWeek':
2248
+ const startOfWeek = new Date(today);
2249
+ startOfWeek.setDate(today.getDate() - today.getDay());
2250
+ const endOfWeek = new Date(startOfWeek);
2251
+ endOfWeek.setDate(startOfWeek.getDate() + 7);
2252
+ return { start: startOfWeek, end: endOfWeek };
2253
+ case 'thisMonth':
2254
+ const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
2255
+ const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1);
2256
+ return { start: startOfMonth, end: endOfMonth };
2257
+ default:
2258
+ return { start: today, end: today };
2259
+ }
2260
+ }
2261
+ doesFilterPass(params) {
2262
+ const field = this.params.colDef.field;
2263
+ if (!field)
2264
+ return true;
2265
+ const cellValue = params.data ? params.data[field] : null;
2266
+ // Eğer filtre yoksa tüm satırları göster
2267
+ if (this.conditions.length === 0) {
2268
+ return true;
2269
+ }
2270
+ // Hücre değeri null/undefined ise filtrele
2271
+ if (!cellValue) {
2272
+ return false;
2273
+ }
2274
+ // Hücre değerini Date'e dönüştür
2275
+ let cellDate;
2276
+ if (cellValue instanceof Date) {
2277
+ cellDate = cellValue;
2278
+ }
2279
+ else if (typeof cellValue === 'string') {
2280
+ // String ise Date'e parse et
2281
+ cellDate = new Date(cellValue);
2282
+ if (isNaN(cellDate.getTime())) {
2283
+ return false; // Geçersiz tarih
2284
+ }
2285
+ }
2286
+ else {
2287
+ return false; // Desteklenmeyen tip
2288
+ }
2289
+ const cellTime = cellDate.getTime();
2290
+ // Koşullardan herhangi birini sağlıyor mu kontrol et
2291
+ return this.conditions.some((condition) => {
2292
+ switch (condition.type) {
2293
+ case 'date':
2294
+ if (!condition.date)
2295
+ return false;
2296
+ const conditionTime = condition.date.getTime();
2297
+ const nextDay = new Date(condition.date);
2298
+ nextDay.setDate(nextDay.getDate() + 1);
2299
+ return cellTime >= conditionTime && cellTime < nextDay.getTime();
2300
+ case 'range':
2301
+ if (!condition.start || !condition.end)
2302
+ return false;
2303
+ const startTime = condition.start.getTime();
2304
+ const endTime = condition.end.getTime();
2305
+ return cellTime >= startTime && cellTime < endTime;
2306
+ case 'special':
2307
+ if (!condition.special)
2308
+ return false;
2309
+ const range = this.getSpecialDateRange(condition.special);
2310
+ return (cellTime >= range.start.getTime() && cellTime < range.end.getTime());
2311
+ default:
2312
+ return false;
2313
+ }
2314
+ });
2315
+ }
2316
+ isFilterActive() {
2317
+ return this.conditions.length > 0;
2318
+ }
2319
+ getModel() {
2320
+ if (this.isFilterActive()) {
2321
+ return {
2322
+ filterType: 'custom',
2323
+ filterText: this.filterText,
2324
+ conditions: this.conditions,
2325
+ };
2326
+ }
2327
+ return null;
2328
+ }
2329
+ setModel(model) {
2330
+ if (model && model.filterText) {
2331
+ this.filterText = model.filterText;
2332
+ this.parseFilterText(); // Modelden set ederken koşulları tekrar parse et
2333
+ }
2334
+ else {
2335
+ this.filterText = '';
2336
+ this.conditions = [];
2337
+ }
2338
+ }
2339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeDateTimeFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: RangeDateTimeFilter, isStandalone: true, selector: "ntybase-range-date-time-filter", ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@dateTimeFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@dateTimeFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(today..yesterday)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleDate' | translate }}:\n <code>YYYY-MM-DD</code>\n <span class=\"custom-filter__example\">(2024-05-15)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@dateTime' | translate }}:\n <code>YYYY-MM-DD HH:MM</code>\n <span class=\"custom-filter__example\">(2024-05-15 14:30)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>date1,date2,start..end</code>\n </div>\n\n <strong class=\"custom-filter__subtitle\">\n {{ '@specialKeywords' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@turkish' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">bug\u00FCn</code>\n <code class=\"custom-filter__keyword\">d\u00FCn</code>\n <code class=\"custom-filter__keyword\">bu hafta</code>\n <code class=\"custom-filter__keyword\">bu ay</code>\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@english' | translate }}:\n <span class=\"custom-filter__keywords\">\n <code class=\"custom-filter__keyword\">today</code>\n <code class=\"custom-filter__keyword\">yesterday</code>\n <code class=\"custom-filter__keyword\">thisWeek</code>\n <code class=\"custom-filter__keyword\">thisMonth</code>\n </span>\n </div>\n\n <div class=\"custom-filter__note\">{{ '@filterExample' | translate }}</div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
2341
+ }
2342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeDateTimeFilter, decorators: [{
2343
+ type: Component,
2344
+ args: [{ selector: 'ntybase-range-date-time-filter', imports: [TranslateModule], 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" }]
2345
+ }] });
2346
+
2347
+ class RangeNumberFilter {
2348
+ params;
2349
+ filterText = '';
2350
+ conditions = [];
2351
+ agInit(params) {
2352
+ this.params = params;
2353
+ }
2354
+ onFilterTextChanged(event) {
2355
+ this.filterText = event.target.value;
2356
+ this.parseFilterText();
2357
+ this.params.filterChangedCallback();
2358
+ }
2359
+ parseFilterText() {
2360
+ this.conditions = [];
2361
+ if (!this.filterText.trim()) {
2362
+ return;
2363
+ }
2364
+ const parts = this.filterText
2365
+ .split(',')
2366
+ .map((part) => part.trim())
2367
+ .filter((part) => part !== '');
2368
+ for (const part of parts) {
2369
+ // Hariç tutma kontrolü (! ile başlıyor mu)
2370
+ if (part.startsWith('!')) {
2371
+ const excludePart = part.substring(1).trim();
2372
+ // Hariç tutma için aralık kontrolü
2373
+ if (excludePart.includes('..')) {
2374
+ const rangeParts = excludePart.split('..');
2375
+ if (rangeParts.length === 2) {
2376
+ const minStr = rangeParts[0].trim();
2377
+ const maxStr = rangeParts[1].trim();
2378
+ // !..10 formatı (max hariç)
2379
+ if (minStr === '' && maxStr !== '') {
2380
+ const max = Number(maxStr);
2381
+ if (!isNaN(max)) {
2382
+ this.conditions.push({
2383
+ type: 'exclude',
2384
+ min: -Infinity,
2385
+ max: max,
2386
+ });
2387
+ }
2388
+ }
2389
+ // !10.. formatı (min hariç)
2390
+ else if (minStr !== '' && maxStr === '') {
2391
+ const min = Number(minStr);
2392
+ if (!isNaN(min)) {
2393
+ this.conditions.push({
2394
+ type: 'exclude',
2395
+ min: min,
2396
+ max: Infinity,
2397
+ });
2398
+ }
2399
+ }
2400
+ // !min..max formatı (aralık hariç)
2401
+ else if (minStr !== '' && maxStr !== '') {
2402
+ const min = Number(minStr);
2403
+ const max = Number(maxStr);
2404
+ if (!isNaN(min) && !isNaN(max)) {
2405
+ this.conditions.push({
2406
+ type: 'exclude',
2407
+ min: Math.min(min, max),
2408
+ max: Math.max(min, max),
2409
+ });
2410
+ }
2411
+ }
2412
+ }
2413
+ }
2414
+ else {
2415
+ // Tek değer hariç tutma
2416
+ const value = Number(excludePart);
2417
+ if (!isNaN(value)) {
2418
+ this.conditions.push({
2419
+ type: 'exclude',
2420
+ value: value,
2421
+ });
2422
+ }
2423
+ }
2424
+ }
2425
+ // Aralık kontrolü (.. içeriyor mu)
2426
+ else if (part.includes('..')) {
2427
+ const rangeParts = part.split('..');
2428
+ if (rangeParts.length === 2) {
2429
+ const minStr = rangeParts[0].trim();
2430
+ const maxStr = rangeParts[1].trim();
2431
+ // ..10 formatı (max belirtilmiş)
2432
+ if (minStr === '' && maxStr !== '') {
2433
+ const max = Number(maxStr);
2434
+ if (!isNaN(max)) {
2435
+ this.conditions.push({
2436
+ type: 'range',
2437
+ min: -Infinity,
2438
+ max: max,
2439
+ });
2440
+ }
2441
+ }
2442
+ // 10.. formatı (min belirtilmiş)
2443
+ else if (minStr !== '' && maxStr === '') {
2444
+ const min = Number(minStr);
2445
+ if (!isNaN(min)) {
2446
+ this.conditions.push({
2447
+ type: 'range',
2448
+ min: min,
2449
+ max: Infinity,
2450
+ });
2451
+ }
2452
+ }
2453
+ // min..max formatı
2454
+ else if (minStr !== '' && maxStr !== '') {
2455
+ const min = Number(minStr);
2456
+ const max = Number(maxStr);
2457
+ if (!isNaN(min) && !isNaN(max)) {
2458
+ this.conditions.push({
2459
+ type: 'range',
2460
+ min: Math.min(min, max),
2461
+ max: Math.max(min, max),
2462
+ });
2463
+ }
2464
+ }
2465
+ }
2466
+ }
2467
+ else {
2468
+ // Tek değer kontrolü
2469
+ const value = Number(part);
2470
+ if (!isNaN(value)) {
2471
+ this.conditions.push({
2472
+ type: 'value',
2473
+ value: value,
2474
+ });
2475
+ }
2476
+ }
2477
+ }
2478
+ }
2479
+ doesFilterPass(params) {
2480
+ const cellValue = this.params.getValue(params.node);
2481
+ // Eğer filtre yoksa tüm satırları göster
2482
+ if (this.conditions.length === 0) {
2483
+ return true;
2484
+ }
2485
+ // Hücre değeri null/undefined ise veya sayı değilse filtrele
2486
+ if (cellValue == null || typeof cellValue !== 'number') {
2487
+ return false;
2488
+ }
2489
+ // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
2490
+ const passesAnyCondition = this.conditions.some((condition) => {
2491
+ if (condition.type === 'range' &&
2492
+ condition.min !== undefined &&
2493
+ condition.max !== undefined) {
2494
+ // Aralık koşulu: değer aralık içinde olmalı
2495
+ return cellValue >= condition.min && cellValue <= condition.max;
2496
+ }
2497
+ else if (condition.type === 'value' && condition.value !== undefined) {
2498
+ // Değer koşulu: değer eşit olmalı
2499
+ return cellValue === condition.value;
2500
+ }
2501
+ else if (condition.type === 'exclude') {
2502
+ if (condition.value !== undefined) {
2503
+ // Tek değer hariç tutma: değer eşit olmamalı
2504
+ return cellValue !== condition.value;
2505
+ }
2506
+ else if (condition.min !== undefined && condition.max !== undefined) {
2507
+ // Aralık hariç tutma: değer aralık dışında olmalı
2508
+ return !(cellValue >= condition.min && cellValue <= condition.max);
2509
+ }
2510
+ }
2511
+ return false;
2512
+ });
2513
+ return passesAnyCondition;
2514
+ }
2515
+ isFilterActive() {
2516
+ return this.conditions.length > 0;
2517
+ }
2518
+ getModel() {
2519
+ if (this.isFilterActive()) {
2520
+ return {
2521
+ filterType: 'custom',
2522
+ filterText: this.filterText,
2523
+ conditions: this.conditions,
2524
+ };
2525
+ }
2526
+ return null;
2527
+ }
2528
+ setModel(model) {
2529
+ if (model && model.filterText) {
2530
+ this.filterText = model.filterText;
2531
+ this.conditions = model.conditions || [];
2532
+ }
2533
+ else {
2534
+ this.filterText = '';
2535
+ this.conditions = [];
2536
+ }
2537
+ }
2538
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeNumberFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2539
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: RangeNumberFilter, isStandalone: true, selector: "ntybase-range-number-filter", ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@numberFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@numberFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\"\n >{{ '@formats' | translate }}:</strong\n >\n\n <div class=\"custom-filter__format\">\n {{ '@closedRange' | translate }}:\n <code>min..max</code>\n <span class=\"custom-filter__example\">(0..5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrGreater' | translate }}:\n <code>min..</code>\n <span class=\"custom-filter__example\">(5..)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@equalOrLess' | translate }}:\n <code>..max</code>\n <span class=\"custom-filter__example\">(..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@singleValue' | translate }}:\n <code>number</code>\n <span class=\"custom-filter__example\">(10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@exclusion' | translate }}:\n <code>!number</code>\n <span class=\"custom-filter__example\">(!5)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@rangeExclusion' | translate }}:\n <code>!min..max</code>\n <span class=\"custom-filter__example\">(!5..10)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,range</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
2540
+ }
2541
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeNumberFilter, decorators: [{
2542
+ type: Component,
2543
+ args: [{ selector: 'ntybase-range-number-filter', imports: [TranslateModule], 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" }]
2544
+ }] });
2545
+
2546
+ class RangeStringFilter {
2547
+ params;
2548
+ filterText = '';
2549
+ conditions = [];
2550
+ agInit(params) {
2551
+ this.params = params;
2552
+ }
2553
+ onFilterTextChanged(event) {
2554
+ this.filterText = event.target.value;
2555
+ this.parseFilterText();
2556
+ this.params.filterChangedCallback();
2557
+ }
2558
+ parseFilterText() {
2559
+ this.conditions = [];
2560
+ if (!this.filterText.trim()) {
2561
+ return;
2562
+ }
2563
+ const parts = this.filterText
2564
+ .split(',')
2565
+ .map((part) => part.trim())
2566
+ .filter((part) => part !== '');
2567
+ for (const part of parts) {
2568
+ // "!" ile başlayan olumsuz koşul kontrolü
2569
+ if (part.startsWith('!')) {
2570
+ const positiveCondition = part.slice(1);
2571
+ const positiveParsed = this.parseSingleCondition(positiveCondition);
2572
+ if (positiveParsed) {
2573
+ this.conditions.push({
2574
+ type: 'not',
2575
+ condition: positiveParsed,
2576
+ });
2577
+ }
2578
+ continue;
2579
+ }
2580
+ const parsedCondition = this.parseSingleCondition(part);
2581
+ if (parsedCondition) {
2582
+ this.conditions.push(parsedCondition);
2583
+ }
2584
+ }
2585
+ }
2586
+ parseSingleCondition(condition) {
2587
+ // Regex kontrolü ($$ ile başlıyorsa)
2588
+ if (condition.startsWith('$$')) {
2589
+ const regexPattern = condition.slice(2);
2590
+ if (regexPattern) {
2591
+ return {
2592
+ type: 'regex',
2593
+ pattern: regexPattern,
2594
+ };
2595
+ }
2596
+ }
2597
+ // Aralık kontrolü (.. içeriyor mu) - ama $$.. şeklinde değilse
2598
+ if (condition.includes('..') && !condition.startsWith('$$')) {
2599
+ const rangeParts = condition.split('..');
2600
+ if (rangeParts.length === 2) {
2601
+ const start = rangeParts[0].trim();
2602
+ const end = rangeParts[1].trim();
2603
+ if (start && end) {
2604
+ return {
2605
+ type: 'range',
2606
+ start: start.toLowerCase(),
2607
+ end: end.toLowerCase(),
2608
+ };
2609
+ }
2610
+ }
2611
+ }
2612
+ // Tek karakter kontrolü (? ile)
2613
+ else if (condition.includes('?') && !condition.startsWith('$$')) {
2614
+ // Eğer sadece normal karakterler varsa (özel karakter yoksa) exact match
2615
+ const hasSpecialChars = condition.includes('*') ||
2616
+ condition.includes('?') ||
2617
+ condition.includes('..');
2618
+ if (!hasSpecialChars) {
2619
+ return {
2620
+ type: 'exact',
2621
+ value: condition.toLowerCase(),
2622
+ };
2623
+ }
2624
+ // ? karakteri içeriyorsa singleChar kontrolü
2625
+ const value = condition.toLowerCase();
2626
+ if (value) {
2627
+ return {
2628
+ type: 'singleChar',
2629
+ value: value,
2630
+ };
2631
+ }
2632
+ }
2633
+ // Başlangıç kontrolü (* sonunda)
2634
+ else if (condition.endsWith('*') &&
2635
+ !condition.startsWith('*') &&
2636
+ !condition.startsWith('$$')) {
2637
+ const value = condition.slice(0, -1).toLowerCase();
2638
+ if (value) {
2639
+ return {
2640
+ type: 'startsWith',
2641
+ value: value,
2642
+ };
2643
+ }
2644
+ }
2645
+ // Bitiş kontrolü (* başında)
2646
+ else if (condition.startsWith('*') &&
2647
+ !condition.endsWith('*') &&
2648
+ !condition.startsWith('$$')) {
2649
+ const value = condition.slice(1).toLowerCase();
2650
+ if (value) {
2651
+ return {
2652
+ type: 'endsWith',
2653
+ value: value,
2654
+ };
2655
+ }
2656
+ }
2657
+ // İçeren kontrolü (* ile başlayıp * ile bitiyorsa)
2658
+ else if (condition.startsWith('*') &&
2659
+ condition.endsWith('*') &&
2660
+ !condition.startsWith('$$')) {
2661
+ const value = condition.slice(1, -1).toLowerCase();
2662
+ if (value) {
2663
+ return {
2664
+ type: 'contains',
2665
+ value: value,
2666
+ };
2667
+ }
2668
+ }
2669
+ // Normal exact match (hiçbir özel karakter yoksa)
2670
+ else if (!condition.startsWith('$$') &&
2671
+ !condition.includes('*') &&
2672
+ !condition.includes('?') &&
2673
+ !condition.includes('..')) {
2674
+ const value = condition.toLowerCase();
2675
+ if (value) {
2676
+ return {
2677
+ type: 'exact',
2678
+ value: value,
2679
+ };
2680
+ }
2681
+ }
2682
+ // Normal içeren kontrolü (varsayılan) - regex değilse
2683
+ else if (!condition.startsWith('$$')) {
2684
+ const value = condition.toLowerCase();
2685
+ if (value) {
2686
+ return {
2687
+ type: 'contains',
2688
+ value: value,
2689
+ };
2690
+ }
2691
+ }
2692
+ return null;
2693
+ }
2694
+ doesFilterPass(params) {
2695
+ const field = this.params.colDef.field;
2696
+ if (!field)
2697
+ return true;
2698
+ const cellValue = params.data
2699
+ ? String(params.data[field] || '').toLowerCase()
2700
+ : '';
2701
+ // Eğer filtre yoksa tüm satırları göster
2702
+ if (this.conditions.length === 0) {
2703
+ return true;
2704
+ }
2705
+ // Hücre değeri boşsa filtrele
2706
+ if (!cellValue) {
2707
+ return false;
2708
+ }
2709
+ // VİRGÜL OR MANTIĞI: Koşullardan herhangi biri sağlanıyorsa true döndür
2710
+ return this.conditions.some((condition) => {
2711
+ const conditionResult = this.checkSingleCondition(cellValue, condition);
2712
+ return condition.type === 'not' ? !conditionResult : conditionResult;
2713
+ });
2714
+ }
2715
+ checkSingleCondition(cellValue, condition) {
2716
+ switch (condition.type) {
2717
+ case 'contains':
2718
+ return condition.value ? cellValue.includes(condition.value) : false;
2719
+ case 'startsWith':
2720
+ return condition.value ? cellValue.startsWith(condition.value) : false;
2721
+ case 'endsWith':
2722
+ return condition.value ? cellValue.endsWith(condition.value) : false;
2723
+ case 'exact':
2724
+ return condition.value ? cellValue === condition.value : false;
2725
+ case 'range':
2726
+ if (condition.start && condition.end) {
2727
+ return cellValue >= condition.start && cellValue <= condition.end;
2728
+ }
2729
+ return false;
2730
+ case 'singleChar':
2731
+ if (condition.value) {
2732
+ // ? karakterini herhangi bir karakter olarak değerlendir
2733
+ const pattern = condition.value;
2734
+ if (cellValue.length !== pattern.length) {
2735
+ return false;
2736
+ }
2737
+ // Her karakteri tek tek kontrol et
2738
+ for (let i = 0; i < pattern.length; i++) {
2739
+ const patternChar = pattern[i];
2740
+ const cellChar = cellValue[i];
2741
+ // Eğer pattern'de ? değilse ve karakterler eşleşmiyorsa false
2742
+ if (patternChar !== '?' && patternChar !== cellChar) {
2743
+ return false;
2744
+ }
2745
+ }
2746
+ return true;
2747
+ }
2748
+ return false;
2749
+ case 'regex':
2750
+ if (condition.pattern) {
2751
+ try {
2752
+ const regex = new RegExp(condition.pattern, 'i'); // case-insensitive
2753
+ return regex.test(cellValue);
2754
+ }
2755
+ catch (e) {
2756
+ // Geçersiz regex patterni durumunda false döndür
2757
+ console.warn('Geçersiz regex patterni:', condition.pattern);
2758
+ return false;
2759
+ }
2760
+ }
2761
+ return false;
2762
+ case 'not':
2763
+ return this.checkSingleCondition(cellValue, condition.condition);
2764
+ default:
2765
+ return false;
2766
+ }
2767
+ }
2768
+ isFilterActive() {
2769
+ return this.conditions.length > 0;
2770
+ }
2771
+ getModel() {
2772
+ if (this.isFilterActive()) {
2773
+ return {
2774
+ filterType: 'custom',
2775
+ filterText: this.filterText,
2776
+ conditions: this.conditions,
2777
+ };
2778
+ }
2779
+ return null;
2780
+ }
2781
+ setModel(model) {
2782
+ if (model && model.filterText) {
2783
+ this.filterText = model.filterText;
2784
+ this.conditions = model.conditions || [];
2785
+ }
2786
+ else {
2787
+ this.filterText = '';
2788
+ this.conditions = [];
2789
+ }
2790
+ }
2791
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeStringFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
2792
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.11", type: RangeStringFilter, isStandalone: true, selector: "ntybase-range-string-filter", ngImport: i0, template: "<div class=\"custom-filter\">\n <div class=\"custom-filter__header\">\n <label class=\"custom-filter__title\">\n {{ '@stringFilter' | translate }}\n </label>\n <input\n type=\"text\"\n class=\"custom-filter__input\"\n [placeholder]=\"'@stringFilterPlaceholder' | translate\"\n [value]=\"filterText\"\n (input)=\"onFilterTextChanged($event)\"\n />\n </div>\n\n <div class=\"custom-filter__help\">\n <strong class=\"custom-filter__help-title\">\n {{ '@formats' | translate }}:\n </strong>\n\n <div class=\"custom-filter__format\">\n {{ '@exactMatch' | translate }}:\n <code>text</code>\n <span class=\"custom-filter__example\">(ahmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@startsWith' | translate }}:\n <code>text*</code>\n <span class=\"custom-filter__example\">(ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@endsWith' | translate }}:\n <code>*text</code>\n <span class=\"custom-filter__example\">(*metin)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@contains' | translate }}:\n <code>*text*</code>\n <span class=\"custom-filter__example\">(*ahmet*)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@range' | translate }}:\n <code>start..end</code>\n <span class=\"custom-filter__example\">(ali..veli)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@singleCharacter' | translate }}:\n </span>\n <code>?em</code>\n <span class=\"custom-filter__example\">\n (?em = 3 characters, 2nd and 3rd letters \"em\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n <span class=\"custom-filter__description\">\n {{ '@multipleCharacters' | translate }}:\n </span>\n <code>???in</code>\n <span class=\"custom-filter__example\">\n (5 characters, last 2 letters \"in\")\n </span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@not' | translate }}:\n <code>!condition</code>\n <span class=\"custom-filter__example\">(!*ahmet*, !?hmet)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@regex' | translate }}:\n <code>$$pattern</code>\n <span class=\"custom-filter__example\">($$^[A-Z].*, $$a.*b)</span>\n </div>\n\n <div class=\"custom-filter__format\">\n {{ '@multiple' | translate }}:\n <code>value1,value2,*end,$$pattern</code>\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i3$1.TranslatePipe, name: "translate" }] });
2793
+ }
2794
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.11", ngImport: i0, type: RangeStringFilter, decorators: [{
2795
+ type: Component,
2796
+ args: [{ selector: 'ntybase-range-string-filter', imports: [TranslateModule], 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" }]
2797
+ }] });
2798
+
2003
2799
  class AuthenticationGuard {
2004
2800
  router = inject(Router);
2005
2801
  credentialsService = inject(CredentialsService);
@@ -2188,7 +2984,7 @@ class AuthenticationService {
2188
2984
  logout() {
2189
2985
  // Customize credentials invalidation here
2190
2986
  this.credentialsService.setCredentials();
2191
- localStorage.clear();
2987
+ //localStorage.clear();
2192
2988
  return of(true);
2193
2989
  }
2194
2990
  /** Send a pasword reset e-mail
@@ -2309,14 +3105,47 @@ class Login extends AuthBase {
2309
3105
  this.icon.set(true);
2310
3106
  this.authService.getAdminLink('Login');
2311
3107
  this.timeout(500).then(() => this.authService.getAdminLink('Login'));
3108
+ this.loadRememberedUsername();
2312
3109
  }
2313
3110
  timeout(ms) {
2314
3111
  return new Promise((resolve) => setTimeout(resolve, ms));
2315
3112
  }
3113
+ handleRememberMe() {
3114
+ const formValues = this.loginForm.value;
3115
+ try {
3116
+ if (formValues.remember) {
3117
+ localStorage.setItem('remembered_username', formValues.username);
3118
+ localStorage.setItem('remember_me', 'true');
3119
+ }
3120
+ else {
3121
+ localStorage.removeItem('remembered_username');
3122
+ localStorage.removeItem('remember_me');
3123
+ }
3124
+ }
3125
+ catch (error) {
3126
+ console.error('Error handling remember me:', error);
3127
+ }
3128
+ }
3129
+ loadRememberedUsername() {
3130
+ try {
3131
+ const rememberedUsername = localStorage.getItem('remembered_username');
3132
+ const rememberMe = localStorage.getItem('remember_me') === 'true';
3133
+ if (rememberedUsername && rememberMe) {
3134
+ this.loginForm.patchValue({
3135
+ username: rememberedUsername,
3136
+ remember: true,
3137
+ });
3138
+ }
3139
+ }
3140
+ catch (error) {
3141
+ console.error('Error loading remembered username:', error);
3142
+ }
3143
+ }
2316
3144
  login() {
2317
3145
  this.isLoading.set(true);
2318
3146
  // Get the form values
2319
3147
  const formValues = this.loginForm.value;
3148
+ this.handleRememberMe();
2320
3149
  this.authService
2321
3150
  .login(formValues) // Use the form values directly
2322
3151
  .pipe(finalize(() => {
@@ -3216,8 +4045,8 @@ class NettyBaseApp {
3216
4045
  i18nService = inject(I18nService);
3217
4046
  async loadBaseTranslations() {
3218
4047
  try {
3219
- const enUSBase = await import('./nettyapps-ntybase-en-USbase-DE6OxgCf.mjs');
3220
- const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-yJyG8qmQ.mjs');
4048
+ const enUSBase = await import('./nettyapps-ntybase-en-USbase-D8YJXJ5r.mjs');
4049
+ const trTRBase = await import('./nettyapps-ntybase-tr-TRbase-DtiNXQKJ.mjs');
3221
4050
  this.i18nService.addTranslations('English', enUSBase.default);
3222
4051
  this.i18nService.addTranslations('Türkçe', trTRBase.default);
3223
4052
  }
@@ -3879,5 +4708,5 @@ class NettyFilter {
3879
4708
  * Generated bundle index. Do not edit.
3880
4709
  */
3881
4710
 
3882
- export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, AutoComplete, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, ColorPalette, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ENVIRONMENT_CONFIG, EnvironmentInfo, EnvironmentInfoService, ExcelImportBase, ForgotPassword, Guid, HttpError403, HttpError404, LeftSidenav, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridSaveBase, NettyAgGridService, NettyBaseApp, NettyFilter, NettyHelper, NettyMenuService, Ntybase, NtybaseModule, SelectionItem, Theme, Toolbar, UrlHelperService };
4711
+ export { AlertService, AuthenticationGuard, AuthenticationInterceptor, AuthenticationService, AutoComplete, ButtonRenderer, CanDeactivateGuard, CheckboxRenderer, ColorPalette, CommonService, ConfirmDialog, CredentialsService, CurrentUserPreference, ENVIRONMENT_CONFIG, EnvironmentInfo, EnvironmentInfoService, ExcelImportBase, ForgotPassword, Guid, HttpError403, HttpError404, LeftSidenav, Login, LoginDto, MFACodeDto, MfaLogin, NettyAgGridBase, NettyAgGridSaveBase, NettyAgGridService, NettyBaseApp, NettyFilter, NettyHelper, NettyMenuService, Ntybase, NtybaseModule, RangeDateTimeFilter, RangeNumberFilter, RangeStringFilter, SelectionItem, Theme, Toolbar, UrlHelperService };
3883
4712
  //# sourceMappingURL=nettyapps-ntybase.mjs.map