@es.framework/ng.ui.core 2.0.61 → 2.0.62
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.
- package/fesm2022/es.framework-ng.ui.core-generic-crud-table.mjs +3 -3
- package/fesm2022/es.framework-ng.ui.core-generic-crud-table.mjs.map +1 -1
- package/fesm2022/es.framework-ng.ui.core-generic-report-tabs.mjs +1 -0
- package/fesm2022/es.framework-ng.ui.core-generic-report-tabs.mjs.map +1 -1
- package/fesm2022/es.framework-ng.ui.core-repeat.mjs +297 -88
- package/fesm2022/es.framework-ng.ui.core-repeat.mjs.map +1 -1
- package/package.json +1 -1
- package/styles.css +1 -1
- package/types/es.framework-ng.ui.core-repeat.d.ts +18 -2
|
@@ -3,6 +3,10 @@ import { NgModule, Component } from '@angular/core';
|
|
|
3
3
|
import { CommonModule } from '@angular/common';
|
|
4
4
|
import { TranslatePipe } from '@es.framework/ng.core/pipes';
|
|
5
5
|
import { FieldArrayType, FormlyField } from '@ngx-formly/core';
|
|
6
|
+
import * as i1 from '@angular/cdk/drag-drop';
|
|
7
|
+
import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
8
|
+
import * as i2 from '@angular/forms';
|
|
9
|
+
import { FormsModule } from '@angular/forms';
|
|
6
10
|
|
|
7
11
|
class RepeatModule {
|
|
8
12
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RepeatModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
@@ -18,141 +22,346 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImpor
|
|
|
18
22
|
|
|
19
23
|
class RepeatTypeComponent extends FieldArrayType {
|
|
20
24
|
cdr;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
// ✅ NEW VERSION OF YOUR FUNCTION
|
|
26
|
-
// getFirstRowColumns(): FormlyFieldConfig[] {
|
|
27
|
-
// const group = this.field.fieldGroup?.[0]?.fieldGroup ?? [];
|
|
28
|
-
// return group.map(f => ({
|
|
29
|
-
// ...f,
|
|
30
|
-
// type: 'label-type', // 🔥 force label-type here
|
|
31
|
-
// readonly: true,
|
|
32
|
-
// disabled: true,
|
|
33
|
-
// }));
|
|
34
|
-
// }
|
|
25
|
+
searchQuery = '';
|
|
26
|
+
currentPage = 0;
|
|
27
|
+
pageSize = 10;
|
|
35
28
|
constructor(cdr) {
|
|
36
29
|
super();
|
|
37
30
|
this.cdr = cdr;
|
|
38
31
|
}
|
|
39
32
|
ngOnInit() {
|
|
40
|
-
// Subscribe to each FormArray changes
|
|
41
|
-
// if (this.formControl instanceof FormArray) {
|
|
42
33
|
this.field.formControl.valueChanges.subscribe(() => {
|
|
43
|
-
// Force Angular to detect changes
|
|
44
34
|
this.field.fieldGroup = [...this.field.fieldGroup ?? []];
|
|
45
35
|
this.cdr.detectChanges();
|
|
46
36
|
});
|
|
47
|
-
|
|
37
|
+
}
|
|
38
|
+
getFirstRowColumns() {
|
|
39
|
+
return this.field.fieldGroup?.[0]?.fieldGroup ?? [];
|
|
40
|
+
}
|
|
41
|
+
// Row visibility / Delete Protection logic
|
|
42
|
+
canDelete(index) {
|
|
43
|
+
const isFirst = index === 0 && this.currentPage === 0;
|
|
44
|
+
const isSecond = index === 1 && this.currentPage === 0;
|
|
45
|
+
if (isFirst && !this.field.props?.['canDeleteFirstRow'])
|
|
46
|
+
return false;
|
|
47
|
+
if (isSecond && !this.field.props?.['canDeleteSecondRow'])
|
|
48
|
+
return false;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
// Pagination Logic
|
|
52
|
+
totalPages() {
|
|
53
|
+
return Math.ceil((this.field.fieldGroup?.length || 0) / this.pageSize) || 1;
|
|
54
|
+
}
|
|
55
|
+
displayedRows() {
|
|
56
|
+
const start = this.currentPage * this.pageSize;
|
|
57
|
+
return (this.field.fieldGroup || []).slice(start, start + this.pageSize);
|
|
58
|
+
}
|
|
59
|
+
nextPage() { if (this.currentPage < this.totalPages() - 1)
|
|
60
|
+
this.currentPage++; }
|
|
61
|
+
prevPage() { if (this.currentPage > 0)
|
|
62
|
+
this.currentPage--; }
|
|
63
|
+
// Totals Logic
|
|
64
|
+
// inside RepeatTypeComponent class
|
|
65
|
+
getFooterConfig(columnKey) {
|
|
66
|
+
// Access footer configuration defined in the field props
|
|
67
|
+
const footerConfigs = this.field.props?.['footerConfig'];
|
|
68
|
+
if (!footerConfigs)
|
|
69
|
+
return null;
|
|
70
|
+
// Find config for this specific key (e.g., { key: 'amount', label: 'Sum', type: 'sum' })
|
|
71
|
+
return footerConfigs.find((c) => c.key === columnKey);
|
|
72
|
+
}
|
|
73
|
+
calculateTotal(key, type = 'sum') {
|
|
74
|
+
const values = (this.formControl.value || [])
|
|
75
|
+
.map((v) => parseFloat(v[key]))
|
|
76
|
+
.filter((v) => !isNaN(v));
|
|
77
|
+
if (values.length === 0)
|
|
78
|
+
return '0.00';
|
|
79
|
+
let result = 0;
|
|
80
|
+
switch (type) {
|
|
81
|
+
case 'avg':
|
|
82
|
+
result = values.reduce((a, b) => a + b, 0) / values.length;
|
|
83
|
+
break;
|
|
84
|
+
case 'count':
|
|
85
|
+
return values.length.toString();
|
|
86
|
+
case 'sum':
|
|
87
|
+
default:
|
|
88
|
+
result = values.reduce((a, b) => a + b, 0);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
// Format as enterprise currency/number
|
|
92
|
+
return result.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
93
|
+
}
|
|
94
|
+
// Search Logic
|
|
95
|
+
onSearch() {
|
|
96
|
+
if (!this.searchQuery)
|
|
97
|
+
return;
|
|
98
|
+
const index = (this.field.fieldGroup || []).findIndex(row => JSON.stringify(row.model).toLowerCase().includes(this.searchQuery.toLowerCase()));
|
|
99
|
+
if (index !== -1) {
|
|
100
|
+
this.currentPage = Math.floor(index / this.pageSize);
|
|
101
|
+
// Optional: Scroll to matched row after a small timeout
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
document.getElementById(`row-${index % this.pageSize}`)?.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
104
|
+
}, 100);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
isMatched(row) {
|
|
108
|
+
if (!this.searchQuery)
|
|
109
|
+
return false;
|
|
110
|
+
return JSON.stringify(row.model).toLowerCase().includes(this.searchQuery.toLowerCase());
|
|
111
|
+
}
|
|
112
|
+
onDrop(event) {
|
|
113
|
+
moveItemInArray(this.field.fieldGroup, event.previousIndex, event.currentIndex);
|
|
114
|
+
const formArray = this.formControl;
|
|
115
|
+
const temp = formArray.at(event.previousIndex);
|
|
116
|
+
formArray.removeAt(event.previousIndex);
|
|
117
|
+
formArray.insert(event.currentIndex, temp);
|
|
118
|
+
this.field.fieldGroup = [...this.field.fieldGroup ?? []];
|
|
119
|
+
this.cdr.detectChanges();
|
|
48
120
|
}
|
|
49
121
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RepeatTypeComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
50
122
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: RepeatTypeComponent, isStandalone: true, selector: "formly-repeat-section", usesInheritance: true, ngImport: i0, template: `
|
|
51
|
-
<div class="
|
|
52
|
-
|
|
53
|
-
|
|
123
|
+
<div class="dx-grid-container shadow-md border border-[#c1c1c1] bg-white text-[#333] rounded-sm overflow-hidden">
|
|
124
|
+
|
|
125
|
+
<div class="bg-gradient-to-b from-[#fdfdfd] to-[#ececec] border-b border-[#c1c1c1] px-3 py-1.5 flex items-center justify-between gap-4">
|
|
126
|
+
<span class="text-[11px] font-bold uppercase tracking-tight text-[#555]">{{ field.props?.label || '' }}</span>
|
|
127
|
+
|
|
128
|
+
@if (field.props?.['enableSearch']) {
|
|
129
|
+
<div class="relative flex items-center">
|
|
130
|
+
<i class="pi pi-search absolute left-2 text-[10px] text-gray-400"></i>
|
|
131
|
+
<input
|
|
132
|
+
[(ngModel)]="searchQuery"
|
|
133
|
+
(input)="onSearch()"
|
|
134
|
+
[placeholder]="'Search' | translate"
|
|
135
|
+
class="pl-7 pr-2 py-1 text-[11px] border border-[#ccc] rounded-sm focus:border-[#0078d7] outline-none w-48 transition-all"
|
|
136
|
+
/>
|
|
137
|
+
</div>
|
|
138
|
+
}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="overflow-x-auto min-h-[100px]">
|
|
142
|
+
<table class="w-full border-collapse table-auto">
|
|
54
143
|
<thead>
|
|
55
|
-
<tr class="bg-
|
|
56
|
-
<th class="w-
|
|
144
|
+
<tr class="bg-[#f2f2f2] border-b border-[#d1d1d1]">
|
|
145
|
+
<th class="w-12 border-r border-[#d1d1d1] bg-[#f2f2f2]"></th>
|
|
57
146
|
@for (col of getFirstRowColumns(); track col) {
|
|
58
|
-
|
|
59
|
-
|
|
147
|
+
@if (!col.hide) {
|
|
148
|
+
<th style="text-align: initial;" class="px-3 py-2 text-[12px] font-semibold text-[#444] border-r border-[#d1d1d1] bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2] whitespace-nowrap">
|
|
149
|
+
{{ (col.props?.label ?? '') | translate }}
|
|
150
|
+
</th>
|
|
151
|
+
}
|
|
60
152
|
}
|
|
61
|
-
<th class="w-
|
|
153
|
+
<th class="w-12 bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2]"></th>
|
|
62
154
|
</tr>
|
|
63
155
|
</thead>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
156
|
+
|
|
157
|
+
<tbody cdkDropList (cdkDropListDropped)="onDrop($event)" [cdkDropListData]="field.fieldGroup">
|
|
158
|
+
@for (row of displayedRows(); track row; let rowIndex = $index) {
|
|
159
|
+
<tr cdkDrag
|
|
160
|
+
[id]="'row-' + rowIndex"
|
|
161
|
+
[class.bg-yellow-50]="isMatched(row)"
|
|
162
|
+
class="dx-row border-b border-[#e0e0e0] hover:bg-[#eff4ff] transition-colors bg-white">
|
|
163
|
+
|
|
164
|
+
<div *cdkDragPlaceholder class="bg-blue-50 border-2 border-dashed border-blue-200 h-10"></div>
|
|
165
|
+
|
|
166
|
+
<td class="text-center border-r border-[#e0e0e0] bg-[#f6f6f6] py-0 px-2 cursor-move" cdkDragHandle>
|
|
167
|
+
<div class="flex items-center gap-1">
|
|
168
|
+
<i class="pi pi-bars text-[10px] text-gray-300"></i>
|
|
169
|
+
<span class="text-[10px] text-gray-400 font-mono">{{ (currentPage * pageSize) + rowIndex + 1 }}</span>
|
|
170
|
+
</div>
|
|
171
|
+
</td>
|
|
172
|
+
|
|
68
173
|
@for (col of row.fieldGroup; track col) {
|
|
69
|
-
|
|
70
|
-
<
|
|
71
|
-
|
|
174
|
+
@if (!col.hide) {
|
|
175
|
+
<td class="p-0 border-r border-[#e0e0e0] align-middle min-w-[150px]">
|
|
176
|
+
<div class="dx-field-cell">
|
|
177
|
+
<formly-field [field]="col"></formly-field>
|
|
178
|
+
</div>
|
|
179
|
+
</td>
|
|
180
|
+
}
|
|
72
181
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
182
|
+
|
|
183
|
+
<td class="px-2 py-0 text-center bg-[#fcfcfc] w-12 border-l border-[#e0e0e0]">
|
|
184
|
+
@if (canDelete(rowIndex) && !(field.props?.['delete']?.hidden ?? false)) {
|
|
185
|
+
<button type="button" (click)="remove(rowIndex)" class="p-2 text-gray-400 hover:text-red-600 transition-colors">
|
|
186
|
+
<i class="pi pi-trash text-[13px]"></i>
|
|
77
187
|
</button>
|
|
78
188
|
}
|
|
79
189
|
</td>
|
|
80
190
|
</tr>
|
|
81
191
|
}
|
|
82
192
|
</tbody>
|
|
83
|
-
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
@if (field.props?.['showFooterTotals']) {
|
|
196
|
+
<tfoot>
|
|
197
|
+
<tr class="bg-[#f9f9f9] border-t-2 border-[#d1d1d1] font-bold text-[12px]">
|
|
198
|
+
<td class="border-r border-[#e0e0e0] bg-[#eee]"></td>
|
|
199
|
+
|
|
200
|
+
@for (col of getFirstRowColumns(); track col) {
|
|
201
|
+
@if (!col.hide) {
|
|
202
|
+
<td class="px-3 py-1 border-r border-[#e0e0e0] text-[#333]">
|
|
203
|
+
@if (getFooterConfig(col.key); as cfg) {
|
|
204
|
+
<div class="flex flex-col leading-tight">
|
|
205
|
+
<span class="text-[8px] text-gray-400 uppercase tracking-tighter">
|
|
206
|
+
{{ cfg.label | translate }}
|
|
207
|
+
</span>
|
|
208
|
+
<span class="text-[#005a9e]">
|
|
209
|
+
{{ calculateTotal(col.key, cfg.type) }}
|
|
210
|
+
</span>
|
|
211
|
+
</div>
|
|
212
|
+
}
|
|
213
|
+
</td>
|
|
214
|
+
}
|
|
84
215
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
216
|
+
<td class="bg-[#eee]"></td>
|
|
217
|
+
</tr>
|
|
218
|
+
</tfoot>
|
|
219
|
+
}
|
|
220
|
+
</table>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div class="p-2 border-t border-[#c1c1c1] bg-[#f3f3f3] flex items-center justify-between">
|
|
224
|
+
<div class="flex items-center gap-2">
|
|
225
|
+
@if (!(field.props?.['add']?.hidden ?? false)) {
|
|
226
|
+
<button type="button" (click)="add()" class="flex items-center gap-2 px-4 py-1.5 rounded-sm border border-primary-500 bg-primary-600 text-white text-[11px] font-medium hover:bg-primary-700 shadow-sm transition-all">
|
|
227
|
+
<i class="pi pi-plus text-[10px]"></i>
|
|
228
|
+
<span>{{ 'Add' | translate }}</span>
|
|
229
|
+
</button>
|
|
230
|
+
}
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<div class="flex items-center gap-1 text-[11px] text-gray-600">
|
|
234
|
+
<button (click)="nextPage()" [disabled]="currentPage >= totalPages() - 1" class="px-2 py-1 border border-gray-300 bg-white disabled:opacity-50"><i class="pi pi-chevron-right text-[9px]"></i></button>
|
|
235
|
+
<span class="px-2"> {{ currentPage + 1 }} - {{ totalPages() }}</span>
|
|
236
|
+
<button (click)="prevPage()" [disabled]="currentPage === 0" class="px-2 py-1 border border-gray-300 bg-white disabled:opacity-50"><i class="pi pi-chevron-left text-[9px]"></i></button>
|
|
237
|
+
|
|
238
|
+
</div>
|
|
95
239
|
</div>
|
|
96
|
-
}
|
|
97
240
|
</div>
|
|
98
|
-
`, isInline: true, dependencies: [{ kind: "component", type: FormlyField, selector: "formly-field", inputs: ["field"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
241
|
+
`, isInline: true, styles: [""], dependencies: [{ kind: "component", type: FormlyField, selector: "formly-field", inputs: ["field"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i1.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i1.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: i1.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i1.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] });
|
|
99
242
|
}
|
|
100
243
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: RepeatTypeComponent, decorators: [{
|
|
101
244
|
type: Component,
|
|
102
|
-
args: [{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
245
|
+
args: [{ selector: 'formly-repeat-section', standalone: true, imports: [FormlyField, TranslatePipe, DragDropModule, FormsModule], template: `
|
|
246
|
+
<div class="dx-grid-container shadow-md border border-[#c1c1c1] bg-white text-[#333] rounded-sm overflow-hidden">
|
|
247
|
+
|
|
248
|
+
<div class="bg-gradient-to-b from-[#fdfdfd] to-[#ececec] border-b border-[#c1c1c1] px-3 py-1.5 flex items-center justify-between gap-4">
|
|
249
|
+
<span class="text-[11px] font-bold uppercase tracking-tight text-[#555]">{{ field.props?.label || '' }}</span>
|
|
250
|
+
|
|
251
|
+
@if (field.props?.['enableSearch']) {
|
|
252
|
+
<div class="relative flex items-center">
|
|
253
|
+
<i class="pi pi-search absolute left-2 text-[10px] text-gray-400"></i>
|
|
254
|
+
<input
|
|
255
|
+
[(ngModel)]="searchQuery"
|
|
256
|
+
(input)="onSearch()"
|
|
257
|
+
[placeholder]="'Search' | translate"
|
|
258
|
+
class="pl-7 pr-2 py-1 text-[11px] border border-[#ccc] rounded-sm focus:border-[#0078d7] outline-none w-48 transition-all"
|
|
259
|
+
/>
|
|
260
|
+
</div>
|
|
261
|
+
}
|
|
262
|
+
</div>
|
|
263
|
+
|
|
264
|
+
<div class="overflow-x-auto min-h-[100px]">
|
|
265
|
+
<table class="w-full border-collapse table-auto">
|
|
110
266
|
<thead>
|
|
111
|
-
<tr class="bg-
|
|
112
|
-
<th class="w-
|
|
267
|
+
<tr class="bg-[#f2f2f2] border-b border-[#d1d1d1]">
|
|
268
|
+
<th class="w-12 border-r border-[#d1d1d1] bg-[#f2f2f2]"></th>
|
|
113
269
|
@for (col of getFirstRowColumns(); track col) {
|
|
114
|
-
|
|
115
|
-
|
|
270
|
+
@if (!col.hide) {
|
|
271
|
+
<th style="text-align: initial;" class="px-3 py-2 text-[12px] font-semibold text-[#444] border-r border-[#d1d1d1] bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2] whitespace-nowrap">
|
|
272
|
+
{{ (col.props?.label ?? '') | translate }}
|
|
273
|
+
</th>
|
|
274
|
+
}
|
|
116
275
|
}
|
|
117
|
-
<th class="w-
|
|
276
|
+
<th class="w-12 bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2]"></th>
|
|
118
277
|
</tr>
|
|
119
278
|
</thead>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
279
|
+
|
|
280
|
+
<tbody cdkDropList (cdkDropListDropped)="onDrop($event)" [cdkDropListData]="field.fieldGroup">
|
|
281
|
+
@for (row of displayedRows(); track row; let rowIndex = $index) {
|
|
282
|
+
<tr cdkDrag
|
|
283
|
+
[id]="'row-' + rowIndex"
|
|
284
|
+
[class.bg-yellow-50]="isMatched(row)"
|
|
285
|
+
class="dx-row border-b border-[#e0e0e0] hover:bg-[#eff4ff] transition-colors bg-white">
|
|
286
|
+
|
|
287
|
+
<div *cdkDragPlaceholder class="bg-blue-50 border-2 border-dashed border-blue-200 h-10"></div>
|
|
288
|
+
|
|
289
|
+
<td class="text-center border-r border-[#e0e0e0] bg-[#f6f6f6] py-0 px-2 cursor-move" cdkDragHandle>
|
|
290
|
+
<div class="flex items-center gap-1">
|
|
291
|
+
<i class="pi pi-bars text-[10px] text-gray-300"></i>
|
|
292
|
+
<span class="text-[10px] text-gray-400 font-mono">{{ (currentPage * pageSize) + rowIndex + 1 }}</span>
|
|
293
|
+
</div>
|
|
294
|
+
</td>
|
|
295
|
+
|
|
124
296
|
@for (col of row.fieldGroup; track col) {
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
|
|
297
|
+
@if (!col.hide) {
|
|
298
|
+
<td class="p-0 border-r border-[#e0e0e0] align-middle min-w-[150px]">
|
|
299
|
+
<div class="dx-field-cell">
|
|
300
|
+
<formly-field [field]="col"></formly-field>
|
|
301
|
+
</div>
|
|
302
|
+
</td>
|
|
303
|
+
}
|
|
128
304
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
305
|
+
|
|
306
|
+
<td class="px-2 py-0 text-center bg-[#fcfcfc] w-12 border-l border-[#e0e0e0]">
|
|
307
|
+
@if (canDelete(rowIndex) && !(field.props?.['delete']?.hidden ?? false)) {
|
|
308
|
+
<button type="button" (click)="remove(rowIndex)" class="p-2 text-gray-400 hover:text-red-600 transition-colors">
|
|
309
|
+
<i class="pi pi-trash text-[13px]"></i>
|
|
133
310
|
</button>
|
|
134
311
|
}
|
|
135
312
|
</td>
|
|
136
313
|
</tr>
|
|
137
314
|
}
|
|
138
315
|
</tbody>
|
|
139
|
-
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
@if (field.props?.['showFooterTotals']) {
|
|
319
|
+
<tfoot>
|
|
320
|
+
<tr class="bg-[#f9f9f9] border-t-2 border-[#d1d1d1] font-bold text-[12px]">
|
|
321
|
+
<td class="border-r border-[#e0e0e0] bg-[#eee]"></td>
|
|
322
|
+
|
|
323
|
+
@for (col of getFirstRowColumns(); track col) {
|
|
324
|
+
@if (!col.hide) {
|
|
325
|
+
<td class="px-3 py-1 border-r border-[#e0e0e0] text-[#333]">
|
|
326
|
+
@if (getFooterConfig(col.key); as cfg) {
|
|
327
|
+
<div class="flex flex-col leading-tight">
|
|
328
|
+
<span class="text-[8px] text-gray-400 uppercase tracking-tighter">
|
|
329
|
+
{{ cfg.label | translate }}
|
|
330
|
+
</span>
|
|
331
|
+
<span class="text-[#005a9e]">
|
|
332
|
+
{{ calculateTotal(col.key, cfg.type) }}
|
|
333
|
+
</span>
|
|
334
|
+
</div>
|
|
335
|
+
}
|
|
336
|
+
</td>
|
|
337
|
+
}
|
|
140
338
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
339
|
+
<td class="bg-[#eee]"></td>
|
|
340
|
+
</tr>
|
|
341
|
+
</tfoot>
|
|
342
|
+
}
|
|
343
|
+
</table>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
<div class="p-2 border-t border-[#c1c1c1] bg-[#f3f3f3] flex items-center justify-between">
|
|
347
|
+
<div class="flex items-center gap-2">
|
|
348
|
+
@if (!(field.props?.['add']?.hidden ?? false)) {
|
|
349
|
+
<button type="button" (click)="add()" class="flex items-center gap-2 px-4 py-1.5 rounded-sm border border-primary-500 bg-primary-600 text-white text-[11px] font-medium hover:bg-primary-700 shadow-sm transition-all">
|
|
350
|
+
<i class="pi pi-plus text-[10px]"></i>
|
|
351
|
+
<span>{{ 'Add' | translate }}</span>
|
|
352
|
+
</button>
|
|
353
|
+
}
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<div class="flex items-center gap-1 text-[11px] text-gray-600">
|
|
357
|
+
<button (click)="nextPage()" [disabled]="currentPage >= totalPages() - 1" class="px-2 py-1 border border-gray-300 bg-white disabled:opacity-50"><i class="pi pi-chevron-right text-[9px]"></i></button>
|
|
358
|
+
<span class="px-2"> {{ currentPage + 1 }} - {{ totalPages() }}</span>
|
|
359
|
+
<button (click)="prevPage()" [disabled]="currentPage === 0" class="px-2 py-1 border border-gray-300 bg-white disabled:opacity-50"><i class="pi pi-chevron-left text-[9px]"></i></button>
|
|
360
|
+
|
|
361
|
+
</div>
|
|
151
362
|
</div>
|
|
152
|
-
}
|
|
153
363
|
</div>
|
|
154
|
-
|
|
155
|
-
}]
|
|
364
|
+
` }]
|
|
156
365
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] });
|
|
157
366
|
|
|
158
367
|
class RepeatTableViewType extends FieldArrayType {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"es.framework-ng.ui.core-repeat.mjs","sources":["../../../../libs/ng.ui.core/repeat/src/lib/repeat-module.ts","../../../../libs/ng.ui.core/repeat/src/lib/repeat-section.type.ts","../../../../libs/ng.ui.core/repeat/src/lib/repeat-table-view.type.ts","../../../../libs/ng.ui.core/repeat/src/es.framework-ng.ui.core-repeat.ts"],"sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n@NgModule({\n imports: [CommonModule],\n})\nexport class RepeatModule {}\n","import { TranslatePipe } from '@es.framework/ng.core/pipes';\nimport { ChangeDetectorRef, Component, OnInit } from '@angular/core';\nimport { FieldArrayType, FormlyField, FormlyFieldConfig } from '@ngx-formly/core';\n\nimport { FormArray } from '@angular/forms';\n\n@Component({\n selector: 'formly-repeat-section',\n standalone: true,\n imports: [FormlyField, TranslatePipe],\n template: `\n <div class=\"overflow-auto bg-gray-100 border border-gray-300\">\n @if ((field.fieldGroup ?? []).length > 0) {\n <table class=\"table-auto w-full border border-gray-300\">\n <thead>\n <tr class=\"bg-gray-100 text-gray-700 text-sm\">\n <th class=\"w-8\"></th>\n @for (col of getFirstRowColumns(); track col) {\n <th class=\"text-center border\">@if (!col.hide) {<span>{{ (col.props?.label ?? '') | translate }}</span>}</th>\n <!-- <th class=\"text-center border\"><formly-field [field]=\"col\"></formly-field></th> -->\n }\n <th class=\"w-10\"></th>\n </tr>\n </thead>\n <tbody>\n @for (row of field.fieldGroup; track row; let rowIndex = $index) {\n <tr class=\"border-t\">\n <td class=\"bg-[#fffbea] text-center text-gray-400 px-2\"><i class=\"pi pi-bars\"></i></td>\n @for (col of row.fieldGroup; track col) {\n <td class=\"bg-[#fffbea]\">\n <formly-field [field]=\"col\"></formly-field>\n </td>\n }\n <td class=\"text-center px-2 bg-[#fffbea]\">\n @if ((rowIndex !== 0 || field.props?.['canDeleteFirstRow']) && !(field.props?.['delete']?.hidden ?? false)) {\n <button type=\"button\" (click)=\"remove(rowIndex)\" class=\"text-red-600 hover:text-red-800\">\n <i class=\"pi pi-trash\"></i>\n </button>\n }\n </td>\n </tr>\n }\n </tbody>\n </table>\n }\n \n @if (!(field.props?.['add']?.hidden ?? false)) {\n <div class=\"flex justify-end\">\n <button\n type=\"button\"\n class=\"inline-flex items-center gap-1 px-4 py-2 bg-primary-600 text-white text-sm font-medium hover:bg-primary-500 transition-colors duration-200 shadow-sm\"\n (click)=\"add()\"\n >\n <span class=\"text-lg\">+</span>\n </button>\n </div>\n }\n </div>\n `,\n})\nexport class RepeatTypeComponent extends FieldArrayType implements OnInit {\n // Return columns of the first row (for table headers)\n getFirstRowColumns() {\n return this.field.fieldGroup?.[0]?.fieldGroup ?? [];\n }\n // ✅ NEW VERSION OF YOUR FUNCTION\n // getFirstRowColumns(): FormlyFieldConfig[] {\n // const group = this.field.fieldGroup?.[0]?.fieldGroup ?? [];\n\n // return group.map(f => ({\n // ...f,\n // type: 'label-type', // 🔥 force label-type here\n // readonly: true,\n // disabled: true,\n // }));\n // }\n constructor(private cdr: ChangeDetectorRef) {\n super();\n }\n ngOnInit() {\n\n // Subscribe to each FormArray changes\n // if (this.formControl instanceof FormArray) {\n this.field.formControl.valueChanges.subscribe(() => {\n // Force Angular to detect changes\n\n this.field.fieldGroup = [...this.field.fieldGroup ?? []];\n this.cdr.detectChanges();\n });\n // }\n }\n}\n","\nimport { Component } from '@angular/core';\nimport { FieldArrayType } from '@ngx-formly/core';\nimport { TranslatePipe } from '@es.framework/ng.core/pipes';\n\n@Component({\n selector: 'formly-repeat-table-view',\n template: `\n <div class=\"mb-0\">\n \n <!-- <label class=\"block text-lg font-semibold mb-3\">\n {{ field.props?.label }}\n </label> -->\n \n <div class=\"overflow-x-auto rounded-xl border\">\n <table class=\"min-w-full bg-white border-collapse\">\n \n <thead class=\"bg-gray-100\">\n <tr>\n <!-- text-left -->\n @for (col of columns; track col) {\n <th\n class=\"px-4 py-3 text-right font-medium border-b\"\n >\n {{ col.label | translate }}\n </th>\n }\n </tr>\n </thead>\n \n <tbody>\n @for (row of rows; track row; let i = $index) {\n <tr\n class=\"border-b hover:bg-gray-50\">\n @for (col of columns; track col) {\n <td\n class=\"px-4 py-2\">\n {{ row[col.key] }}\n </td>\n }\n </tr>\n }\n \n @if (!rows || rows.length === 0) {\n <tr>\n <td [attr.colspan]=\"columns.length\"\n class=\"text-center py-6 text-gray-400\">\n No data\n </td>\n </tr>\n }\n \n </tbody>\n \n </table>\n </div>\n \n </div>\n \n `,\n imports: [TranslatePipe],\n})\nexport class RepeatTableViewType extends FieldArrayType {\n\n get columns() {\n const group = (this.field?.fieldArray as any)?.fieldGroup || [];\n return group.map((f :any)=> ({\n key: f.key as string,\n label: f.props?.label || f.key\n }));\n }\n\n get rows() {\n return this.model || [];\n }\n\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"es.framework-ng.ui.core-repeat.mjs","sources":["../../../../libs/ng.ui.core/repeat/src/lib/repeat-module.ts","../../../../libs/ng.ui.core/repeat/src/lib/repeat-section.type.ts","../../../../libs/ng.ui.core/repeat/src/lib/repeat-table-view.type.ts","../../../../libs/ng.ui.core/repeat/src/es.framework-ng.ui.core-repeat.ts"],"sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\n\n@NgModule({\n imports: [CommonModule],\n})\nexport class RepeatModule {}\n","import { TranslatePipe } from '@es.framework/ng.core/pipes';\nimport { ChangeDetectorRef, Component, OnInit, signal, computed } from '@angular/core';\nimport { FieldArrayType, FormlyField, FormlyFieldConfig } from '@ngx-formly/core';\nimport { DragDropModule, moveItemInArray, CdkDragDrop } from '@angular/cdk/drag-drop';\nimport { FormsModule } from '@angular/forms';\n\n@Component({\n selector: 'formly-repeat-section',\n standalone: true,\n imports: [FormlyField, TranslatePipe, DragDropModule, FormsModule],\n template: `\n <div class=\"dx-grid-container shadow-md border border-[#c1c1c1] bg-white text-[#333] rounded-sm overflow-hidden\">\n \n <div class=\"bg-gradient-to-b from-[#fdfdfd] to-[#ececec] border-b border-[#c1c1c1] px-3 py-1.5 flex items-center justify-between gap-4\">\n <span class=\"text-[11px] font-bold uppercase tracking-tight text-[#555]\">{{ field.props?.label || '' }}</span>\n \n @if (field.props?.['enableSearch']) {\n <div class=\"relative flex items-center\">\n <i class=\"pi pi-search absolute left-2 text-[10px] text-gray-400\"></i>\n <input \n [(ngModel)]=\"searchQuery\" \n (input)=\"onSearch()\"\n [placeholder]=\"'Search' | translate\" \n class=\"pl-7 pr-2 py-1 text-[11px] border border-[#ccc] rounded-sm focus:border-[#0078d7] outline-none w-48 transition-all\"\n />\n </div>\n }\n </div>\n\n <div class=\"overflow-x-auto min-h-[100px]\">\n <table class=\"w-full border-collapse table-auto\">\n <thead>\n <tr class=\"bg-[#f2f2f2] border-b border-[#d1d1d1]\">\n <th class=\"w-12 border-r border-[#d1d1d1] bg-[#f2f2f2]\"></th>\n @for (col of getFirstRowColumns(); track col) {\n @if (!col.hide) {\n <th style=\"text-align: initial;\" class=\"px-3 py-2 text-[12px] font-semibold text-[#444] border-r border-[#d1d1d1] bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2] whitespace-nowrap\">\n {{ (col.props?.label ?? '') | translate }}\n </th>\n }\n }\n <th class=\"w-12 bg-gradient-to-b from-[#fdfdfd] to-[#f2f2f2]\"></th>\n </tr>\n </thead>\n \n <tbody cdkDropList (cdkDropListDropped)=\"onDrop($event)\" [cdkDropListData]=\"field.fieldGroup\">\n @for (row of displayedRows(); track row; let rowIndex = $index) {\n <tr cdkDrag \n [id]=\"'row-' + rowIndex\"\n [class.bg-yellow-50]=\"isMatched(row)\"\n class=\"dx-row border-b border-[#e0e0e0] hover:bg-[#eff4ff] transition-colors bg-white\">\n \n <div *cdkDragPlaceholder class=\"bg-blue-50 border-2 border-dashed border-blue-200 h-10\"></div>\n\n <td class=\"text-center border-r border-[#e0e0e0] bg-[#f6f6f6] py-0 px-2 cursor-move\" cdkDragHandle>\n <div class=\"flex items-center gap-1\">\n <i class=\"pi pi-bars text-[10px] text-gray-300\"></i>\n <span class=\"text-[10px] text-gray-400 font-mono\">{{ (currentPage * pageSize) + rowIndex + 1 }}</span>\n </div>\n </td>\n \n @for (col of row.fieldGroup; track col) {\n @if (!col.hide) {\n <td class=\"p-0 border-r border-[#e0e0e0] align-middle min-w-[150px]\">\n <div class=\"dx-field-cell\">\n <formly-field [field]=\"col\"></formly-field>\n </div>\n </td>\n }\n }\n\n <td class=\"px-2 py-0 text-center bg-[#fcfcfc] w-12 border-l border-[#e0e0e0]\">\n @if (canDelete(rowIndex) && !(field.props?.['delete']?.hidden ?? false)) {\n <button type=\"button\" (click)=\"remove(rowIndex)\" class=\"p-2 text-gray-400 hover:text-red-600 transition-colors\">\n <i class=\"pi pi-trash text-[13px]\"></i>\n </button>\n }\n </td>\n </tr>\n }\n </tbody>\n\n \n@if (field.props?.['showFooterTotals']) {\n <tfoot>\n <tr class=\"bg-[#f9f9f9] border-t-2 border-[#d1d1d1] font-bold text-[12px]\">\n <td class=\"border-r border-[#e0e0e0] bg-[#eee]\"></td>\n \n @for (col of getFirstRowColumns(); track col) {\n @if (!col.hide) {\n <td class=\"px-3 py-1 border-r border-[#e0e0e0] text-[#333]\">\n @if (getFooterConfig(col.key); as cfg) {\n <div class=\"flex flex-col leading-tight\">\n <span class=\"text-[8px] text-gray-400 uppercase tracking-tighter\">\n {{ cfg.label | translate }}\n </span>\n <span class=\"text-[#005a9e]\">\n {{ calculateTotal(col.key, cfg.type) }}\n </span>\n </div>\n }\n </td>\n }\n }\n <td class=\"bg-[#eee]\"></td>\n </tr>\n </tfoot>\n}\n </table>\n </div>\n\n <div class=\"p-2 border-t border-[#c1c1c1] bg-[#f3f3f3] flex items-center justify-between\">\n <div class=\"flex items-center gap-2\">\n @if (!(field.props?.['add']?.hidden ?? false)) {\n <button type=\"button\" (click)=\"add()\" class=\"flex items-center gap-2 px-4 py-1.5 rounded-sm border border-primary-500 bg-primary-600 text-white text-[11px] font-medium hover:bg-primary-700 shadow-sm transition-all\">\n <i class=\"pi pi-plus text-[10px]\"></i>\n <span>{{ 'Add' | translate }}</span>\n </button>\n }\n </div>\n\n <div class=\"flex items-center gap-1 text-[11px] text-gray-600\">\n <button (click)=\"nextPage()\" [disabled]=\"currentPage >= totalPages() - 1\" class=\"px-2 py-1 border border-gray-300 bg-white disabled:opacity-50\"><i class=\"pi pi-chevron-right text-[9px]\"></i></button>\n <span class=\"px-2\"> {{ currentPage + 1 }} - {{ totalPages() }}</span>\n <button (click)=\"prevPage()\" [disabled]=\"currentPage === 0\" class=\"px-2 py-1 border border-gray-300 bg-white disabled:opacity-50\"><i class=\"pi pi-chevron-left text-[9px]\"></i></button>\n \n </div>\n </div>\n </div>\n `,\n styles: [`\n :host ::ng-deep {\n .dx-field-cell .form-control, .dx-field-cell input, .dx-field-cell select {\n @apply w-full bg-transparent border-none px-3 py-2 text-[13px] outline-none;\n border-radius: 0; box-shadow: none !important;\n }\n .dx-field-cell:focus-within { @apply bg-white ring-1 ring-inset ring-[#0078d7]; box-shadow: inset 0 0 0 1px #0078d7; }\n .dx-row:nth-child(even) { background-color: #fafafa; }\n .cdk-drag-preview { @apply shadow-2xl border border-blue-200 bg-white opacity-90; display: table; width: 100%; }\n }\n `]\n})\nexport class RepeatTypeComponent extends FieldArrayType implements OnInit {\n searchQuery = '';\n currentPage = 0;\n pageSize = 10;\n\n constructor(private cdr: ChangeDetectorRef) { super(); }\n\n ngOnInit() {\n this.field.formControl.valueChanges.subscribe(() => {\n this.field.fieldGroup = [...this.field.fieldGroup ?? []];\n this.cdr.detectChanges();\n });\n }\n\n getFirstRowColumns() {\n return this.field.fieldGroup?.[0]?.fieldGroup ?? [];\n }\n\n // Row visibility / Delete Protection logic\n canDelete(index: number): boolean {\n const isFirst = index === 0 && this.currentPage === 0;\n const isSecond = index === 1 && this.currentPage === 0;\n \n if (isFirst && !this.field.props?.['canDeleteFirstRow']) return false;\n if (isSecond && !this.field.props?.['canDeleteSecondRow']) return false;\n \n return true;\n }\n\n // Pagination Logic\n totalPages() {\n return Math.ceil((this.field.fieldGroup?.length || 0) / this.pageSize) || 1;\n }\n\n displayedRows() {\n const start = this.currentPage * this.pageSize;\n return (this.field.fieldGroup || []).slice(start, start + this.pageSize);\n }\n\n nextPage() { if (this.currentPage < this.totalPages() - 1) this.currentPage++; }\n prevPage() { if (this.currentPage > 0) this.currentPage--; }\n\n // Totals Logic\n // inside RepeatTypeComponent class\n\ngetFooterConfig(columnKey: any) {\n // Access footer configuration defined in the field props\n const footerConfigs = this.field.props?.['footerConfig'];\n if (!footerConfigs) return null;\n \n // Find config for this specific key (e.g., { key: 'amount', label: 'Sum', type: 'sum' })\n return footerConfigs.find((c: any) => c.key === columnKey);\n}\n\ncalculateTotal(key: any, type: 'sum' | 'avg' | 'count' = 'sum'): string {\n const values = (this.formControl.value || [])\n .map((v: any) => parseFloat(v[key]))\n .filter((v: number) => !isNaN(v));\n\n if (values.length === 0) return '0.00';\n\n let result = 0;\n switch (type) {\n case 'avg':\n result = values.reduce((a:any, b:any) => a + b, 0) / values.length;\n break;\n case 'count':\n return values.length.toString();\n case 'sum':\n default:\n result = values.reduce((a:any, b:any) => a + b, 0);\n break;\n }\n\n // Format as enterprise currency/number\n return result.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });\n}\n\n // Search Logic\n onSearch() {\n if (!this.searchQuery) return;\n const index = (this.field.fieldGroup || []).findIndex(row => \n JSON.stringify(row.model).toLowerCase().includes(this.searchQuery.toLowerCase())\n );\n \n if (index !== -1) {\n this.currentPage = Math.floor(index / this.pageSize);\n // Optional: Scroll to matched row after a small timeout\n setTimeout(() => {\n document.getElementById(`row-${index % this.pageSize}`)?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, 100);\n }\n }\n\n isMatched(row: FormlyFieldConfig): boolean {\n if (!this.searchQuery) return false;\n return JSON.stringify(row.model).toLowerCase().includes(this.searchQuery.toLowerCase());\n }\n\n onDrop(event: CdkDragDrop<any[]> | any) {\n moveItemInArray(this.field.fieldGroup as any[], event.previousIndex, event.currentIndex);\n const formArray = this.formControl as any;\n const temp = formArray.at(event.previousIndex);\n formArray.removeAt(event.previousIndex);\n formArray.insert(event.currentIndex, temp);\n this.field.fieldGroup = [...this.field.fieldGroup ?? []];\n this.cdr.detectChanges();\n }\n}","\nimport { Component } from '@angular/core';\nimport { FieldArrayType } from '@ngx-formly/core';\nimport { TranslatePipe } from '@es.framework/ng.core/pipes';\n\n@Component({\n selector: 'formly-repeat-table-view',\n template: `\n <div class=\"mb-0\">\n \n <!-- <label class=\"block text-lg font-semibold mb-3\">\n {{ field.props?.label }}\n </label> -->\n \n <div class=\"overflow-x-auto rounded-xl border\">\n <table class=\"min-w-full bg-white border-collapse\">\n \n <thead class=\"bg-gray-100\">\n <tr>\n <!-- text-left -->\n @for (col of columns; track col) {\n <th\n class=\"px-4 py-3 text-right font-medium border-b\"\n >\n {{ col.label | translate }}\n </th>\n }\n </tr>\n </thead>\n \n <tbody>\n @for (row of rows; track row; let i = $index) {\n <tr\n class=\"border-b hover:bg-gray-50\">\n @for (col of columns; track col) {\n <td\n class=\"px-4 py-2\">\n {{ row[col.key] }}\n </td>\n }\n </tr>\n }\n \n @if (!rows || rows.length === 0) {\n <tr>\n <td [attr.colspan]=\"columns.length\"\n class=\"text-center py-6 text-gray-400\">\n No data\n </td>\n </tr>\n }\n \n </tbody>\n \n </table>\n </div>\n \n </div>\n \n `,\n imports: [TranslatePipe],\n})\nexport class RepeatTableViewType extends FieldArrayType {\n\n get columns() {\n const group = (this.field?.fieldArray as any)?.fieldGroup || [];\n return group.map((f :any)=> ({\n key: f.key as string,\n label: f.props?.label || f.key\n }));\n }\n\n get rows() {\n return this.model || [];\n }\n\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|