@servicemind.tis/tis-smart-table-viewer 2.2.0 → 2.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ import * as i6 from '@angular/forms';
5
5
  import { FormGroup, FormControl, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
6
6
  import * as i3$1 from '@angular/router';
7
7
  import { RouterLink, RouterOutlet } from '@angular/router';
8
- import { BehaviorSubject, of, Subject, takeUntil, tap, map, shareReplay, debounceTime, distinctUntilChanged } from 'rxjs';
8
+ import { BehaviorSubject, of, takeUntil, Subject, tap, map, shareReplay, debounceTime, distinctUntilChanged } from 'rxjs';
9
9
  import { SelectionModel } from '@angular/cdk/collections';
10
10
  import * as i13 from '@angular/cdk/drag-drop';
11
11
  import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
@@ -78,9 +78,9 @@ class ApiDataSource {
78
78
  this.apiSubject.complete();
79
79
  this.extraDataSubject.complete();
80
80
  this.loadingSubject.complete();
81
- // if(this.apiSubs) {
82
- // this.apiSubs.unsubscribe();
83
- // }
81
+ if (this.apiSubs) {
82
+ this.apiSubs.unsubscribe();
83
+ }
84
84
  }
85
85
  load(url, pageIndex, pageSize, search, filter, sortFilter) {
86
86
  if (this.apiSubs) {
@@ -99,6 +99,28 @@ class ApiDataSource {
99
99
  this.extraDataSubject.next(r?.extraData);
100
100
  });
101
101
  }
102
+ loadWithCancellation(url, pageIndex, pageSize, search, filter, sortFilter, cancelSubject) {
103
+ if (this.apiSubs) {
104
+ this.apiSubs.unsubscribe();
105
+ }
106
+ this.loadingSubject.next(true);
107
+ let apiCall$ = this.apiService.getList(url, (pageIndex + 1), pageSize, search, { filter }, { sortFilter }).pipe(catchError(() => of([])), finalize(() => this.loadingSubject.next(false)));
108
+ // Add cancellation capability if provided
109
+ if (cancelSubject) {
110
+ apiCall$ = apiCall$.pipe(takeUntil(cancelSubject));
111
+ }
112
+ this.apiSubs = apiCall$.subscribe(r => {
113
+ console.log(`DataSource: Url: ${url}, Reply:`, r);
114
+ if (r?.data?.length > 0) {
115
+ this.totalDataLength.next(r?.total);
116
+ }
117
+ else {
118
+ this.totalDataLength.next(0);
119
+ }
120
+ this.apiSubject.next(r?.data);
121
+ this.extraDataSubject.next(r?.extraData);
122
+ });
123
+ }
102
124
  }
103
125
 
104
126
  class ApiService {
@@ -166,6 +188,943 @@ const removeMultipleKeys = (keys) => {
166
188
  });
167
189
  };
168
190
 
191
+ /**
192
+ * TimeoutManager - A utility class for managing timeouts to prevent memory leaks
193
+ *
194
+ * This class provides a centralized way to create, track, and clean up setTimeout calls.
195
+ * It automatically handles cleanup when component is destroyed to prevent memory leaks.
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * export class MyComponent implements OnDestroy {
200
+ * private timeoutManager = new TimeoutManager();
201
+ *
202
+ * someMethod() {
203
+ * this.timeoutManager.createTimeout(() => {
204
+ * console.log('Delayed execution');
205
+ * }, 1000);
206
+ * }
207
+ *
208
+ * ngOnDestroy() {
209
+ * this.timeoutManager.clearAll(); // Clean up all pending timeouts
210
+ * }
211
+ * }
212
+ * ```
213
+ */
214
+ class TimeoutManager {
215
+ activeTimeouts = new Set();
216
+ /**
217
+ * Creates a tracked timeout that will be automatically cleaned up
218
+ * @param callback - Function to execute after delay
219
+ * @param delay - Delay in milliseconds
220
+ * @returns The timeout ID (same as setTimeout return value)
221
+ */
222
+ createTimeout(callback, delay) {
223
+ const timeoutId = setTimeout(() => {
224
+ // Auto-remove from tracking when timeout executes naturally
225
+ this.activeTimeouts.delete(timeoutId);
226
+ callback();
227
+ }, delay);
228
+ // Add to tracking set
229
+ this.activeTimeouts.add(timeoutId);
230
+ return timeoutId;
231
+ }
232
+ /**
233
+ * Manually clear a specific timeout
234
+ * @param timeoutId - The timeout ID returned from createTimeout
235
+ */
236
+ clearTimeout(timeoutId) {
237
+ if (this.activeTimeouts.has(timeoutId)) {
238
+ clearTimeout(timeoutId);
239
+ this.activeTimeouts.delete(timeoutId);
240
+ }
241
+ }
242
+ /**
243
+ * Clear all pending timeouts
244
+ * This should be called in ngOnDestroy to prevent memory leaks
245
+ */
246
+ clearAll() {
247
+ this.activeTimeouts.forEach(timeoutId => clearTimeout(timeoutId));
248
+ this.activeTimeouts.clear();
249
+ }
250
+ /**
251
+ * Get the number of active (pending) timeouts
252
+ * Useful for debugging and testing
253
+ */
254
+ get activeCount() {
255
+ return this.activeTimeouts.size;
256
+ }
257
+ /**
258
+ * Check if a specific timeout is still active
259
+ * @param timeoutId - The timeout ID to check
260
+ */
261
+ isActive(timeoutId) {
262
+ return this.activeTimeouts.has(timeoutId);
263
+ }
264
+ }
265
+ /**
266
+ * Static helper functions for one-off timeout usage
267
+ * Use the TimeoutManager class for more comprehensive timeout management
268
+ */
269
+ class TimeoutHelper {
270
+ /**
271
+ * Create a single tracked timeout with external cleanup responsibility
272
+ * @param callback - Function to execute after delay
273
+ * @param delay - Delay in milliseconds
274
+ * @param trackingSet - Set to track the timeout for cleanup
275
+ * @returns The timeout ID
276
+ */
277
+ static createTrackedTimeout(callback, delay, trackingSet) {
278
+ const timeoutId = setTimeout(() => {
279
+ trackingSet.delete(timeoutId);
280
+ callback();
281
+ }, delay);
282
+ trackingSet.add(timeoutId);
283
+ return timeoutId;
284
+ }
285
+ /**
286
+ * Clear all timeouts in a tracking set
287
+ * @param trackingSet - Set containing timeout IDs to clear
288
+ */
289
+ static clearAllTimeouts(trackingSet) {
290
+ trackingSet.forEach(timeoutId => clearTimeout(timeoutId));
291
+ trackingSet.clear();
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Centralized date/time utility helper for consistent date handling across the library.
297
+ * Provides common date formatting and conversion functions to avoid code duplication.
298
+ */
299
+ class DateTimeHelper {
300
+ /**
301
+ * Formats a date value for display based on form control type
302
+ * @param value - The date value (Date, DateTime, string, number)
303
+ * @param formControlType - The type of form control ('date', 'date-time', etc.)
304
+ * @returns Formatted date string
305
+ */
306
+ static formatForDisplay(value, formControlType) {
307
+ if (!value)
308
+ return '';
309
+ const dateTime = this.toDateTime(value);
310
+ if (!dateTime?.isValid)
311
+ return '';
312
+ switch (formControlType) {
313
+ case 'date':
314
+ return dateTime.toFormat('dd-MM-yyyy');
315
+ case 'date-time':
316
+ return dateTime.toFormat('dd-MM-yyyy HH:mm');
317
+ case 'date-time-with-seconds':
318
+ return dateTime.toFormat('dd-MM-yyyy HH:mm:ss');
319
+ default:
320
+ return dateTime.toFormat('dd-MM-yyyy');
321
+ }
322
+ }
323
+ /**
324
+ * Converts various date formats to DateTime object
325
+ * @param value - Date value in various formats
326
+ * @returns DateTime object or null if invalid
327
+ */
328
+ static toDateTime(value) {
329
+ if (!value)
330
+ return null;
331
+ if (DateTime.isDateTime(value)) {
332
+ return value;
333
+ }
334
+ if (value instanceof Date) {
335
+ return DateTime.fromJSDate(value);
336
+ }
337
+ if (typeof value === 'string' && value !== '') {
338
+ // Try parsing as milliseconds first (if numeric string)
339
+ const numValue = Number(value);
340
+ if (!isNaN(numValue) && numValue > 0) {
341
+ return DateTime.fromMillis(numValue);
342
+ }
343
+ // Try parsing as ISO string
344
+ return DateTime.fromISO(value);
345
+ }
346
+ if (typeof value === 'number') {
347
+ return DateTime.fromMillis(value);
348
+ }
349
+ return null;
350
+ }
351
+ /**
352
+ * Converts date/DateTime objects to milliseconds for API calls
353
+ * @param value - Date value
354
+ * @returns Milliseconds or original value if not a date
355
+ */
356
+ static toMilliseconds(value) {
357
+ if (!value)
358
+ return value;
359
+ if (value instanceof Date) {
360
+ return DateTime.fromJSDate(value).toMillis();
361
+ }
362
+ if (DateTime.isDateTime(value)) {
363
+ return value.toMillis();
364
+ }
365
+ return value;
366
+ }
367
+ /**
368
+ * Checks if a query parameter key represents a date field
369
+ * @param key - Query parameter key
370
+ * @param value - Query parameter value
371
+ * @returns True if it's a date field
372
+ */
373
+ static isDateQueryParam(key, value) {
374
+ return key.toLowerCase().includes('date') && value.length === 13;
375
+ }
376
+ /**
377
+ * Parses date from query parameters
378
+ * @param value - Query parameter value (milliseconds as string)
379
+ * @returns DateTime object
380
+ */
381
+ static parseFromQueryParam(value) {
382
+ return DateTime.fromMillis(Number(value));
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Centralized query parameter utility helper for consistent URL parameter handling.
388
+ * Provides common functions for parsing, validating, and transforming query parameters.
389
+ */
390
+ class QueryParamsHelper {
391
+ /**
392
+ * Parses query parameters from URL and handles type conversions
393
+ * @param url - Full URL string
394
+ * @returns Parsed query parameters object
395
+ */
396
+ static parseQueryParams(url) {
397
+ const urlObj = new URL(url);
398
+ const params = new URLSearchParams(urlObj.search);
399
+ const paramsObj = {};
400
+ params.forEach((value, key) => {
401
+ // Check if the parameter already exists (for handling multiple values)
402
+ if (paramsObj.hasOwnProperty(key)) {
403
+ // If it's not already an array, convert it to an array
404
+ if (!Array.isArray(paramsObj[key])) {
405
+ paramsObj[key] = [paramsObj[key]];
406
+ }
407
+ // Push the new value to the existing array
408
+ paramsObj[key].push(value);
409
+ }
410
+ else {
411
+ // Assign the value to the key in the object
412
+ paramsObj[key] = value;
413
+ }
414
+ });
415
+ return paramsObj;
416
+ }
417
+ /**
418
+ * Checks if a query parameter value is valid (not empty, null, or undefined)
419
+ * @param value - Query parameter value
420
+ * @returns True if valid
421
+ */
422
+ static isValidParam(value) {
423
+ return value && value !== '' && value !== 'null' && value !== 'undefined';
424
+ }
425
+ /**
426
+ * Processes a query parameter value and handles arrays
427
+ * @param value - Raw query parameter value
428
+ * @returns Processed value (string or array)
429
+ */
430
+ static processParamValue(value) {
431
+ if (value.includes(',')) {
432
+ return value.split(',');
433
+ }
434
+ return value;
435
+ }
436
+ /**
437
+ * Processes query parameters for filter form with type conversions
438
+ * @param queryParams - Raw query parameters
439
+ * @param columnsCodeMapping - Column mapping for transformations
440
+ * @returns Processed filter and sort objects
441
+ */
442
+ static processForFilters(queryParams, columnsCodeMapping) {
443
+ const filterParams = {};
444
+ const sortParams = {};
445
+ let pageIndex = 0;
446
+ let pageSize = 10;
447
+ let search = '';
448
+ for (const key in queryParams) {
449
+ if (!this.isValidParam(queryParams[key]))
450
+ continue;
451
+ let fixedKeyMatched = false;
452
+ const value = queryParams[key];
453
+ // Handle fixed parameters
454
+ if (key.toLowerCase() === 'pageindex') {
455
+ pageIndex = Number(value);
456
+ fixedKeyMatched = true;
457
+ }
458
+ else if (key.toLowerCase() === 'pagesize') {
459
+ pageSize = Number(value);
460
+ fixedKeyMatched = true;
461
+ }
462
+ else if (key.toLowerCase() === 'sortby') {
463
+ sortParams.sortBy = value;
464
+ fixedKeyMatched = true;
465
+ }
466
+ else if (key.toLowerCase() === 'sortorder') {
467
+ sortParams.sortOrder = value;
468
+ fixedKeyMatched = true;
469
+ }
470
+ else if (key.toLowerCase() === 'search') {
471
+ search = value;
472
+ fixedKeyMatched = true;
473
+ }
474
+ else if (DateTimeHelper.isDateQueryParam(key, value)) {
475
+ // Handle date parameters
476
+ filterParams[key] = DateTimeHelper.parseFromQueryParam(value);
477
+ fixedKeyMatched = true;
478
+ }
479
+ if (!fixedKeyMatched) {
480
+ filterParams[key] = this.processParamValue(value);
481
+ // Apply transformation if mapping exists
482
+ const mapping = columnsCodeMapping.find(ccm => ccm.filterFormKey === key);
483
+ if (mapping?.transformQueryParamFn) {
484
+ filterParams[key] = mapping.transformQueryParamFn(filterParams[key]);
485
+ }
486
+ }
487
+ }
488
+ return { filterParams, sortParams, pageIndex, pageSize, search };
489
+ }
490
+ /**
491
+ * Builds query string from filter data with proper encoding
492
+ * @param filterData - Filter form data
493
+ * @param sortParams - Sort parameters
494
+ * @param pageIndex - Current page index
495
+ * @param pageSize - Current page size
496
+ * @param search - Search term
497
+ * @returns URLSearchParams object
498
+ */
499
+ static buildQueryString(filterData, sortParams, pageIndex, pageSize, search) {
500
+ const qs = new URLSearchParams();
501
+ // Process filter data
502
+ if (filterData) {
503
+ const processedFilter = { ...filterData };
504
+ // Convert date objects to milliseconds
505
+ for (const key in processedFilter) {
506
+ processedFilter[key] = DateTimeHelper.toMilliseconds(processedFilter[key]);
507
+ }
508
+ // Append filter parameters
509
+ Object.keys(processedFilter).forEach(key => {
510
+ const value = processedFilter[key];
511
+ if (this.isValidParam(value)) {
512
+ if (value === '*') {
513
+ qs.append(key, '');
514
+ }
515
+ else {
516
+ qs.append(key, value);
517
+ }
518
+ }
519
+ });
520
+ }
521
+ // Append sort parameters
522
+ if (sortParams) {
523
+ Object.keys(sortParams).forEach(key => {
524
+ if (this.isValidParam(sortParams[key])) {
525
+ qs.append(key, sortParams[key]);
526
+ }
527
+ });
528
+ }
529
+ // Append pagination and search
530
+ qs.append('pageIndex', pageIndex.toString());
531
+ qs.append('pageSize', pageSize.toString());
532
+ if (search !== '') {
533
+ qs.append('search', search);
534
+ }
535
+ return qs;
536
+ }
537
+ }
538
+
539
+ /**
540
+ * Centralized filter display utility helper for managing filter value formatting and grouping.
541
+ * Handles the complex logic of grouping and displaying filter values in a consistent manner.
542
+ */
543
+ class FilterDisplayHelper {
544
+ /**
545
+ * Formats filter values based on form control type for display
546
+ * @param items - Array of filter display values
547
+ * @returns Processed array with formatted display values
548
+ */
549
+ static formatFilterValuesForDisplay(items) {
550
+ return items.map(item => {
551
+ const processedItem = { ...item };
552
+ // Handle different form control types
553
+ switch (item.formControlType) {
554
+ case 'input':
555
+ case 'checkbox':
556
+ // No special formatting needed
557
+ break;
558
+ case 'date':
559
+ processedItem.valueKey = DateTimeHelper.formatForDisplay(item.value, 'date');
560
+ break;
561
+ case 'date-time':
562
+ processedItem.valueKey = DateTimeHelper.formatForDisplay(item.value, 'date-time');
563
+ break;
564
+ default:
565
+ // Keep original valueKey if no special handling needed
566
+ break;
567
+ }
568
+ return processedItem;
569
+ });
570
+ }
571
+ /**
572
+ * Groups filter values by form control attributes
573
+ * @param data - Array of filter display values
574
+ * @returns Grouped filter values
575
+ */
576
+ static groupByFormControlAttributes(data) {
577
+ const groups = {};
578
+ // First format the data for display
579
+ const formattedData = this.formatFilterValuesForDisplay(data);
580
+ formattedData.forEach(item => {
581
+ const key = `${item.formControlName}-${item.formControlType}`;
582
+ if (!groups[key]) {
583
+ groups[key] = {
584
+ formControlName: item.formControlName,
585
+ formControlType: item.formControlType,
586
+ arrValues: []
587
+ };
588
+ }
589
+ const isSingleValue = this.isSingleValueFormControl(item.formControlType, item.isSingleValue);
590
+ // Check if only the last value should be kept due to isSingleValue or duplicated value/valueKey
591
+ if (isSingleValue) {
592
+ groups[key].arrValues = [item]; // Replace with the current item
593
+ }
594
+ else {
595
+ // Check for duplicate value and valueKey in the current array
596
+ const existingIndex = groups[key].arrValues.findIndex(x => x.value === item.value && x.valueKey === item.valueKey);
597
+ if (existingIndex !== -1) {
598
+ groups[key].arrValues[existingIndex] = item; // Replace the duplicate
599
+ }
600
+ else {
601
+ groups[key].arrValues.push(item); // Add new item
602
+ }
603
+ }
604
+ });
605
+ return Object.values(groups);
606
+ }
607
+ /**
608
+ * Determines if a form control should only have single values
609
+ * @param formControlType - Type of form control
610
+ * @param explicitSingleValue - Explicit single value flag
611
+ * @returns True if single value control
612
+ */
613
+ static isSingleValueFormControl(formControlType, explicitSingleValue) {
614
+ if (explicitSingleValue !== undefined) {
615
+ return explicitSingleValue;
616
+ }
617
+ return ['input', 'radio', 'date', 'date-time', 'toggle'].includes(formControlType);
618
+ }
619
+ /**
620
+ * Updates selected filter values by replacing values for a specific form control
621
+ * @param currentValues - Current selected filter values
622
+ * @param newValues - New values to add/update
623
+ * @param formControlName - Name of the form control being updated
624
+ * @returns Updated filter values and grouped values
625
+ */
626
+ static updateSelectedFilterValues(currentValues, newValues, formControlName) {
627
+ let targetFormControlName;
628
+ let newValuesArray;
629
+ if (Array.isArray(newValues)) {
630
+ newValuesArray = newValues;
631
+ targetFormControlName = formControlName || newValues[0]?.formControlName;
632
+ }
633
+ else {
634
+ newValuesArray = [newValues];
635
+ targetFormControlName = formControlName || newValues?.formControlName;
636
+ }
637
+ // Remove existing values for this form control
638
+ const filteredValues = currentValues.filter(sfv => sfv.formControlName !== targetFormControlName);
639
+ // Group the new values
640
+ const newGroupedValues = this.groupByFormControlAttributes(newValuesArray);
641
+ // Add new values for the target form control
642
+ newGroupedValues.forEach(gv => {
643
+ if (gv.formControlName === targetFormControlName) {
644
+ gv.arrValues.forEach(v => {
645
+ filteredValues.push(v);
646
+ });
647
+ }
648
+ });
649
+ // Return updated values and all grouped values
650
+ const allGroupedValues = this.groupByFormControlAttributes(filteredValues);
651
+ return {
652
+ selectedFilterValues: filteredValues,
653
+ selectedFilterGroupedValues: allGroupedValues
654
+ };
655
+ }
656
+ /**
657
+ * Filters selected values to only show those present in query parameters
658
+ * @param selectedValues - All selected filter values
659
+ * @param queryParams - Current query parameters
660
+ * @returns Filtered values for display
661
+ */
662
+ static getValuesForDisplay(selectedValues, queryParams) {
663
+ return selectedValues.filter(sf => queryParams.hasOwnProperty(sf.formControlName));
664
+ }
665
+ /**
666
+ * Removes a specific filter value from the collection
667
+ * @param selectedValues - Current selected filter values
668
+ * @param filterToRemove - Filter value to remove
669
+ * @returns Updated filter values
670
+ */
671
+ static removeFilterValue(selectedValues, filterToRemove) {
672
+ return selectedValues.filter(sfv => !(sfv.formControlName === filterToRemove.formControlName &&
673
+ sfv.valueKey === filterToRemove.valueKey));
674
+ }
675
+ }
676
+
677
+ /**
678
+ * Centralized validation utility helper for common validation tasks.
679
+ * Provides reusable validation functions to avoid code duplication.
680
+ */
681
+ class ValidationHelper {
682
+ /**
683
+ * Checks if a value is not null, undefined, or empty string
684
+ * @param value - Value to check
685
+ * @returns True if value has content
686
+ */
687
+ static hasValue(value) {
688
+ return value !== null && value !== undefined && value !== '';
689
+ }
690
+ /**
691
+ * Checks if any values in an object are non-empty
692
+ * @param obj - Object to check
693
+ * @returns True if any value is non-empty
694
+ */
695
+ static hasNonEmptyValue(obj) {
696
+ if (!obj)
697
+ return false;
698
+ return Object.values(obj).some(value => this.hasValue(value));
699
+ }
700
+ /**
701
+ * Checks if a form has any non-empty values
702
+ * @param formData - Form data object
703
+ * @returns True if form has any data
704
+ */
705
+ static hasFormData(formData) {
706
+ if (!formData)
707
+ return false;
708
+ return this.hasNonEmptyValue(formData);
709
+ }
710
+ /**
711
+ * Validates if an array has items
712
+ * @param array - Array to check
713
+ * @returns True if array exists and has items
714
+ */
715
+ static hasItems(array) {
716
+ return Array.isArray(array) && array.length > 0;
717
+ }
718
+ /**
719
+ * Checks if a URL is valid
720
+ * @param url - URL string to validate
721
+ * @returns True if URL is valid
722
+ */
723
+ static isValidUrl(url) {
724
+ if (!url || typeof url !== 'string')
725
+ return false;
726
+ try {
727
+ new URL(url);
728
+ return true;
729
+ }
730
+ catch {
731
+ return false;
732
+ }
733
+ }
734
+ /**
735
+ * Validates if a string is a valid number
736
+ * @param value - Value to check
737
+ * @returns True if value is a valid number
738
+ */
739
+ static isValidNumber(value) {
740
+ return !isNaN(Number(value)) && isFinite(Number(value));
741
+ }
742
+ /**
743
+ * Checks if an object has a specific property with a valid value
744
+ * @param obj - Object to check
745
+ * @param property - Property name
746
+ * @returns True if property exists and has a value
747
+ */
748
+ static hasProperty(obj, property) {
749
+ return obj && obj.hasOwnProperty(property) && this.hasValue(obj[property]);
750
+ }
751
+ /**
752
+ * Validates if a selection model row has the required key
753
+ * @param row - Row object
754
+ * @param keyName - Key property name
755
+ * @returns True if row has the key property with a value
756
+ */
757
+ static hasRowKey(row, keyName) {
758
+ return row && this.hasProperty(row, keyName);
759
+ }
760
+ /**
761
+ * Checks if a filter value should be processed (not null, empty, or invalid)
762
+ * @param value - Filter value
763
+ * @returns True if filter value is valid for processing
764
+ */
765
+ static isValidFilterValue(value) {
766
+ if (!this.hasValue(value))
767
+ return false;
768
+ // Check for common invalid filter values
769
+ const invalidValues = ['null', 'undefined', '*'];
770
+ if (typeof value === 'string' && invalidValues.includes(value)) {
771
+ return value === '*'; // Special case: '*' is valid but gets converted to empty string
772
+ }
773
+ return true;
774
+ }
775
+ /**
776
+ * Validates pagination parameters
777
+ * @param pageIndex - Page index
778
+ * @param pageSize - Page size
779
+ * @returns Object with validation results
780
+ */
781
+ static validatePagination(pageIndex, pageSize) {
782
+ const validPageIndex = this.isValidNumber(pageIndex) ? Number(pageIndex) : 0;
783
+ const validPageSize = this.isValidNumber(pageSize) ? Number(pageSize) : 10;
784
+ return {
785
+ isValid: validPageIndex >= 0 && validPageSize > 0,
786
+ pageIndex: Math.max(0, validPageIndex),
787
+ pageSize: Math.max(1, validPageSize)
788
+ };
789
+ }
790
+ }
791
+
792
+ /**
793
+ * Centralized collection management utility helper for common array and object operations.
794
+ * Provides reusable functions for managing collections, selections, and data structures.
795
+ */
796
+ class CollectionHelper {
797
+ /**
798
+ * Safely clears an array if it exists
799
+ * @param array - Array to clear
800
+ */
801
+ static clearArray(array) {
802
+ if (Array.isArray(array)) {
803
+ array.length = 0;
804
+ }
805
+ }
806
+ /**
807
+ * Safely clears a Set if it exists
808
+ * @param set - Set to clear
809
+ */
810
+ static clearSet(set) {
811
+ if (set instanceof Set) {
812
+ set.clear();
813
+ }
814
+ }
815
+ /**
816
+ * Safely clears a Map if it exists
817
+ * @param map - Map to clear
818
+ */
819
+ static clearMap(map) {
820
+ if (map instanceof Map) {
821
+ map.clear();
822
+ }
823
+ }
824
+ /**
825
+ * Gets a consistent identifier for a row based on available keys
826
+ * @param row - Row object
827
+ * @param primaryKey - Primary key property name (default: 'id')
828
+ * @param fallbackKey - Fallback key property name
829
+ * @returns Row identifier or JSON string as last resort
830
+ */
831
+ static getRowIdentifier(row, primaryKey = 'id', fallbackKey) {
832
+ if (!row)
833
+ return '';
834
+ // Try primary key first
835
+ if (row[primaryKey] !== undefined && row[primaryKey] !== null) {
836
+ return row[primaryKey];
837
+ }
838
+ // Try fallback key if provided
839
+ if (fallbackKey && row[fallbackKey] !== undefined && row[fallbackKey] !== null) {
840
+ return row[fallbackKey];
841
+ }
842
+ // Last resort: stringify the object (not recommended for large objects)
843
+ return JSON.stringify(row);
844
+ }
845
+ /**
846
+ * Creates a hash from an array of objects for cache validation
847
+ * @param items - Array of items to hash
848
+ * @param keyExtractor - Function to extract key from each item
849
+ * @returns Hash string
850
+ */
851
+ static createArrayHash(items, keyExtractor) {
852
+ if (!Array.isArray(items))
853
+ return '';
854
+ return JSON.stringify(items.map(keyExtractor));
855
+ }
856
+ /**
857
+ * Safely filters an array with predicate function
858
+ * @param array - Array to filter
859
+ * @param predicate - Filter predicate function
860
+ * @returns Filtered array or empty array if input is invalid
861
+ */
862
+ static safeFilter(array, predicate) {
863
+ if (!Array.isArray(array))
864
+ return [];
865
+ return array.filter(predicate);
866
+ }
867
+ /**
868
+ * Safely maps an array with transform function
869
+ * @param array - Array to map
870
+ * @param transform - Transform function
871
+ * @returns Mapped array or empty array if input is invalid
872
+ */
873
+ static safeMap(array, transform) {
874
+ if (!Array.isArray(array))
875
+ return [];
876
+ return array.map(transform);
877
+ }
878
+ /**
879
+ * Safely finds an item in array
880
+ * @param array - Array to search
881
+ * @param predicate - Find predicate function
882
+ * @returns Found item or undefined
883
+ */
884
+ static safeFind(array, predicate) {
885
+ if (!Array.isArray(array))
886
+ return undefined;
887
+ return array.find(predicate);
888
+ }
889
+ /**
890
+ * Creates a Map from an array for O(1) lookups
891
+ * @param array - Array to convert
892
+ * @param keyExtractor - Function to extract key from each item
893
+ * @returns Map with keys and items
894
+ */
895
+ static createLookupMap(array, keyExtractor) {
896
+ const map = new Map();
897
+ if (!Array.isArray(array))
898
+ return map;
899
+ array.forEach(item => {
900
+ const key = keyExtractor(item);
901
+ map.set(key, item);
902
+ });
903
+ return map;
904
+ }
905
+ /**
906
+ * Checks if two arrays have the same items (order doesn't matter)
907
+ * @param array1 - First array
908
+ * @param array2 - Second array
909
+ * @param keyExtractor - Function to extract comparison key
910
+ * @returns True if arrays contain same items
911
+ */
912
+ static arraysEqual(array1, array2, keyExtractor) {
913
+ if (!Array.isArray(array1) || !Array.isArray(array2))
914
+ return false;
915
+ if (array1.length !== array2.length)
916
+ return false;
917
+ if (keyExtractor) {
918
+ const keys1 = array1.map(keyExtractor).sort();
919
+ const keys2 = array2.map(keyExtractor).sort();
920
+ return JSON.stringify(keys1) === JSON.stringify(keys2);
921
+ }
922
+ else {
923
+ return JSON.stringify([...array1].sort()) === JSON.stringify([...array2].sort());
924
+ }
925
+ }
926
+ /**
927
+ * Safely removes items from a Set based on a predicate
928
+ * @param set - Set to modify
929
+ * @param predicate - Function to determine if item should be removed
930
+ */
931
+ static removeFromSet(set, predicate) {
932
+ if (!(set instanceof Set))
933
+ return;
934
+ const itemsToRemove = [];
935
+ set.forEach(item => {
936
+ if (predicate(item)) {
937
+ itemsToRemove.push(item);
938
+ }
939
+ });
940
+ itemsToRemove.forEach(item => set.delete(item));
941
+ }
942
+ /**
943
+ * Safely clones an array to prevent mutation issues
944
+ * @param array - Array to clone
945
+ * @returns Cloned array or empty array if input is invalid
946
+ */
947
+ static cloneArray(array) {
948
+ if (!Array.isArray(array))
949
+ return [];
950
+ return [...array];
951
+ }
952
+ /**
953
+ * Performs safe property access with default value
954
+ * @param obj - Object to access
955
+ * @param path - Property path (e.g., 'user.profile.name')
956
+ * @param defaultValue - Default value if property doesn't exist
957
+ * @returns Property value or default
958
+ */
959
+ static getNestedProperty(obj, path, defaultValue = null) {
960
+ if (!obj || !path)
961
+ return defaultValue;
962
+ // If there is no '.', just return the direct property
963
+ if (!path.includes('.')) {
964
+ return obj[path] !== undefined ? obj[path] : defaultValue;
965
+ }
966
+ // Otherwise, traverse the nested properties
967
+ try {
968
+ return path.split('.').reduce((acc, part) => {
969
+ return acc && acc[part] !== undefined ? acc[part] : defaultValue;
970
+ }, obj);
971
+ }
972
+ catch {
973
+ return defaultValue;
974
+ }
975
+ }
976
+ }
977
+
978
+ /**
979
+ * Centralized URL and navigation utility helper.
980
+ * Provides common functions for URL manipulation and navigation.
981
+ */
982
+ class UrlHelper {
983
+ /**
984
+ * Extracts the home URL from current window location
985
+ * @returns Home URL path
986
+ */
987
+ static getHomeUrl() {
988
+ const pathname = window.location.pathname;
989
+ return `/${pathname.split('/')[1]}`;
990
+ }
991
+ /**
992
+ * Safely navigates to a URL if it's valid
993
+ * @param router - Angular Router instance
994
+ * @param url - URL to navigate to
995
+ * @returns Promise<boolean> - Navigation result
996
+ */
997
+ static safeNavigate(router, url) {
998
+ if (!url || typeof url !== 'string') {
999
+ return null;
1000
+ }
1001
+ try {
1002
+ return router.navigateByUrl(url);
1003
+ }
1004
+ catch (error) {
1005
+ console.warn('Navigation error:', error);
1006
+ return null;
1007
+ }
1008
+ }
1009
+ /**
1010
+ * Updates the browser URL without navigation using Location service
1011
+ * @param location - Angular Location service
1012
+ * @param baseUrl - Base URL path
1013
+ * @param queryString - Query string parameters
1014
+ */
1015
+ static updateUrl(location, baseUrl, queryString) {
1016
+ const newUrl = `${baseUrl}?${queryString}`;
1017
+ const currentUrl = window.location.pathname + window.location.search;
1018
+ if (currentUrl !== newUrl) {
1019
+ location.go(newUrl);
1020
+ }
1021
+ }
1022
+ /**
1023
+ * Builds a complete URL with query parameters
1024
+ * @param baseUrl - Base URL path
1025
+ * @param queryParams - URLSearchParams object
1026
+ * @returns Complete URL string
1027
+ */
1028
+ static buildUrl(baseUrl, queryParams) {
1029
+ const queryString = queryParams.toString();
1030
+ return queryString ? `${baseUrl}?${queryString}` : baseUrl;
1031
+ }
1032
+ /**
1033
+ * Gets the base URL without query parameters
1034
+ * @param router - Angular Router instance
1035
+ * @returns Base URL string
1036
+ */
1037
+ static getBaseUrl(router) {
1038
+ return router.url.split('?')[0];
1039
+ }
1040
+ /**
1041
+ * Checks if current URL differs from generated URL
1042
+ * @param generatedUrl - Generated URL to compare
1043
+ * @returns True if URLs are different
1044
+ */
1045
+ static hasUrlChanged(generatedUrl) {
1046
+ const currentUrl = window.location.pathname + window.location.search;
1047
+ return currentUrl !== generatedUrl;
1048
+ }
1049
+ /**
1050
+ * Extracts query parameters from a URL string
1051
+ * @param url - Full URL string
1052
+ * @returns URLSearchParams object
1053
+ */
1054
+ static extractQueryParams(url) {
1055
+ try {
1056
+ const urlObj = new URL(url);
1057
+ return new URLSearchParams(urlObj.search);
1058
+ }
1059
+ catch (error) {
1060
+ console.warn('Invalid URL for query param extraction:', url);
1061
+ return null;
1062
+ }
1063
+ }
1064
+ /**
1065
+ * Handles button click actions (URL navigation or callback execution)
1066
+ * @param router - Angular Router instance
1067
+ * @param config - Button configuration object
1068
+ * @param primaryUrlKey - Primary URL property name (default: 'btnUrl')
1069
+ * @param primaryClickKey - Primary click handler property name (default: 'btnClick')
1070
+ */
1071
+ static handleButtonClick(router, config, primaryUrlKey = 'btnUrl', primaryClickKey = 'btnClick') {
1072
+ if (!config)
1073
+ return;
1074
+ // Try callback first
1075
+ if (config[primaryClickKey] && typeof config[primaryClickKey] === 'function') {
1076
+ try {
1077
+ config[primaryClickKey]();
1078
+ }
1079
+ catch (error) {
1080
+ console.warn('Error executing button callback:', error);
1081
+ }
1082
+ }
1083
+ // Fallback to URL navigation
1084
+ else if (config[primaryUrlKey]) {
1085
+ this.safeNavigate(router, config[primaryUrlKey]);
1086
+ }
1087
+ }
1088
+ /**
1089
+ * Handles secondary button click actions
1090
+ * @param router - Angular Router instance
1091
+ * @param config - Button configuration object
1092
+ */
1093
+ static handleSecondaryButtonClick(router, config) {
1094
+ this.handleButtonClick(router, config, 'secondBtnUrl', 'secondBtnClick');
1095
+ }
1096
+ /**
1097
+ * Validates if a URL string is properly formatted
1098
+ * @param url - URL to validate
1099
+ * @returns True if URL is valid
1100
+ */
1101
+ static isValidUrl(url) {
1102
+ if (!url || typeof url !== 'string')
1103
+ return false;
1104
+ try {
1105
+ // Allow relative URLs starting with '/'
1106
+ if (url.startsWith('/'))
1107
+ return true;
1108
+ // Validate absolute URLs
1109
+ new URL(url);
1110
+ return true;
1111
+ }
1112
+ catch {
1113
+ return false;
1114
+ }
1115
+ }
1116
+ /**
1117
+ * Safely encodes URL parameters
1118
+ * @param value - Value to encode
1119
+ * @returns Encoded string
1120
+ */
1121
+ static encodeParam(value) {
1122
+ if (value === null || value === undefined)
1123
+ return '';
1124
+ return encodeURIComponent(String(value));
1125
+ }
1126
+ }
1127
+
169
1128
  class ScrollingDirective {
170
1129
  el;
171
1130
  constructor(el) {
@@ -223,25 +1182,68 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImpor
223
1182
 
224
1183
  class UserCustomizationService {
225
1184
  http;
1185
+ token = '';
226
1186
  constructor(http) {
227
1187
  this.http = http;
228
1188
  }
229
1189
  getColumnsTemplates(url, listComponent) {
1190
+ if (this.token) {
1191
+ return this.http.get(`${url}?listComponent=${listComponent}`, {
1192
+ headers: {
1193
+ 'Authorization': `Bearer ${this.token}`
1194
+ }
1195
+ });
1196
+ }
230
1197
  return this.http.get(`${url}?listComponent=${listComponent}`);
231
1198
  }
232
1199
  addColumnsTemplate(url, body) {
1200
+ if (this.token) {
1201
+ return this.http.post(`${url}`, body, {
1202
+ headers: {
1203
+ 'Authorization': `Bearer ${this.token}`
1204
+ }
1205
+ });
1206
+ }
233
1207
  return this.http.post(url, body);
234
1208
  }
235
1209
  updateColumnsTemplate(url, body) {
1210
+ if (this.token) {
1211
+ return this.http.post(`${url}`, body, {
1212
+ headers: {
1213
+ 'Authorization': `Bearer ${this.token}`
1214
+ }
1215
+ });
1216
+ }
236
1217
  return this.http.post(url, body);
237
1218
  }
238
1219
  deleteColumnsTemplate(url, body) {
1220
+ if (this.token) {
1221
+ return this.http.put(`${url}`, body, {
1222
+ headers: {
1223
+ 'Authorization': `Bearer ${this.token}`
1224
+ }
1225
+ });
1226
+ }
239
1227
  return this.http.put(url, body);
240
1228
  }
241
1229
  getSelectedColumnsTemplate(url, listComponent) {
1230
+ if (this.token) {
1231
+ return this.http.get(`${url}?listComponent=${listComponent}`, {
1232
+ headers: {
1233
+ 'Authorization': `Bearer ${this.token}`
1234
+ }
1235
+ });
1236
+ }
242
1237
  return this.http.get(`${url}?listComponent=${listComponent}`);
243
1238
  }
244
1239
  updateSelectedColumnsTemplate(url, body) {
1240
+ if (this.token) {
1241
+ return this.http.post(`${url}`, body, {
1242
+ headers: {
1243
+ 'Authorization': `Bearer ${this.token}`
1244
+ }
1245
+ });
1246
+ }
245
1247
  return this.http.post(url, body);
246
1248
  }
247
1249
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: UserCustomizationService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
@@ -563,13 +1565,16 @@ class TisColumnsBtnComponent {
563
1565
  columns;
564
1566
  skipTranslation = false;
565
1567
  customColumns;
566
- displayedColumnsChange = new EventEmitter();
567
- fromStartColumnNumberChange = new EventEmitter();
568
- fromEndColumnNumberChange = new EventEmitter();
569
1568
  selectedTemplate = {
570
1569
  id: -1,
571
- name: 'Default'
1570
+ name: 'Default',
1571
+ fromStartColumnNumber: 0,
1572
+ fromEndColumnNumber: 0,
572
1573
  };
1574
+ selectedTemplateChange = new EventEmitter();
1575
+ displayedColumnsChange = new EventEmitter();
1576
+ fromStartColumnNumberChange = new EventEmitter();
1577
+ fromEndColumnNumberChange = new EventEmitter();
573
1578
  displayedColumns = [];
574
1579
  templates = [];
575
1580
  isDeleteTemplate = false;
@@ -626,6 +1631,7 @@ class TisColumnsBtnComponent {
626
1631
  this.templates = [res, ...this.templates];
627
1632
  }
628
1633
  this.selectedTemplate = res;
1634
+ this.selectedTemplateChange.emit(this.selectedTemplate);
629
1635
  this.changeDisplayColumns();
630
1636
  }
631
1637
  });
@@ -645,6 +1651,7 @@ class TisColumnsBtnComponent {
645
1651
  if (r?.data && Object.keys(r?.data).length != 0) {
646
1652
  if (r.data?.listComponentColumnsTemplateId > 0) {
647
1653
  this.selectedTemplate = this.templates?.find((t) => t.id == r.data?.listComponentColumnsTemplateId);
1654
+ this.selectedTemplateChange.emit(this.selectedTemplate);
648
1655
  }
649
1656
  console.log("getSelectedColumnsTemplate:", this.templates, this.selectedTemplate);
650
1657
  this.changeDisplayColumns();
@@ -685,6 +1692,7 @@ class TisColumnsBtnComponent {
685
1692
  fromStartColumnNumber: 0,
686
1693
  fromEndColumnNumber: 0,
687
1694
  };
1695
+ this.selectedTemplateChange.emit(this.selectedTemplate);
688
1696
  this.changeDisplayColumns();
689
1697
  }
690
1698
  }, err => this.helper.showHttpErrorMsg(err));
@@ -707,6 +1715,7 @@ class TisColumnsBtnComponent {
707
1715
  name: 'Default'
708
1716
  };
709
1717
  }
1718
+ this.selectedTemplateChange.emit(this.selectedTemplate);
710
1719
  this.userCustomizationService.updateSelectedColumnsTemplate(this.columnCustomizationUrlConfig.updateSelectedTemplate, { id: this.selectedTemplate?.id, listComponentName: this.componentName }).subscribe((r) => {
711
1720
  this.changeDisplayColumns();
712
1721
  });
@@ -736,7 +1745,7 @@ class TisColumnsBtnComponent {
736
1745
  target.style.color = `color: var(--tis-primary, var(--mat-sys-primary, #3838a2)) !important;`;
737
1746
  }
738
1747
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: TisColumnsBtnComponent, deps: [{ token: TisHelperService }, { token: UserCustomizationService }, { token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
739
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.7", type: TisColumnsBtnComponent, isStandalone: false, selector: "tis-columns-btn", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", defaultColumns: "defaultColumns", columns: "columns", skipTranslation: "skipTranslation", customColumns: "customColumns" }, outputs: { displayedColumnsChange: "displayedColumnsChange", fromStartColumnNumberChange: "fromStartColumnNumberChange", fromEndColumnNumberChange: "fromEndColumnNumberChange" }, ngImport: i0, template: "<!-- shared.tisColumnsBtnComponent -->\n<button mat-flat-button class=\"tis-columns-btn\" style=\"background-color: var(--tis-light, #f5f5f5); color: black;\" [matMenuTriggerFor]=\"menu\">\n <mat-icon>view_week</mat-icon>\n <span style=\"display: flex; flex-direction: row;\">\n {{selectedTemplate?.name}}\n <mat-icon style=\"width: 15px; height: 15px; font-size: 20px; line-height: 16px;\">arrow_drop_down</mat-icon>\n </span>\n</button>\n<mat-menu #menu=\"matMenu\" class=\"tis-columns-btn-mat-menu\">\n <button mat-menu-item (click)=\"selectedTemplate?.id != -1 ? onSelectedTemplate(-1) : null\">\n <mat-icon>{{selectedTemplate?.id == -1 ? 'done': ''}}</mat-icon>\n Default\n </button>\n <button mat-menu-item *ngFor=\"let template of templates\" (click)=\"onSelectedTemplate(template?.id)\">\n <mat-icon>{{template?.id == selectedTemplate?.id ? 'done': ''}}</mat-icon>\n <span style=\"padding-right: 4rem;\">{{template.name}}</span>\n <mat-icon style=\"position: absolute; right: 0;\" class=\"delete-button\" (mouseover)=\"onMouseOverOut($event, `var(--tis-delete-icon, #bb333b)`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isDeleteTemplate = true\">delete</mat-icon>\n <mat-icon style=\"position: absolute; right: 2rem;\" class=\"edit-button\" (mouseover)=\"onMouseOverOut($event, `var(--tis-edit-icon, var(--mat-sys-primary, #3838a2))`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isEditTemplate = true\">edit</mat-icon>\n </button>\n <mat-divider class=\"tis-mat-divider\" style=\"margin: 0px;\"></mat-divider>\n <button mat-menu-item class=\"tis-create-columns-template-button\" style=\"color: var(--tis-primary, var(--mat-sys-primary, #3838a2));\" (click)=\"createNewTemplateDialog()\"><mat-icon style=\"color: var(--tis-primary, var(--mat-sys-primary, #3838a2));\">add</mat-icon> {{t?.tisColumnsBtnComponent?.createNewView}}</button>\n</mat-menu>", styles: [""], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i7.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: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }] });
1748
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.7", type: TisColumnsBtnComponent, isStandalone: false, selector: "tis-columns-btn", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", defaultColumns: "defaultColumns", columns: "columns", skipTranslation: "skipTranslation", customColumns: "customColumns", selectedTemplate: "selectedTemplate" }, outputs: { selectedTemplateChange: "selectedTemplateChange", displayedColumnsChange: "displayedColumnsChange", fromStartColumnNumberChange: "fromStartColumnNumberChange", fromEndColumnNumberChange: "fromEndColumnNumberChange" }, ngImport: i0, template: "<!-- shared.tisColumnsBtnComponent -->\n<button mat-flat-button class=\"tis-columns-btn\" style=\"background-color: var(--tis-light, #f5f5f5); color: black;\" [matMenuTriggerFor]=\"menu\">\n <mat-icon>view_week</mat-icon>\n <span style=\"display: flex; flex-direction: row;\">\n {{selectedTemplate?.name}}\n <mat-icon style=\"width: 15px; height: 15px; font-size: 20px; line-height: 16px;\">arrow_drop_down</mat-icon>\n </span>\n</button>\n<mat-menu #menu=\"matMenu\" class=\"tis-columns-btn-mat-menu\">\n <button mat-menu-item (click)=\"selectedTemplate?.id != -1 ? onSelectedTemplate(-1) : null\">\n <mat-icon>{{selectedTemplate?.id == -1 ? 'done': ''}}</mat-icon>\n Default\n </button>\n <button mat-menu-item *ngFor=\"let template of templates\" (click)=\"onSelectedTemplate(template?.id)\">\n <mat-icon>{{template?.id == selectedTemplate?.id ? 'done': ''}}</mat-icon>\n <span style=\"padding-right: 4rem;\">{{template.name}}</span>\n <mat-icon style=\"position: absolute; right: 0;\" class=\"delete-button\" (mouseover)=\"onMouseOverOut($event, `var(--tis-delete-icon, #bb333b)`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isDeleteTemplate = true\">delete</mat-icon>\n <mat-icon style=\"position: absolute; right: 2rem;\" class=\"edit-button\" (mouseover)=\"onMouseOverOut($event, `var(--tis-edit-icon, var(--mat-sys-primary, #3838a2))`)\" (mouseout)=\"onMouseOverOut($event, '')\" (click)=\"isEditTemplate = true\">edit</mat-icon>\n </button>\n <mat-divider class=\"tis-mat-divider\" style=\"margin: 0px;\"></mat-divider>\n <button mat-menu-item class=\"tis-create-columns-template-button\" style=\"color: var(--tis-primary, var(--mat-sys-primary, #3838a2));\" (click)=\"createNewTemplateDialog()\"><mat-icon style=\"color: var(--tis-primary, var(--mat-sys-primary, #3838a2));\">add</mat-icon> {{t?.tisColumnsBtnComponent?.createNewView}}</button>\n</mat-menu>", styles: [""], dependencies: [{ kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i7.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: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }] });
740
1749
  }
741
1750
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: TisColumnsBtnComponent, decorators: [{
742
1751
  type: Component,
@@ -759,6 +1768,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImpor
759
1768
  type: Input
760
1769
  }], customColumns: [{
761
1770
  type: Input
1771
+ }], selectedTemplate: [{
1772
+ type: Input
1773
+ }], selectedTemplateChange: [{
1774
+ type: Output
762
1775
  }], displayedColumnsChange: [{
763
1776
  type: Output
764
1777
  }], fromStartColumnNumberChange: [{
@@ -909,6 +1922,12 @@ class TisSmartTableViewerComponent {
909
1922
  onDataLoaded = new EventEmitter();
910
1923
  onSetExtraData = new EventEmitter();
911
1924
  onSetTotal = new EventEmitter();
1925
+ selectedTemplate = {
1926
+ id: -1,
1927
+ name: 'Default',
1928
+ fromStartColumnNumber: 0,
1929
+ fromEndColumnNumber: 0,
1930
+ };
912
1931
  selectedFilterValues = [];
913
1932
  finalSelectedFilterValuesToDisplay = [];
914
1933
  selectedFilterGroupedValues = [];
@@ -924,6 +1943,20 @@ class TisSmartTableViewerComponent {
924
1943
  search = '';
925
1944
  searchCtrl = new FormControl();
926
1945
  _onDestroy = new Subject();
1946
+ // Additional subscriptions that need cleanup
1947
+ _selectionSubscription;
1948
+ _handsetSubscription;
1949
+ _queryParamsSubscription;
1950
+ // Memory-efficient caching
1951
+ _columnMappingCache = new Map();
1952
+ _displayedColumnsCache = [];
1953
+ _lastColumnsCodeMappingHash = '';
1954
+ // Race condition prevention
1955
+ _currentRequestSubject = new Subject();
1956
+ // Timeout management for proper cleanup - prevent memory leaks
1957
+ timeoutManager = new TimeoutManager();
1958
+ // Computed row backgrounds for optimal performance
1959
+ computedRowBackgrounds = new Map();
927
1960
  dataSource;
928
1961
  _sort;
929
1962
  _sortSubscription;
@@ -970,6 +2003,8 @@ class TisSmartTableViewerComponent {
970
2003
  isExpandedRow = false;
971
2004
  expandedTemplate;
972
2005
  isAllExpanded = false;
2006
+ // Expansion state management - avoid direct mutation
2007
+ expandedRowIds = new Set();
973
2008
  isHandset$;
974
2009
  isMobile = false;
975
2010
  constructor(
@@ -981,82 +2016,48 @@ class TisSmartTableViewerComponent {
981
2016
  this.router = router;
982
2017
  this.location = location;
983
2018
  this.breakpointObserver = breakpointObserver;
984
- this.selection.changed.subscribe(change => {
985
- change.added.forEach(item => this.selectedIds.add(item['id']));
986
- change.removed.forEach(item => this.selectedIds.delete(item['id']));
2019
+ // Store subscription reference for proper cleanup
2020
+ this._selectionSubscription = this.selection.changed.subscribe(change => {
2021
+ change.added.forEach(item => {
2022
+ if (item && item[this.selectedRowKey] !== undefined) {
2023
+ this.selectedIds.add(item[this.selectedRowKey]);
2024
+ }
2025
+ });
2026
+ change.removed.forEach(item => {
2027
+ if (item && item[this.selectedRowKey] !== undefined) {
2028
+ this.selectedIds.delete(item[this.selectedRowKey]);
2029
+ }
2030
+ });
987
2031
  });
988
2032
  }
989
2033
  ngOnInit() {
990
2034
  this.isHandset$ = this.breakpointObserver.observe([Breakpoints.Handset])
991
- .pipe(map(result => {
992
- console.log("== result ==", result);
993
- return result.matches;
994
- }), shareReplay());
995
- this.isHandset$.subscribe(r => {
996
- console.log('IS HANDSET:', r);
2035
+ .pipe(map(result => result.matches), shareReplay());
2036
+ this._handsetSubscription = this.isHandset$.subscribe(r => {
997
2037
  this.isMobile = r;
998
2038
  });
999
2039
  this.setDefaultColumns();
1000
2040
  this.getHomeUrl();
1001
- this.route.queryParams.subscribe(qp => {
2041
+ this._queryParamsSubscription = this.route.queryParams.subscribe(qp => {
2042
+ // Initialize objects
1002
2043
  this.filterFromQueryParams = {};
1003
2044
  this.sortFromQueryParams = {};
1004
2045
  if (this.keepFilterInUrl) {
1005
- for (const key in qp) {
1006
- if (qp.hasOwnProperty(key) && qp[key] && qp[key] != '' && qp[key] != 'null' && qp[key] != 'undefined') {
1007
- let fixedKeyMatched = false;
1008
- if (key.toLowerCase() === 'pageIndex'.toLowerCase()) {
1009
- this.pageIndex = Number(qp[key]);
1010
- fixedKeyMatched = true;
1011
- }
1012
- if (key.toLowerCase() === 'pageSize'.toLowerCase()) {
1013
- this.pageSize = Number(qp[key]);
1014
- fixedKeyMatched = true;
1015
- }
1016
- if (key.toLowerCase() === 'sortBy'.toLowerCase()) {
1017
- this.sortFromQueryParams.sortBy = qp[key];
1018
- fixedKeyMatched = true;
1019
- }
1020
- if (key.toLowerCase() === 'sortOrder'.toLowerCase()) {
1021
- this.sortFromQueryParams.sortOrder = qp[key];
1022
- fixedKeyMatched = true;
1023
- }
1024
- if (key.toLowerCase() === 'search'.toLowerCase()) {
1025
- this.search = qp[key];
1026
- this.searchCtrl.patchValue(this.search);
1027
- fixedKeyMatched = true;
1028
- }
1029
- if (key.toLowerCase().includes('date') && qp[key].length == 13) { // To Check if it is a date
1030
- // this.filterFromQueryParams[key] = moment(Number(qp[key]));
1031
- this.filterFromQueryParams[key] = DateTime.fromMillis(Number(qp[key]));
1032
- fixedKeyMatched = true;
1033
- }
1034
- if (!fixedKeyMatched) {
1035
- if ((qp[key]).includes(',')) {
1036
- this.filterFromQueryParams[key] = (qp[key]).split(',');
1037
- }
1038
- else {
1039
- this.filterFromQueryParams[key] = qp[key];
1040
- }
1041
- }
1042
- // Transform Data, before patching in filter Form
1043
- let mapping = this.columnsCodeMapping.find(ccm => ccm.filterFormKey == key);
1044
- if (mapping?.transformQueryParamFn) {
1045
- this.filterFromQueryParams[key] = mapping.transformQueryParamFn(this.filterFromQueryParams[key]);
1046
- }
1047
- }
1048
- }
2046
+ const { filterParams, sortParams, pageIndex, pageSize, search } = QueryParamsHelper.processForFilters(qp, this.columnsCodeMapping);
2047
+ this.filterFromQueryParams = filterParams;
2048
+ this.sortFromQueryParams = sortParams;
2049
+ this.pageIndex = pageIndex;
2050
+ this.pageSize = pageSize;
2051
+ this.search = search;
2052
+ this.searchCtrl.patchValue(this.search);
1049
2053
  this.filterFormGroup.patchValue(this.filterFromQueryParams);
1050
- if (this.sortFromQueryParams && this.sortFromQueryParams.sortBy && this.sortFromQueryParams.sortOrder) {
2054
+ if (ValidationHelper.hasProperty(this.sortFromQueryParams, 'sortBy') &&
2055
+ ValidationHelper.hasProperty(this.sortFromQueryParams, 'sortOrder')) {
1051
2056
  this.sortObj = this.sortFromQueryParams;
1052
- console.log('[table-list-view-wrapper]: Emitting Sort Obj from QP to parent component:', this.sortFromQueryParams);
1053
2057
  this.sortObjChange.emit(this.sortObj);
1054
2058
  }
1055
2059
  }
1056
- let filterHasNonEmptyValue = Object.values(this.filterFromQueryParams).some(value => value !== null && value !== undefined && value !== '');
1057
- if (filterHasNonEmptyValue) {
1058
- this.filterApplied = true;
1059
- }
2060
+ this.filterApplied = ValidationHelper.hasNonEmptyValue(this.filterFromQueryParams);
1060
2061
  this.getList();
1061
2062
  });
1062
2063
  this.searchCtrl.valueChanges
@@ -1070,13 +2071,11 @@ class TisSmartTableViewerComponent {
1070
2071
  ngOnChanges(changes) {
1071
2072
  // console.log(`[table-list-view-wrapper]: ngOnChanges:`, changes);
1072
2073
  if (changes['defaultDisplayedColumns']) {
1073
- console.log(`[table-list-view-wrapper]: changes['defaultDisplayedColumns']:`, changes['defaultDisplayedColumns']);
1074
- this.handleDisplayedColumns();
2074
+ this.handleDisplayedColumns('defaultDisplayedColumns');
1075
2075
  }
1076
2076
  if (changes['columnsCodeMapping']) {
1077
- console.log(`[table-list-view-wrapper]: changes['columnsCodeMapping']:`, changes['columnsCodeMapping']);
1078
2077
  this.columnsCodeMapping = changes['columnsCodeMapping'].currentValue;
1079
- this.handleDisplayedColumns();
2078
+ this.handleDisplayedColumns('columnsCodeMapping');
1080
2079
  this.columns = this.columnsCodeMapping.map(c => c.name);
1081
2080
  this.autoRenderColumns = this.columnsCodeMapping.filter(c => c.hasOwnProperty('valueKey'));
1082
2081
  this.templateRenderColumns = this.columnsCodeMapping.filter(c => c.hasOwnProperty('template'));
@@ -1097,7 +2096,6 @@ class TisSmartTableViewerComponent {
1097
2096
  }
1098
2097
  if (changes['loadDataApiBaseUrl']) {
1099
2098
  if (changes['loadDataApiBaseUrl'].currentValue) {
1100
- console.log(`[table-list-view-wrapper]: Datasource changes['loadDataApiBaseUrl'].currentValue:`, changes['loadDataApiBaseUrl'].currentValue);
1101
2099
  if (this.loadingSubscription) {
1102
2100
  this.loadingSubscription.unsubscribe();
1103
2101
  }
@@ -1105,14 +2103,16 @@ class TisSmartTableViewerComponent {
1105
2103
  this.dataLengthSubscription.unsubscribe();
1106
2104
  }
1107
2105
  this.dataSource = new ApiDataSource(this.apiService);
1108
- console.log('[table-list-view-wrapper]: Datasource Initialized:', this.dataSource);
1109
2106
  this.loadingSubscription = this.dataSource.loading$.subscribe(loading => {
1110
- console.log('[table-list-view-wrapper]: dataSource loading:', loading);
1111
2107
  if (!loading) {
1112
2108
  if (this._paginator) {
1113
2109
  this._paginator.pageIndex = this.pageIndex;
1114
2110
  this._paginator.pageSize = this.pageSize;
1115
2111
  }
2112
+ // Clear background cache when new data arrives
2113
+ this.clearRowBackgroundCache();
2114
+ // Pre-compute all row backgrounds for optimal performance
2115
+ this.computeAllRowBackgrounds();
1116
2116
  this.checkAllRowsSelected();
1117
2117
  this.onDataLoaded.emit(true);
1118
2118
  this.onSetExtraData.emit(this.dataSource.extraDataSubject.value);
@@ -1124,7 +2124,6 @@ class TisSmartTableViewerComponent {
1124
2124
  }
1125
2125
  });
1126
2126
  this.dataLengthSubscription = this.dataSource.totalDataLength$.subscribe((total) => {
1127
- console.log('[table-list-view-wrapper]: dataSource total:', total);
1128
2127
  if (total !== null) {
1129
2128
  this.initialLoading = false;
1130
2129
  this.onSetTotal.emit(total);
@@ -1139,7 +2138,7 @@ class TisSmartTableViewerComponent {
1139
2138
  }
1140
2139
  this.filterFormGroupSubscription = this.filterFormGroup.valueChanges
1141
2140
  .pipe(takeUntil(this._onDestroy), distinctUntilChanged()).subscribe(val => {
1142
- this.filterHasNonEmptyValue = Object.values(val).some(value => value !== null && value !== undefined && value !== '');
2141
+ this.filterHasNonEmptyValue = ValidationHelper.hasNonEmptyValue(val);
1143
2142
  });
1144
2143
  }
1145
2144
  if (changes['selectedRows']) {
@@ -1163,12 +2162,42 @@ class TisSmartTableViewerComponent {
1163
2162
  }
1164
2163
  }
1165
2164
  ngOnDestroy() {
2165
+ // Complete the destroy subject first to trigger takeUntil operators
2166
+ this._onDestroy.next();
2167
+ this._onDestroy.complete();
2168
+ // Clean up all subscriptions
1166
2169
  this._sortSubscription?.unsubscribe();
1167
2170
  this._paginatorSubscription?.unsubscribe();
1168
2171
  this.loadingSubscription?.unsubscribe();
1169
2172
  this.dataLengthSubscription?.unsubscribe();
1170
2173
  this.filterFormGroupSubscription?.unsubscribe();
1171
- // this.dataSource.disconnect({} as CollectionViewer); // stops API calls
2174
+ // Clean up additional subscriptions
2175
+ this._selectionSubscription?.unsubscribe();
2176
+ this._handsetSubscription?.unsubscribe();
2177
+ this._queryParamsSubscription?.unsubscribe();
2178
+ // Clean up selection model and data structures using CollectionHelper
2179
+ this.selection.clear();
2180
+ CollectionHelper.clearSet(this.selectedIds);
2181
+ CollectionHelper.clearSet(this.expandedRowIds);
2182
+ // Clear arrays to free memory using CollectionHelper
2183
+ CollectionHelper.clearArray(this.selectedFilterValues);
2184
+ CollectionHelper.clearArray(this.finalSelectedFilterValuesToDisplay);
2185
+ CollectionHelper.clearArray(this.selectedFilterGroupedValues);
2186
+ CollectionHelper.clearArray(this.displayedColumns);
2187
+ // Clear caches to free memory
2188
+ CollectionHelper.clearMap(this._columnMappingCache);
2189
+ CollectionHelper.clearArray(this._displayedColumnsCache);
2190
+ this._lastColumnsCodeMappingHash = '';
2191
+ CollectionHelper.clearMap(this.computedRowBackgrounds);
2192
+ // Complete race condition prevention subject
2193
+ this._currentRequestSubject.next();
2194
+ this._currentRequestSubject.complete();
2195
+ // Clear all pending timeouts to prevent memory leaks
2196
+ this.timeoutManager.clearAll();
2197
+ // Disconnect data source to stop API calls and complete observables
2198
+ if (this.dataSource) {
2199
+ this.dataSource.disconnect({});
2200
+ }
1172
2201
  }
1173
2202
  setDefaultColumns() {
1174
2203
  if (this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
@@ -1178,22 +2207,98 @@ class TisSmartTableViewerComponent {
1178
2207
  this.defaultColumns = this.columnsCodeMapping.map(c => c.name);
1179
2208
  }
1180
2209
  }
1181
- handleDisplayedColumns() {
1182
- if (this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
1183
- const columnsSet = new Set(this.columnsCodeMapping.map(ccm => ccm.name));
1184
- this.displayedColumns = this.defaultDisplayedColumns.filter(c => columnsSet.has(c));
2210
+ handleDisplayedColumns(msg = '') {
2211
+ if (this.selectedTemplate?.id > 0 && this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
2212
+ this.displayedColumns = this.defaultDisplayedColumns.filter(c => this._columnMappingCache.has(c));
1185
2213
  }
1186
2214
  else {
1187
- this.displayedColumns = this.columnsCodeMapping.map(c => c?.columnDef || c.name);
2215
+ // Create a hash of current columns to check if cache is valid
2216
+ const columnsHash = JSON.stringify(this.columnsCodeMapping.map(c => c.name));
2217
+ // Use cache if columns haven't changed
2218
+ if (this._lastColumnsCodeMappingHash === columnsHash && this._displayedColumnsCache.length > 0) {
2219
+ this.displayedColumns = [...this._displayedColumnsCache];
2220
+ }
2221
+ else {
2222
+ // Update cache
2223
+ this.updateColumnMappingCache();
2224
+ this._lastColumnsCodeMappingHash = columnsHash;
2225
+ if (this.defaultDisplayedColumns && this.defaultDisplayedColumns.length) {
2226
+ this.displayedColumns = this.defaultDisplayedColumns.filter(c => this._columnMappingCache.has(c));
2227
+ }
2228
+ else {
2229
+ this.displayedColumns = this.columnsCodeMapping.map(c => c?.columnDef || c.name);
2230
+ }
2231
+ // Cache the result before adding selection/drag columns
2232
+ this._displayedColumnsCache = [...this.displayedColumns];
2233
+ }
1188
2234
  }
2235
+ // Add selection and drag columns (these are dynamic and shouldn't be cached)
2236
+ const finalColumns = [...this.displayedColumns];
1189
2237
  if (this.enableRowsSelection) {
1190
- this.displayedColumns = ['Select', ...this.displayedColumns];
2238
+ finalColumns.unshift('Select');
1191
2239
  }
1192
2240
  if (this.enableDragNDrop) {
1193
- this.displayedColumns = ['drag', ...this.displayedColumns];
2241
+ finalColumns.unshift('drag');
1194
2242
  }
2243
+ console.log(`=== handleDisplayedColumns :: ${msg} :: finalColumns ===`, finalColumns);
2244
+ this.displayedColumns = finalColumns;
1195
2245
  this.displayedColumnsChange.emit(this.displayedColumns);
1196
2246
  }
2247
+ updateColumnMappingCache() {
2248
+ this._columnMappingCache.clear();
2249
+ this.columnsCodeMapping.forEach(column => {
2250
+ this._columnMappingCache.set(column.name, column);
2251
+ });
2252
+ }
2253
+ // TrackBy functions for optimal rendering performance
2254
+ trackByBreadcrumb(index, breadcrumb) {
2255
+ return breadcrumb.url + breadcrumb.name || index.toString();
2256
+ }
2257
+ trackByFilterValue(index, filterValue) {
2258
+ return `${filterValue.formControlName}_${filterValue.valueKey}_${filterValue.value}`;
2259
+ }
2260
+ trackByAutoColumn(index, column) {
2261
+ return column.name + (column.serverKeyCode || '');
2262
+ }
2263
+ trackByTemplateColumn(index, column) {
2264
+ return column.name + (column.serverKeyCode || '');
2265
+ }
2266
+ trackByTableRow(index, row) {
2267
+ return row.id || row[this.selectedRowKey] || index;
2268
+ }
2269
+ // Helper method to get consistent row identifier for expansion tracking
2270
+ getRowIdentifier(row) {
2271
+ return CollectionHelper.getRowIdentifier(row, 'id', this.selectedRowKey);
2272
+ }
2273
+ // Helper method to check if a row is expanded (non-mutating)
2274
+ isRowExpanded(row) {
2275
+ if (!this.isExpansion)
2276
+ return false;
2277
+ const rowId = this.getRowIdentifier(row);
2278
+ return this.expandedRowIds.has(rowId);
2279
+ }
2280
+ // Clear background cache when data changes to ensure fresh calculations
2281
+ clearRowBackgroundCache() {
2282
+ this.computedRowBackgrounds.clear();
2283
+ }
2284
+ // Compute all row backgrounds when data changes (runs once per data load)
2285
+ computeAllRowBackgrounds() {
2286
+ if (!this.dataSource?.apiSubject.value || !this.rowsConfig.backgroundApplyFunction) {
2287
+ return;
2288
+ }
2289
+ this.computedRowBackgrounds.clear();
2290
+ this.dataSource.apiSubject.value.forEach((row) => {
2291
+ const rowId = row?.id || row?.[this.selectedRowKey] || JSON.stringify(row);
2292
+ try {
2293
+ const background = this.rowsConfig.backgroundApplyFunction(row);
2294
+ this.computedRowBackgrounds.set(rowId, background);
2295
+ }
2296
+ catch (error) {
2297
+ console.warn('Error computing row background:', error);
2298
+ this.computedRowBackgrounds.set(rowId, null);
2299
+ }
2300
+ });
2301
+ }
1197
2302
  handleSortingChanges(ch) {
1198
2303
  this.sortObj = { sortOrder: ch.direction, sortBy: this.columnsCodeMapping.find(c => c.name === ch.active)?.serverKeyCode };
1199
2304
  this.sortFromQueryParams.sortBy = this.sortObj.sortBy;
@@ -1202,90 +2307,30 @@ class TisSmartTableViewerComponent {
1202
2307
  this.getList();
1203
2308
  }
1204
2309
  getHomeUrl() {
1205
- let pathname = window.location.pathname;
1206
- // console.log("=== app-table-list-view-wrapper :: pathname ===", pathname);
1207
- this.homeUrl = `/${pathname.split('/')[1]}`;
2310
+ this.homeUrl = UrlHelper.getHomeUrl();
1208
2311
  }
1209
2312
  getNestedValue(obj, path) {
1210
- if (!path)
1211
- return null;
1212
- // If there is no '.', just return the direct property
1213
- if (!path.includes('.')) {
1214
- return obj && obj[path] ? obj[path] : null;
1215
- }
1216
- // Otherwise, traverse the nested properties
1217
- return path.split('.').reduce((acc, part) => acc && acc[part], obj);
2313
+ return CollectionHelper.getNestedProperty(obj, path);
1218
2314
  }
1219
2315
  groupByFormControlAttributes(data) {
1220
- const groups = {};
1221
- data.forEach(item => {
1222
- if (item.formControlType == 'input') {
1223
- // Do Nothing...
1224
- }
1225
- if (item.formControlType == 'checkbox') {
1226
- // Do Nothing...
1227
- }
1228
- if (item.formControlType == 'date') {
1229
- item.valueKey = DateTime.fromJSDate(item.value).toFormat('dd-MM-yyyy');
1230
- }
1231
- if (item.formControlType == 'date-time') {
1232
- item.valueKey = DateTime.fromJSDate(item.value).toFormat('dd-MM-yyyy HH:mm');
1233
- }
1234
- const key = `${item.formControlName}-${item.formControlType}`;
1235
- if (!groups[key]) {
1236
- groups[key] = {
1237
- formControlName: item.formControlName,
1238
- formControlType: item.formControlType,
1239
- arrValues: []
1240
- };
1241
- }
1242
- const isSingleValue = item.isSingleValue ?? ['input', 'radio', 'date', 'date-time', 'toggle'].includes(item.formControlType);
1243
- // Check if only the last value should be kept due to isSingleValue or duplicated value/valueKey
1244
- if (isSingleValue) {
1245
- groups[key].arrValues = [item]; // Replace with the current item
1246
- }
1247
- else {
1248
- // Check for duplicate value and valueKey in the current array
1249
- const existingIndex = groups[key].arrValues.findIndex(x => x.value === item.value && x.valueKey === item.valueKey);
1250
- if (existingIndex !== -1) {
1251
- groups[key].arrValues[existingIndex] = item; // Replace the duplicate
1252
- }
1253
- else {
1254
- groups[key].arrValues.push(item); // Add new item
1255
- }
1256
- }
1257
- });
1258
- return Object.values(groups);
2316
+ return FilterDisplayHelper.groupByFormControlAttributes(data);
1259
2317
  }
1260
2318
  updateSelectedFilterValues(values) {
1261
2319
  let currentFormControlName;
1262
2320
  if (Array.isArray(values)) {
1263
- this.selectedFilterGroupedValues = this.groupByFormControlAttributes(values);
1264
2321
  currentFormControlName = values[0]?.formControlName;
1265
2322
  }
1266
2323
  else {
1267
2324
  currentFormControlName = values?.formControlName;
1268
- this.selectedFilterGroupedValues = this.groupByFormControlAttributes([values]);
1269
2325
  }
1270
- this.selectedFilterValues = this.selectedFilterValues.filter(sfv => sfv.formControlName != currentFormControlName);
1271
- this.selectedFilterGroupedValues.forEach(gv => {
1272
- if (gv.formControlName = currentFormControlName) {
1273
- gv.arrValues.forEach(v => {
1274
- this.selectedFilterValues.push(v);
1275
- });
1276
- }
1277
- });
2326
+ const result = FilterDisplayHelper.updateSelectedFilterValues(this.selectedFilterValues, values, currentFormControlName);
2327
+ this.selectedFilterValues = result.selectedFilterValues;
2328
+ this.selectedFilterGroupedValues = result.selectedFilterGroupedValues;
1278
2329
  this.displayAfterFilterRemoved = true;
1279
- // this.filterFromQueryParams
1280
2330
  this.getFinalSelectedFilterValuesToDisplay();
1281
2331
  }
1282
2332
  getFinalSelectedFilterValuesToDisplay() {
1283
- this.finalSelectedFilterValuesToDisplay = [];
1284
- this.selectedFilterValues.forEach(sf => {
1285
- if (Object.keys(this.filterFromQueryParams).includes(sf.formControlName)) {
1286
- this.finalSelectedFilterValuesToDisplay.push(sf);
1287
- }
1288
- });
2333
+ this.finalSelectedFilterValuesToDisplay = FilterDisplayHelper.getValuesForDisplay(this.selectedFilterValues, this.filterFromQueryParams);
1289
2334
  }
1290
2335
  removeParticularFilter(f) {
1291
2336
  let val = this.filterFormGroup.get(f.formControlName)?.value;
@@ -1296,23 +2341,27 @@ class TisSmartTableViewerComponent {
1296
2341
  else {
1297
2342
  this.filterFormGroup.get(f.formControlName)?.reset();
1298
2343
  }
1299
- this.selectedFilterValues = this.selectedFilterValues.filter(sfv => !(sfv.formControlName == f.formControlName && sfv.valueKey == f.valueKey));
2344
+ this.selectedFilterValues = FilterDisplayHelper.removeFilterValue(this.selectedFilterValues, f);
1300
2345
  this.displayAfterFilterRemoved = true;
1301
- setTimeout(() => {
2346
+ this.timeoutManager.createTimeout(() => {
1302
2347
  this.filterRecords();
1303
2348
  }, 500);
1304
2349
  }
1305
2350
  filterRecords() {
1306
2351
  this.filterApplied = true;
1307
2352
  this.resetFlag = true;
1308
- setTimeout(() => {
2353
+ // Clear computed backgrounds before loading filtered data
2354
+ this.clearRowBackgroundCache();
2355
+ this.timeoutManager.createTimeout(() => {
1309
2356
  this.getList(true);
1310
2357
  this.isShowFilter = false;
1311
2358
  }, 500);
1312
2359
  }
1313
2360
  resetFilters() {
1314
2361
  this.filterApplied = false;
1315
- setTimeout(() => {
2362
+ // Clear computed backgrounds before reset
2363
+ this.clearRowBackgroundCache();
2364
+ this.timeoutManager.createTimeout(() => {
1316
2365
  this.resetFlag = true;
1317
2366
  this.filterFromQueryParams = {};
1318
2367
  this.sortFromQueryParams = {};
@@ -1322,43 +2371,15 @@ class TisSmartTableViewerComponent {
1322
2371
  }, 250);
1323
2372
  }
1324
2373
  getList(forceFromObject = false) {
2374
+ // Cancel any previous request to prevent race conditions
2375
+ this._currentRequestSubject.next();
1325
2376
  this.isAllExpanded = false;
2377
+ // Clear expansion state when loading new data to avoid stale expansion state
2378
+ CollectionHelper.clearSet(this.expandedRowIds);
1326
2379
  const filterFormData = this.filterFormGroup?.value;
1327
- let qs = new URLSearchParams();
1328
- let filter = { ...filterFormData };
1329
- if (filterFormData) {
1330
- this.filterHasNonEmptyValue = Object.values(filterFormData).some(value => value !== null && value !== undefined && value !== '');
1331
- }
1332
- else {
1333
- this.filterHasNonEmptyValue = false;
1334
- }
1335
- for (const key in filter) {
1336
- if (typeof filter[key] === 'object' && (filter[key] instanceof Date || DateTime.isDateTime(filter[key]))) {
1337
- if (filter[key] instanceof Date) {
1338
- filter[key] = DateTime.fromJSDate(filter[key]).toMillis();
1339
- }
1340
- else if (DateTime.isDateTime(filter[key])) {
1341
- filter[key] = filter[key].toMillis();
1342
- }
1343
- }
1344
- }
1345
- // Append All Filters from filter form
1346
- Object.keys(filter).forEach(key => {
1347
- if (filter[key] != null && filter[key] != '' && filter[key] != 'null' && filter[key] != 'undefined') {
1348
- if (filter[key] === '*') {
1349
- filter[key] = '';
1350
- }
1351
- qs.append(key, filter[key]);
1352
- }
1353
- });
1354
- // Append sorting conditions...
1355
- if (this.sortFromQueryParams) {
1356
- Object.keys(this.sortFromQueryParams).forEach(key => {
1357
- if (this.sortFromQueryParams[key] != null && this.sortFromQueryParams[key] != '' && this.sortFromQueryParams[key] != 'null' && this.sortFromQueryParams[key] != 'undefined') {
1358
- qs.append(key, this.sortFromQueryParams[key]);
1359
- }
1360
- });
1361
- }
2380
+ this.filterHasNonEmptyValue = ValidationHelper.hasFormData(filterFormData);
2381
+ // Build query string using helper
2382
+ const qs = QueryParamsHelper.buildQueryString(filterFormData, this.sortFromQueryParams, this.resetFlag ? 0 : this.pageIndex, this.pageSize, this.search);
1362
2383
  if (this.resetFlag) {
1363
2384
  this.pageIndex = 0;
1364
2385
  }
@@ -1366,41 +2387,44 @@ class TisSmartTableViewerComponent {
1366
2387
  this._paginator.pageIndex = this.pageIndex;
1367
2388
  this._paginator.pageSize = this.pageSize;
1368
2389
  }
1369
- qs.append("pageIndex", this.pageIndex);
1370
- qs.append("pageSize", this.pageSize);
1371
- if (this.search != '') {
1372
- qs.append('search', this.search);
1373
- }
1374
- qs = qs.toString();
1375
- let genUrl = this.router.url.split('?')[0] + '?' + qs;
1376
- let currentUrl = window.location.pathname + window.location.search;
1377
- if (currentUrl != genUrl) {
1378
- if (this.keepFilterInUrl) {
1379
- this.location.go(genUrl);
1380
- this.filterFromQueryParams = this.getQueryParams(window.location.href);
1381
- }
2390
+ // Update URL if needed
2391
+ const baseUrl = UrlHelper.getBaseUrl(this.router);
2392
+ const genUrl = UrlHelper.buildUrl(baseUrl, qs);
2393
+ if (this.keepFilterInUrl && UrlHelper.hasUrlChanged(genUrl)) {
2394
+ UrlHelper.updateUrl(this.location, baseUrl, qs.toString());
2395
+ this.filterFromQueryParams = QueryParamsHelper.parseQueryParams(window.location.href);
1382
2396
  }
1383
- else { }
1384
- this.dataSource.load(this.loadDataApiBaseUrl, this.pageIndex, this.pageSize, this.search, filter, this.sortObj);
2397
+ // Load data with race condition protection
2398
+ this.dataSource.loadWithCancellation(this.loadDataApiBaseUrl, this.pageIndex, this.pageSize, this.search, filterFormData, // Pass original form data - datasource will handle conversions
2399
+ this.sortObj, this._currentRequestSubject);
1385
2400
  this.getFinalSelectedFilterValuesToDisplay();
1386
2401
  this.resetFlag = false;
1387
2402
  }
1388
2403
  onPaginationChanges() {
1389
2404
  if (this.pageIndex != this._paginator.pageIndex) {
1390
2405
  this.pageIndex = this._paginator.pageIndex;
2406
+ // Clear computed backgrounds before loading new page data
2407
+ this.clearRowBackgroundCache();
1391
2408
  this.getList();
1392
2409
  this.pageIndexChange.emit(this.pageIndex);
1393
2410
  }
1394
2411
  if (this.pageSize != this._paginator.pageSize) {
1395
2412
  this.pageSize = this._paginator.pageSize;
2413
+ // Clear computed backgrounds before loading new page size data
2414
+ this.clearRowBackgroundCache();
1396
2415
  this.getList();
1397
2416
  this.pageSizeChange.emit(this.pageSize);
1398
2417
  setToLocalStorageWithExpiry('user_pagination_page_size', this.pageSize, 1000 * 60 * 60 * 24 * 15);
1399
2418
  }
1400
2419
  }
2420
+ onSetSelectedTemplate(data) {
2421
+ console.log("=== onSetSelectedTemplate ===", data);
2422
+ // this.selectedTemplate = data;
2423
+ }
1401
2424
  onChangeDisplayColumns(columns) {
2425
+ console.log("=== onChangeDisplayColumns ===", columns);
1402
2426
  this.defaultDisplayedColumns = columns;
1403
- this.handleDisplayedColumns();
2427
+ this.handleDisplayedColumns('onChangeDisplayColumns');
1404
2428
  }
1405
2429
  onChangeFromStartColumnNumber(columnNumber) {
1406
2430
  this.startStickyColumnCount = columnNumber;
@@ -1409,9 +2433,7 @@ class TisSmartTableViewerComponent {
1409
2433
  this.endStickyColumnCount = columnNumber;
1410
2434
  }
1411
2435
  goToUrl(url) {
1412
- if (url) {
1413
- this.router.navigateByUrl(url);
1414
- }
2436
+ UrlHelper.safeNavigate(this.router, url);
1415
2437
  }
1416
2438
  toggleSelection(status, row) {
1417
2439
  if (this.onlySingleSelection && status.checked) {
@@ -1443,28 +2465,11 @@ class TisSmartTableViewerComponent {
1443
2465
  $event.stopPropagation();
1444
2466
  }
1445
2467
  isChecked(row) {
1446
- return this.selectedIds.has(row['id']);
2468
+ return ValidationHelper.hasRowKey(row, this.selectedRowKey) &&
2469
+ this.selectedIds.has(row[this.selectedRowKey]);
1447
2470
  }
1448
2471
  getQueryParams(url) {
1449
- const urlObj = new URL(url);
1450
- const params = new URLSearchParams(urlObj.search);
1451
- const paramsObj = {};
1452
- params.forEach((value, key) => {
1453
- // Check if the parameter already exists (for handling multiple values)
1454
- if (paramsObj.hasOwnProperty(key)) {
1455
- // If it's not already an array, convert it to an array
1456
- if (!Array.isArray(paramsObj[key])) {
1457
- paramsObj[key] = [paramsObj[key]]; // Cast as string because we know it's not an array here
1458
- }
1459
- // Push the new value to the existing array
1460
- paramsObj[key].push(value); // Cast as string[] to use array methods
1461
- }
1462
- else {
1463
- // Assign the value to the key in the object
1464
- paramsObj[key] = value;
1465
- }
1466
- });
1467
- return paramsObj;
2472
+ return QueryParamsHelper.parseQueryParams(url);
1468
2473
  }
1469
2474
  isStickyStart(columnName) {
1470
2475
  const index = this.displayedColumns.indexOf(columnName);
@@ -1498,10 +2503,26 @@ class TisSmartTableViewerComponent {
1498
2503
  }
1499
2504
  }
1500
2505
  }
2506
+ // Optimized getRowBackground - simple O(1) lookup
1501
2507
  getRowBackground(row) {
1502
- return this.rowsConfig.backgroundApplyFunction
1503
- ? this.rowsConfig.backgroundApplyFunction(row)
1504
- : null;
2508
+ // Early return if no background function is provided
2509
+ if (!this.rowsConfig.backgroundApplyFunction) {
2510
+ return null;
2511
+ }
2512
+ const rowId = row?.id || row?.[this.selectedRowKey] || JSON.stringify(row);
2513
+ // If not computed yet, compute on-demand (fallback)
2514
+ if (!this.computedRowBackgrounds.has(rowId)) {
2515
+ try {
2516
+ const background = this.rowsConfig.backgroundApplyFunction(row);
2517
+ this.computedRowBackgrounds.set(rowId, background);
2518
+ return background;
2519
+ }
2520
+ catch (error) {
2521
+ console.warn('Error computing row background:', error);
2522
+ return null;
2523
+ }
2524
+ }
2525
+ return this.computedRowBackgrounds.get(rowId) || null;
1505
2526
  }
1506
2527
  drop(event) {
1507
2528
  // Ignore if the item was dropped at the same index
@@ -1521,20 +2542,10 @@ class TisSmartTableViewerComponent {
1521
2542
  this.listDataSequenceChange.emit(currentData);
1522
2543
  }
1523
2544
  handleButtonClick(config) {
1524
- if (config?.btnClick) {
1525
- config.btnClick();
1526
- }
1527
- else if (config?.btnUrl) {
1528
- this.goToUrl(config.btnUrl);
1529
- }
2545
+ UrlHelper.handleButtonClick(this.router, config);
1530
2546
  }
1531
2547
  handleSecondButtonClick(config) {
1532
- if (config?.secondBtnClick) {
1533
- config.secondBtnClick();
1534
- }
1535
- else if (config?.secondBtnUrl) {
1536
- this.goToUrl(config.secondBtnUrl);
1537
- }
2548
+ UrlHelper.handleSecondaryButtonClick(this.router, config);
1538
2549
  }
1539
2550
  setSelectedRows() {
1540
2551
  this.selection.clear();
@@ -1554,29 +2565,40 @@ class TisSmartTableViewerComponent {
1554
2565
  }
1555
2566
  /** Toggles the expanded state of an element. */
1556
2567
  toggleExpand(element) {
1557
- if (this.isExpansion) {
1558
- if (!element?.expanded) {
1559
- element.expanded = true;
1560
- }
1561
- else {
1562
- element.expanded = false;
1563
- }
2568
+ if (!this.isExpansion || !element) {
2569
+ return;
2570
+ }
2571
+ const rowId = this.getRowIdentifier(element);
2572
+ if (this.expandedRowIds.has(rowId)) {
2573
+ this.expandedRowIds.delete(rowId);
2574
+ }
2575
+ else {
2576
+ this.expandedRowIds.add(rowId);
1564
2577
  }
1565
2578
  }
1566
2579
  expandAllRow() {
1567
- if (this.isExpansion) {
1568
- this.isAllExpanded = !this.isAllExpanded;
2580
+ if (!this.isExpansion || !this.dataSource?.apiSubject?.value) {
2581
+ return;
2582
+ }
2583
+ this.isAllExpanded = !this.isAllExpanded;
2584
+ if (this.isAllExpanded) {
2585
+ // Add all row IDs to expanded set
1569
2586
  this.dataSource.apiSubject.value.forEach(row => {
1570
- row.expanded = this.isAllExpanded;
2587
+ const rowId = this.getRowIdentifier(row);
2588
+ this.expandedRowIds.add(rowId);
1571
2589
  });
1572
2590
  }
2591
+ else {
2592
+ // Clear all expanded rows
2593
+ this.expandedRowIds.clear();
2594
+ }
1573
2595
  }
1574
2596
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: TisSmartTableViewerComponent, deps: [{ token: i1$1.MatDialog }, { token: ApiService }, { token: i3$1.ActivatedRoute }, { token: i3$1.Router }, { token: i4.Location }, { token: i5.BreakpointObserver }], target: i0.ɵɵFactoryTarget.Component });
1575
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: TisSmartTableViewerComponent, isStandalone: false, selector: "tis-smart-table-viewer", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", mainTitle: "mainTitle", searchPlaceholder: "searchPlaceholder", breadcrumbs: "breadcrumbs", hideHeader: "hideHeader", hideTableHeader: "hideTableHeader", hidePaginator: "hidePaginator", keepFilterInUrl: "keepFilterInUrl", disableBorderedView: "disableBorderedView", displayColumnsSelectionButton: "displayColumnsSelectionButton", loadDataApiBaseUrl: "loadDataApiBaseUrl", startStickyColumnCount: "startStickyColumnCount", endStickyColumnCount: "endStickyColumnCount", loaderPosition: "loaderPosition", dataNotFoundConfig: "dataNotFoundConfig", showFilterButtonSection: "showFilterButtonSection", columnsCodeMapping: "columnsCodeMapping", defaultDisplayedColumns: "defaultDisplayedColumns", defaultSortObj: "defaultSortObj", loadingSpinnerDiameter: "loadingSpinnerDiameter", pageSizeOptions: "pageSizeOptions", pageSize: "pageSize", useGlobalPageSize: "useGlobalPageSize", pageIndex: "pageIndex", filterFormGroup: "filterFormGroup", rowsConfig: "rowsConfig", enableRowsSelection: "enableRowsSelection", enableAllRowsSelection: "enableAllRowsSelection", onlySingleSelection: "onlySingleSelection", selectedRowIds: "selectedRowIds", selectedRowKey: "selectedRowKey", selectedRows: "selectedRows", enableDragNDrop: "enableDragNDrop", isExpansion: "isExpansion", isExpandedRow: "isExpandedRow", expandedTemplate: "expandedTemplate" }, outputs: { displayedColumnsChange: "displayedColumnsChange", sortObjChange: "sortObjChange", pageSizeChange: "pageSizeChange", pageIndexChange: "pageIndexChange", onDataLoaded: "onDataLoaded", onSetExtraData: "onSetExtraData", onSetTotal: "onSetTotal", selectedRowsChange: "selectedRowsChange", allRowsSelectedChange: "allRowsSelectedChange", listDataSequenceChange: "listDataSequenceChange" }, providers: [CdkColumnDef], viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section [class.tis-page]=\"!hideHeader\">\n <div class=\"tis-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"tis-breadcrumb\">\n <ol class=\"tis-breadcrumb\">\n <li class=\"tis-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track breadcrumb) {\n <li class=\"tis-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"tis-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"tis-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"tis-page-body\">\n <div class=\"tis-page-body-content\">\n\n @if(initialLoading){\n <div class=\"tis-d-flex tis-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"tis-table-container\">\n @if(!hideTableHeader){\n <div class=\"tis-table-container-header\">\n <ul class=\"tis-inline-group\">\n <li class=\"tis-inline-group-item\">\n <tis-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></tis-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"tis-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if(!isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track v) {\n @if (v) {\n <span class=\"tis-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons tis-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if(isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"tis-table-container-body\">\n <div class=\"tis-table-wrapper\" [appScrolling]=\"true\">\n\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"tis-table\" [class.tis-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row)\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track column.serverKeyCode; let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDate) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTime) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTimeWithSeconds) : ''}}\n </p>\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : '1.4-4') : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey))?.toFixed(2) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track column.serverKeyCode; let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"tis-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"element.expanded ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"tis-element-detail-wrapper\" [class.tis-element-detail-wrapper-expanded]=\"element.expanded\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"tis-detail-row\"></tr>\n </table>\n <!--Table End-->\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"tis-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n <p class=\"tis-p\">{{dataNotFoundConfig.desc}}</p>\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.tis-detail-row{height:0!important}.tis-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.tis-element-detail-wrapper-expanded{max-height:500px}.tis-table-bordered{border-collapse:collapse;width:100%}.tis-table-bordered th,.tis-table-bordered td{border-left:1px solid #e0e0e0}.tis-table-bordered th:first-child,.tis-table-bordered td:first-child{border-left:0px solid #e0e0e0}.tis-table-bordered .bg-unset{background-color:unset!important}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i6.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: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i10.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i10$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i12$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: i13$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i13$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i13$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i13$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i13$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i13$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i13$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i13$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i13$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i13$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i13$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i15.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i15.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "directive", type: i13.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i13.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i13.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: ScrollingDirective, selector: "[appScrolling]", inputs: ["appScrolling"] }, { kind: "component", type: TisColumnsBtnComponent, selector: "tis-columns-btn", inputs: ["columnCustomizationUrlConfig", "t", "componentName", "defaultColumns", "columns", "skipTranslation", "customColumns"], outputs: ["displayedColumnsChange", "fromStartColumnNumberChange", "fromEndColumnNumberChange"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.DecimalPipe, name: "number" }, { kind: "pipe", type: TisDatePipe, name: "tisDate" }, { kind: "pipe", type: TisDateTimePipe, name: "tisDateTime" }, { kind: "pipe", type: TisDateTimeWithSecondsPipe, name: "tisDateTimeWithSeconds" }] });
2597
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.7", type: TisSmartTableViewerComponent, isStandalone: false, selector: "tis-smart-table-viewer", inputs: { columnCustomizationUrlConfig: "columnCustomizationUrlConfig", t: "t", componentName: "componentName", mainTitle: "mainTitle", searchPlaceholder: "searchPlaceholder", breadcrumbs: "breadcrumbs", hideHeader: "hideHeader", hideTableHeader: "hideTableHeader", hidePaginator: "hidePaginator", keepFilterInUrl: "keepFilterInUrl", disableBorderedView: "disableBorderedView", displayColumnsSelectionButton: "displayColumnsSelectionButton", loadDataApiBaseUrl: "loadDataApiBaseUrl", startStickyColumnCount: "startStickyColumnCount", endStickyColumnCount: "endStickyColumnCount", loaderPosition: "loaderPosition", dataNotFoundConfig: "dataNotFoundConfig", showFilterButtonSection: "showFilterButtonSection", columnsCodeMapping: "columnsCodeMapping", defaultDisplayedColumns: "defaultDisplayedColumns", defaultSortObj: "defaultSortObj", loadingSpinnerDiameter: "loadingSpinnerDiameter", pageSizeOptions: "pageSizeOptions", pageSize: "pageSize", useGlobalPageSize: "useGlobalPageSize", pageIndex: "pageIndex", filterFormGroup: "filterFormGroup", rowsConfig: "rowsConfig", enableRowsSelection: "enableRowsSelection", enableAllRowsSelection: "enableAllRowsSelection", onlySingleSelection: "onlySingleSelection", selectedRowIds: "selectedRowIds", selectedRowKey: "selectedRowKey", selectedRows: "selectedRows", enableDragNDrop: "enableDragNDrop", isExpansion: "isExpansion", isExpandedRow: "isExpandedRow", expandedTemplate: "expandedTemplate" }, outputs: { displayedColumnsChange: "displayedColumnsChange", sortObjChange: "sortObjChange", pageSizeChange: "pageSizeChange", pageIndexChange: "pageIndexChange", onDataLoaded: "onDataLoaded", onSetExtraData: "onSetExtraData", onSetTotal: "onSetTotal", selectedRowsChange: "selectedRowsChange", allRowsSelectedChange: "allRowsSelectedChange", listDataSequenceChange: "listDataSequenceChange" }, providers: [CdkColumnDef], viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section [class.tis-page]=\"!hideHeader\">\n <div class=\"tis-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"tis-breadcrumb\">\n <ol class=\"tis-breadcrumb\">\n <li class=\"tis-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track trackByBreadcrumb($index, breadcrumb)) {\n <li class=\"tis-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"tis-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"tis-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"tis-page-body\">\n <div class=\"tis-page-body-content\">\n\n @if(initialLoading){\n <div class=\"tis-d-flex tis-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"tis-table-container\">\n @if(!hideTableHeader){\n <div class=\"tis-table-container-header\">\n <ul class=\"tis-inline-group\">\n <li class=\"tis-inline-group-item\">\n <tis-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [(selectedTemplate)]=\"selectedTemplate\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (selectedTemplateChange)=\"onSetSelectedTemplate($event)\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></tis-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"tis-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if(!isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track trackByFilterValue($index, v)) {\n @if (v) {\n <span class=\"tis-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons tis-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if(isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"tis-table-container-body\">\n <div class=\"tis-table-wrapper\" [appScrolling]=\"true\">\n\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"tis-table\" [class.tis-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row)\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track trackByAutoColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDate) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTime) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTimeWithSeconds) : ''}}\n </p>\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : '1.4-4') : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey))?.toFixed(2) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track trackByTemplateColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"tis-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"element.expanded ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"tis-element-detail-wrapper\" [class.tis-element-detail-wrapper-expanded]=\"element.expanded\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"tis-detail-row\"></tr>\n </table>\n <!--Table End-->\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"tis-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n <p class=\"tis-p\">{{dataNotFoundConfig.desc}}</p>\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.tis-detail-row{height:0!important}.tis-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.tis-element-detail-wrapper-expanded{max-height:500px}.tis-table-bordered{border-collapse:collapse;width:100%}.tis-table-bordered th,.tis-table-bordered td{border-left:1px solid #e0e0e0}.tis-table-bordered th:first-child,.tis-table-bordered td:first-child{border-left:0px solid #e0e0e0}.tis-table-bordered .bg-unset{background-color:unset!important}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i4.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i6.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: i6.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i6.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i8.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i8.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i8.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i10.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i10$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: i4$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: i12$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: i13$1.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i13$1.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i13$1.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i13$1.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i13$1.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i13$1.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i13$1.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i13$1.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i13$1.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i13$1.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "directive", type: i13$1.MatNoDataRow, selector: "ng-template[matNoDataRow]" }, { kind: "component", type: i12.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: i15.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i15.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "directive", type: i13.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i13.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i13.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: ScrollingDirective, selector: "[appScrolling]", inputs: ["appScrolling"] }, { kind: "component", type: TisColumnsBtnComponent, selector: "tis-columns-btn", inputs: ["columnCustomizationUrlConfig", "t", "componentName", "defaultColumns", "columns", "skipTranslation", "customColumns", "selectedTemplate"], outputs: ["selectedTemplateChange", "displayedColumnsChange", "fromStartColumnNumberChange", "fromEndColumnNumberChange"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.DecimalPipe, name: "number" }, { kind: "pipe", type: TisDatePipe, name: "tisDate" }, { kind: "pipe", type: TisDateTimePipe, name: "tisDateTime" }, { kind: "pipe", type: TisDateTimeWithSecondsPipe, name: "tisDateTimeWithSeconds" }] });
1576
2598
  }
1577
2599
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImport: i0, type: TisSmartTableViewerComponent, decorators: [{
1578
2600
  type: Component,
1579
- args: [{ selector: 'tis-smart-table-viewer', standalone: false, providers: [CdkColumnDef], template: "<section [class.tis-page]=\"!hideHeader\">\n <div class=\"tis-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"tis-breadcrumb\">\n <ol class=\"tis-breadcrumb\">\n <li class=\"tis-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track breadcrumb) {\n <li class=\"tis-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"tis-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"tis-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"tis-page-body\">\n <div class=\"tis-page-body-content\">\n\n @if(initialLoading){\n <div class=\"tis-d-flex tis-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"tis-table-container\">\n @if(!hideTableHeader){\n <div class=\"tis-table-container-header\">\n <ul class=\"tis-inline-group\">\n <li class=\"tis-inline-group-item\">\n <tis-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></tis-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"tis-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if(!isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track v) {\n @if (v) {\n <span class=\"tis-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons tis-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if(isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"tis-table-container-body\">\n <div class=\"tis-table-wrapper\" [appScrolling]=\"true\">\n\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"tis-table\" [class.tis-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row)\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track column.serverKeyCode; let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDate) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTime) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTimeWithSeconds) : ''}}\n </p>\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : '1.4-4') : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey))?.toFixed(2) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track column.serverKeyCode; let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"tis-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"element.expanded ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"tis-element-detail-wrapper\" [class.tis-element-detail-wrapper-expanded]=\"element.expanded\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"tis-detail-row\"></tr>\n </table>\n <!--Table End-->\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"tis-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n <p class=\"tis-p\">{{dataNotFoundConfig.desc}}</p>\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.tis-detail-row{height:0!important}.tis-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.tis-element-detail-wrapper-expanded{max-height:500px}.tis-table-bordered{border-collapse:collapse;width:100%}.tis-table-bordered th,.tis-table-bordered td{border-left:1px solid #e0e0e0}.tis-table-bordered th:first-child,.tis-table-bordered td:first-child{border-left:0px solid #e0e0e0}.tis-table-bordered .bg-unset{background-color:unset!important}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"] }]
2601
+ args: [{ selector: 'tis-smart-table-viewer', standalone: false, providers: [CdkColumnDef], template: "<section [class.tis-page]=\"!hideHeader\">\n <div class=\"tis-page-header\" *ngIf=\"!hideHeader\">\n <nav aria-label=\"tis-breadcrumb\">\n <ol class=\"tis-breadcrumb\">\n <li class=\"tis-breadcrumb-item\"><a href=\"javascript:;\" [routerLink]=\"homeUrl\">{{t?.home}}</a></li>\n @for(breadcrumb of breadcrumbs; track trackByBreadcrumb($index, breadcrumb)) {\n <li class=\"tis-breadcrumb-item\" *ngIf=\"breadcrumb?.url\">\n <a href=\"javascript:;\" (click)=\"goToUrl(breadcrumb.url)\">{{breadcrumb?.name}}</a>\n </li>\n }\n <li class=\"tis-breadcrumb-item active\">\n {{mainTitle}}\n </li>\n </ol>\n </nav>\n <ng-content select=\"[slot='top-buttons-section']\"></ng-content>\n </div>\n <h1 class=\"tis-page-title\" *ngIf=\"!hideHeader\">{{mainTitle}}</h1>\n <div class=\"tis-page-body\">\n <div class=\"tis-page-body-content\">\n\n @if(initialLoading){\n <div class=\"tis-d-flex tis-justify-content-center pb-2 pt-7\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"60\"></mat-progress-spinner>\n </div>\n } @else {\n\n @if ((dataSource?.totalDataLength$ | async) || (dataSource?.loading$ | async) || search ||\n filterHasNonEmptyValue || showFilterButtonSection || displayAfterFilterRemoved) {\n <div class=\"tis-table-container\">\n @if(!hideTableHeader){\n <div class=\"tis-table-container-header\">\n <ul class=\"tis-inline-group\">\n <li class=\"tis-inline-group-item\">\n <tis-columns-btn [columnCustomizationUrlConfig]=\"columnCustomizationUrlConfig\" [t]=\"t\"\n [componentName]=\"componentName\" [(selectedTemplate)]=\"selectedTemplate\" [defaultColumns]=\"defaultColumns\" [columns]=\"columns\"\n (selectedTemplateChange)=\"onSetSelectedTemplate($event)\"\n (displayedColumnsChange)=\"onChangeDisplayColumns($event)\"\n (fromStartColumnNumberChange)=\"onChangeFromStartColumnNumber($event)\"\n (fromEndColumnNumberChange)=\"onChangeFromEndColumnNumber($event)\"></tis-columns-btn>\n </li>\n <ng-content select=\"[slot='filter-button-section']\"></ng-content>\n </ul>\n <div class=\"flex items-center\">\n <ul class=\"tis-inline-group\">\n <ng-content select=\"[slot='filter-right-button-section']\"></ng-content>\n </ul>\n @if(!isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field ml-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n </div>\n </div>\n }\n\n @if (filterFormGroup) {\n\n <ng-content select=\"[slot='filter-form-section']\"></ng-content>\n\n @if(finalSelectedFilterValuesToDisplay.length && filterApplied) {\n <div class=\"flex gap-3 mb-3 filter-applied-section md-hide-scrollbar\">\n @for(v of finalSelectedFilterValuesToDisplay; track trackByFilterValue($index, v)) {\n @if (v) {\n <span class=\"tis-filter-badge\" style=\"white-space: nowrap;\">\n @if(v.labelKey && v.labelKey != '' && (v.valueKey || v.value)) {\n <span class=\"font-semibold\"> {{v.labelKey }} </span>\n }\n @if(v.valueKey) {\n {{v.valueKey }}\n } @else {\n {{v.value }}\n }\n <span class=\"material-icons tis-curser-pointer\"\n (click)=\"removeParticularFilter(v)\">cancel</span>\n </span>\n }\n }\n </div>\n }\n }\n\n @if(isMobile && searchPlaceholder && searchPlaceholder != ''){\n <mat-form-field\n class=\"custom-mat-form-field-mb-0 search-mat-form-field mb-3 tis-table-search-field\"\n appearance=\"outline\">\n <span class=\"material-icons\" matPrefix>search</span>\n <input matInput [formControl]=\"searchCtrl\" [placeholder]=\"searchPlaceholder\">\n <span class=\"material-icons mr-2 tis-curser-pointer\" matSuffix\n (click)=\"searchCtrl.setValue('')\"\n *ngIf=\"searchCtrl.value && searchCtrl.value != ''\">close</span>\n </mat-form-field>\n }\n\n \n @if(loaderPosition == 'top'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n <div class=\"tis-table-container-body\">\n <div class=\"tis-table-wrapper\" [appScrolling]=\"true\">\n\n <!--Table Here-->\n <table mat-table matSort [dataSource]=\"dataSource\" class=\"tis-table\" [class.tis-table-bordered]=\"disableBorderedView == false\" cdkDropList (cdkDropListDropped)=\"drop($event)\" [cdkDropListLockAxis]=\"'y'\" multiTemplateDataRows>\n\n @if (enableRowsSelection) {\n <ng-container matColumnDef=\"Select\">\n <th mat-header-cell *matHeaderCellDef>\n @if (enableAllRowsSelection) {\n <mat-checkbox color=\"primary\" (change)=\"$event ? toggleAllRows() : null\"\n [checked]=\"isAllRowsSelected\"\n [indeterminate]=\"selection.hasValue() && !isAllRowsSelected\">\n </mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox color=\"primary\" (click)=\"stopPropagation($event)\" (change)=\"$event ? toggleSelection($event, row) : null\" [checked]=\"isChecked(row)\"></mat-checkbox>\n </td>\n </ng-container>\n }\n\n @for(column of autoRenderColumns; track trackByAutoColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"i > (autoRenderColumns?.length - endStickyColumnCount)\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px;\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell mat-sort-header *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n \n\n @if(column.type == 'date'){\n <td mat-cell *matCellDef=\"let element\" class=\"1al-{{column.align}} 1ty-{{column.type}}\" >\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDate) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTime) : ''}}\n </p>\n </td>\n } @else if(column.type == 'date-time-with-seconds'){\n <td mat-cell *matCellDef=\"let element\" class=\"2al-{{column.align}} 2ty-{{column.type}}\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | tisDateTimeWithSeconds) : ''}}\n </p>\n </td>\n } @else {\n <td mat-cell *matCellDef=\"let element\" class=\"3al-{{column.align}} 3ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <p [class.tis-a]=\"column.clickFn\" (click)=\"column?.clickFn?.(element, $event)\">\n @if (column.type == 'quantity') {\n {{ column.valueKey ? (getNestedValue(element, column.valueKey) | number : '1.4-4') : '-' }}\n } @else if (column.type == 'money') {\n {{ column.valueKey && (getNestedValue(element, column.valueKey))?.toFixed(2) }}\n } @else {\n {{ column.valueKey && getNestedValue(element, column.valueKey) }}\n }\n </p>\n </td>\n }\n </ng-container>\n\n }\n\n\n @for(column of templateRenderColumns; track trackByTemplateColumn($index, column); let i = $index; let l = $last){\n <!-- [sticky]=\"i < startStickyColumnCount\" [stickyEnd]=\"l\" -->\n <ng-container [matColumnDef]=\"column?.columnDef || column.name\" [sticky]=\"isStickyStart(column?.columnDef || column.name)\" [stickyEnd]=\"isStickyEnd(column?.columnDef || column.name)\">\n @if(column.type == 'expand') {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n <div style=\"display: flex; align-items: center; gap: 5px; cursor: pointer;\" (click)=\"expandAllRow()\">\n <span>{{ column?.columnName ? column?.columnName : t[column.name] }}</span>\n <mat-icon *ngIf=\"!isAllExpanded\">expand_more</mat-icon>\n <mat-icon *ngIf=\"isAllExpanded\">expand_less</mat-icon>\n </div>\n </th>\n }\n @else if(column.sort) {\n <th mat-header-cell *matHeaderCellDef mat-sort-header [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n @else {\n <th mat-header-cell *matHeaderCellDef [ngClass]=\"getColumnClasses(column)\">\n {{ column?.columnName ? column?.columnName : t[column.name] }}\n </th>\n }\n <td mat-cell *matCellDef=\"let element\" class=\"4al-{{column.align}} 4ty-{{column.type}}\" [ngClass]=\"getColumnClasses(column)\">\n <ng-container *ngIf=\"column.template as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colDef: column, colData: element }\"></ng-container>\n </ng-container>\n </td>\n </ng-container>\n }\n\n <!--Drag Column Def Start-->\n <ng-container [matColumnDef]=\"'drag'\" >\n <th mat-header-cell *matHeaderCellDef>\n --\n </th>\n <td mat-cell *matCellDef=\"let element\" class=\"5al-drag 5ty-drag\">\n <mat-icon cdkDragHandle class=\"tis-curser-pointer\" style=\"color: rgba(0, 0, 0, 0.54); font-size: 19px; width: 19px; height: 19px;\">drag_indicator</mat-icon>\n </td>\n </ng-container>\n <!--Drag Column Def End-->\n\n <!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\" [style.border-bottom-width]=\"element.expanded ? '1px' : '0px'\" style=\"padding: 0px !important;\">\n <div class=\"tis-element-detail-wrapper\" [class.tis-element-detail-wrapper-expanded]=\"element.expanded\">\n <ng-container *ngIf=\"expandedTemplate as template\">\n <ng-container *ngTemplateOutlet=\"template; context: { colData: element }\"></ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n\n\n <tr class=\"mat-row\" *matNoDataRow>\n <td class=\"mat-cell\" [attr.colspan]=\"displayedColumns.length\">\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n </div>\n </td>\n </tr>\n\n <!-- Apply Drag and Drop to tbody -->\n @if(enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\" cdkDrag></tr>\n }\n\n @if(!enableDragNDrop) {\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\" [ngStyle]=\"{'background-color': getRowBackground(row) || 'inherit'}\" [class.tis-curser-pointer]=\"isExpandedRow\" (click)=\"(isExpansion && isExpandedRow) ? toggleExpand(row) : null\"></tr>\n } \n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"tis-detail-row\"></tr>\n </table>\n <!--Table End-->\n\n </div>\n @if(loaderPosition == 'bottom'){\n @if(dataSource?.loading$ | async){\n <div class=\"tis-d-flex tis-justify-content-center py-2\">\n <mat-progress-spinner color=\"primary\" mode=\"indeterminate\" [diameter]=\"loadingSpinnerDiameter\"></mat-progress-spinner>\n </div>\n }\n }\n @if (!hidePaginator) {\n <div class=\"tis-table-paginator\">\n <mat-paginator [length]=\"dataSource?.totalDataLength?.value\" [pageSize]=\"pageSize\"\n [pageSizeOptions]=\"pageSizeOptions\" showFirstLastButtons></mat-paginator>\n </div>\n }\n </div>\n </div>\n } @else {\n\n @if(dataNotFoundConfig) {\n <div class=\"tis-data-not-found\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"130\" height=\"126.89\" viewBox=\"0 0 647.63626 632.17383\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" role=\"img\" artist=\"Katerina Limpitsouni\" source=\"https://undraw.co/\">\n <path d=\"M687.3279,276.08691H512.81813a15.01828,15.01828,0,0,0-15,15v387.85l-2,.61005-42.81006,13.11a8.00676,8.00676,0,0,1-9.98974-5.31L315.678,271.39691a8.00313,8.00313,0,0,1,5.31006-9.99l65.97022-20.2,191.25-58.54,65.96972-20.2a7.98927,7.98927,0,0,1,9.99024,5.3l32.5498,106.32Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#f2f2f2\"/>\n <path d=\"M725.408,274.08691l-39.23-128.14a16.99368,16.99368,0,0,0-21.23-11.28l-92.75,28.39L380.95827,221.60693l-92.75,28.4a17.0152,17.0152,0,0,0-11.28028,21.23l134.08008,437.93a17.02661,17.02661,0,0,0,16.26026,12.03,16.78926,16.78926,0,0,0,4.96972-.75l63.58008-19.46,2-.62v-2.09l-2,.61-64.16992,19.65a15.01489,15.01489,0,0,1-18.73-9.95l-134.06983-437.94a14.97935,14.97935,0,0,1,9.94971-18.73l92.75-28.4,191.24024-58.54,92.75-28.4a15.15551,15.15551,0,0,1,4.40966-.66,15.01461,15.01461,0,0,1,14.32032,10.61l39.0498,127.56.62012,2h2.08008Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M398.86279,261.73389a9.0157,9.0157,0,0,1-8.61133-6.3667l-12.88037-42.07178a8.99884,8.99884,0,0,1,5.9712-11.24023l175.939-53.86377a9.00867,9.00867,0,0,1,11.24072,5.9707l12.88037,42.07227a9.01029,9.01029,0,0,1-5.9707,11.24072L401.49219,261.33887A8.976,8.976,0,0,1,398.86279,261.73389Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"190.15351\" cy=\"24.95465\" r=\"12.66462\" fill=\"#fff\"/>\n <path d=\"M878.81836,716.08691h-338a8.50981,8.50981,0,0,1-8.5-8.5v-405a8.50951,8.50951,0,0,1,8.5-8.5h338a8.50982,8.50982,0,0,1,8.5,8.5v405A8.51013,8.51013,0,0,1,878.81836,716.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#e6e6e6\"/>\n <path d=\"M723.31813,274.08691h-210.5a17.02411,17.02411,0,0,0-17,17v407.8l2-.61v-407.19a15.01828,15.01828,0,0,1,15-15H723.93825Zm183.5,0h-394a17.02411,17.02411,0,0,0-17,17v458a17.0241,17.0241,0,0,0,17,17h394a17.0241,17.0241,0,0,0,17-17v-458A17.02411,17.02411,0,0,0,906.81813,274.08691Zm15,475a15.01828,15.01828,0,0,1-15,15h-394a15.01828,15.01828,0,0,1-15-15v-458a15.01828,15.01828,0,0,1,15-15h394a15.01828,15.01828,0,0,1,15,15Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"#3f3d56\"/>\n <path d=\"M801.81836,318.08691h-184a9.01015,9.01015,0,0,1-9-9v-44a9.01016,9.01016,0,0,1,9-9h184a9.01016,9.01016,0,0,1,9,9v44A9.01015,9.01015,0,0,1,801.81836,318.08691Z\" transform=\"translate(-276.18187 -133.91309)\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"20\" fill=\"var(--tis-primary, var(--mat-sys-primary, #3838a2))\"/>\n <circle cx=\"433.63626\" cy=\"105.17383\" r=\"12.18187\" fill=\"#fff\"/>\n </svg>\n <h5 class=\"tis-h5\">{{dataNotFoundConfig.title}}</h5>\n <p class=\"tis-p\">{{dataNotFoundConfig.desc}}</p>\n @if((dataNotFoundConfig.btnUrl || dataNotFoundConfig?.btnClick) && dataNotFoundConfig.btnText) {\n <button mat-flat-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.btnText}}\n </button>\n }\n @if((dataNotFoundConfig.secondBtnUrl || dataNotFoundConfig?.secondBtnClick) && dataNotFoundConfig.secondBtnText) {\n <button mat-stroked-button color=\"primary\" class=\"tis-text-upper\"\n (click)=\"handleSecondButtonClick(dataNotFoundConfig)\">\n <mat-icon>add</mat-icon>\n {{dataNotFoundConfig.secondBtnText}}\n </button>\n }\n </div>\n }\n\n }\n\n }\n\n </div>\n </div>\n</section>", styles: ["::ng-deep .sub-main-content{border:0px solid #f00;margin-top:56px;height:calc(100% - 56px);padding:15px;overflow:auto}.header-title{margin-top:8px;padding:7px 10px;color:#969a9c}.header-title h3{font-size:20px!important;font-weight:700}.header-menu{border:0px solid red;background:#fff;margin-top:1px;margin-bottom:0}.w-100{width:100%}.mat-mdc-table-sticky-border-elem-right{border-left:1px solid #e0e0e087}.mat-mdc-table-sticky-border-elem-left{border-right:1px solid #e0e0e087}.search-mat-form-field{width:100%}.filter-applied-section{overflow:auto}.tis-detail-row{height:0!important}.tis-element-detail-wrapper{overflow:hidden;max-height:0;transition:max-height 225ms ease}.tis-element-detail-wrapper-expanded{max-height:500px}.tis-table-bordered{border-collapse:collapse;width:100%}.tis-table-bordered th,.tis-table-bordered td{border-left:1px solid #e0e0e0}.tis-table-bordered th:first-child,.tis-table-bordered td:first-child{border-left:0px solid #e0e0e0}.tis-table-bordered .bg-unset{background-color:unset!important}@media (max-width: 575.98px){.search-mat-form-field{width:100%!important}}@media (min-width: 576px) and (max-width: 767.98px){.search-mat-form-field{width:100%!important}}\n"] }]
1580
2602
  }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: ApiService }, { type: i3$1.ActivatedRoute }, { type: i3$1.Router }, { type: i4.Location }, { type: i5.BreakpointObserver }], propDecorators: { columnCustomizationUrlConfig: [{
1581
2603
  type: Input,
1582
2604
  args: [{ required: true }]
@@ -1802,7 +2824,6 @@ class TisSmartTableViewerModule {
1802
2824
  Money, TisSmartTableViewerComponent,
1803
2825
  TisColumnsBtnComponent,
1804
2826
  CreateColumnsTemplateComponent,
1805
- TisSmartTableViewerComponent,
1806
2827
  TisSmartTableErrorDialogComponent,
1807
2828
  TisSmartTableConfirmationDialogComponent], imports: [CommonModule,
1808
2829
  FormsModule,
@@ -1837,7 +2858,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.7", ngImpor
1837
2858
  TisSmartTableViewerComponent,
1838
2859
  TisColumnsBtnComponent,
1839
2860
  CreateColumnsTemplateComponent,
1840
- TisSmartTableViewerComponent,
1841
2861
  TisSmartTableErrorDialogComponent,
1842
2862
  TisSmartTableConfirmationDialogComponent
1843
2863
  ],