aggregation
This commit is contained in:
		
							parent
							
								
									7f80ea6330
								
							
						
					
					
						commit
						56e1e3b0fe
					
				| @ -17,8 +17,9 @@ | ||||
|       </button> | ||||
|     </div> | ||||
|   </div> | ||||
|   <ng-container *ngIf="!isCardview"> <!-- GET ALL --> <clr-datagrid [clrDgLoading]="loading" | ||||
|       [(clrDgSelected)]="selected"> | ||||
|   <ng-container *ngIf="!isCardview"> <!-- GET ALL --> | ||||
|     <div style="overflow-x: auto;"> | ||||
|       <clr-datagrid [clrDgLoading]="loading" [(clrDgSelected)]="selected" style="width: max-content; min-width: 100%;"> | ||||
|         <clr-dg-placeholder> | ||||
|           <ng-template #loadingSpinner> | ||||
|             <clr-spinner>Loading ... </clr-spinner> | ||||
| @ -33,6 +34,8 @@ | ||||
|         <clr-dg-column [clrDgField]="'url'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Url | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
|         <clr-dg-column [clrDgField]="'url_endpoint'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Url Endpoint | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
|         <clr-dg-column [clrDgField]="'schedule'"> <ng-container *clrDgHideableColumn="{hidden: false}"> schedule | ||||
|           </ng-container></clr-dg-column> | ||||
| @ -45,20 +48,26 @@ | ||||
|         <clr-dg-column [clrDgField]="'json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> json | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
| 
 | ||||
|       <clr-dg-column [clrDgField]="'url_endpoint'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Url Endpoint | ||||
|         <!-- Add groupby_json column --> | ||||
|         <clr-dg-column [clrDgField]="'groupby_json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||
|             Group By JSON | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         <clr-dg-column [clrDgField]="'batch_volume'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Batch Volume | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
|       <clr-dg-column [clrDgField]="'sure_connect_id'"> <ng-container *clrDgHideableColumn="{hidden: false}"> SureConnect | ||||
|         <clr-dg-column [clrDgField]="'sure_connect_id'"> <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||
|             SureConnect | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
|         <clr-dg-column [clrDgField]="'calculated_field_json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||
|             Calculated Fields | ||||
|           </ng-container></clr-dg-column> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         <!-- who column --> | ||||
|         <clr-dg-column> | ||||
|           <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||
| @ -71,20 +80,6 @@ | ||||
|           <clr-dg-cell>{{user.name }}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|         <clr-dg-cell (click)="goTourlUrl(user.url)" | ||||
|           style="cursor: pointer; color: rgb(108, 108, 194);">{{user.url}}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|         <clr-dg-cell>{{user.schedule }}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|         <clr-dg-cell>{{user.cron_job }}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|         <clr-dg-cell (click)="goToReplaceStringjson(user.json)" style="cursor: pointer; align-items: center;"><clr-icon | ||||
|             shape="details"></clr-icon></clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|           <clr-dg-cell> | ||||
|             <div style="display: flex; align-items: center; max-width: 200px;"> | ||||
|               <span | ||||
| @ -97,6 +92,36 @@ | ||||
|               </button> | ||||
|             </div> | ||||
|           </clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|           <clr-dg-cell> | ||||
|             <div style="display: flex; align-items: center; max-width: 200px;"> | ||||
|               <span | ||||
|                 style="margin-right: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-grow: 1;" | ||||
|                 title="{{user.url_endpoint}}" (click)="showFullUrl(user.url_endpoint)"> | ||||
|                 {{user.url | slice:0:30}}{{user.url_endpoint.length > 30 ? '...' : ''}} | ||||
|               </span> | ||||
|               <button class="btn btn-icon btn-sm" (click)="copyToClipboard(user.url_endpoint)" title="Copy URL"> | ||||
|                 <clr-icon shape="copy-to-clipboard"></clr-icon> | ||||
|               </button> | ||||
|             </div> | ||||
|           </clr-dg-cell> | ||||
| 
 | ||||
|           <clr-dg-cell>{{user.schedule }}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|           <clr-dg-cell>{{user.cron_job }}</clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|           <clr-dg-cell (click)="goToReplaceStringjson(user.json)" | ||||
|             style="cursor: pointer; align-items: center;"><clr-icon shape="details"></clr-icon></clr-dg-cell> | ||||
| 
 | ||||
|           <!-- Add groupby_json cell --> | ||||
|           <clr-dg-cell (click)="goToReplaceStringjson(user.groupby_json)" | ||||
|             style="cursor: pointer; align-items: center;"><clr-icon shape="details" | ||||
|               *ngIf="user.groupby_json"></clr-icon></clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
|           <clr-dg-cell>{{user.batch_volume}}</clr-dg-cell> | ||||
| 
 | ||||
|           <clr-dg-cell>{{user.sureconnect_name}}</clr-dg-cell> | ||||
| @ -105,8 +130,11 @@ | ||||
|             style="cursor: pointer; align-items: center;"><clr-icon shape="details" | ||||
|               *ngIf="user.calculated_field_json"></clr-icon></clr-dg-cell> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|           <!-- who column --> | ||||
|           <clr-dg-cell> | ||||
|             <div style="display: flex; align-items: center; gap: 1px; flex-wrap: nowrap;"> | ||||
|               <clr-signpost> | ||||
|                 <span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success" | ||||
|                     style="color: rgb(0, 130, 236);"></clr-icon></span> | ||||
| @ -121,14 +149,20 @@ | ||||
|               </clr-signpost> | ||||
| 
 | ||||
|               <!-- New JSON Update button --> | ||||
|           <button class="btn btn-icon" (click)="updateJson(user.id)" title="Update JSON"> | ||||
|               <button class="btn btn-icon btn-sm" (click)="updateJson(user.id)" title="Update JSON"> | ||||
|                 <clr-icon shape="refresh"></clr-icon> | ||||
|               </button> | ||||
| 
 | ||||
|               <!-- Calculated Field button --> | ||||
|           <button class="btn btn-icon" (click)="fetchAvailableKeys(user)" title="Create Calculated Field"> | ||||
|               <button class="btn btn-icon btn-sm" (click)="fetchAvailableKeys(user)" title="Create Calculated Field"> | ||||
|                 <clr-icon shape="calculator"></clr-icon> | ||||
|               </button> | ||||
| 
 | ||||
|               <!-- Group By button --> | ||||
|               <button class="btn btn-icon btn-sm" (click)="openGroupByModal(user)" title="Group By Configuration"> | ||||
|                 <clr-icon shape="group"></clr-icon> | ||||
|               </button> | ||||
|             </div> | ||||
|           </clr-dg-cell> | ||||
| 
 | ||||
|           <!-- who colmn --> | ||||
| @ -155,7 +189,9 @@ | ||||
|             of {{pagination.totalItems}} users | ||||
|           </clr-dg-pagination> | ||||
|         </clr-dg-footer> | ||||
|     </clr-datagrid> </ng-container> | ||||
|       </clr-datagrid> | ||||
|     </div> | ||||
|   </ng-container> | ||||
|   <ng-template #showInfo> | ||||
|     <div class="alert alert-info" role="alert"> | ||||
|       <div class="alert-items"> | ||||
| @ -289,7 +325,41 @@ | ||||
| 
 | ||||
| <clr-modal [(clrModalOpen)]="rsModaljson" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true"> | ||||
|   <div class="modal-body"> | ||||
|     <textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea> | ||||
|     <!-- Grid view above JSON --> | ||||
|     <div *ngIf="isJsonData(rowSelected)" class="json-grid-view" style="margin-bottom: 20px;"> | ||||
|       <h4>JSON Data Grid View</h4> | ||||
|       <div style="overflow-x: auto; max-height: 300px; overflow-y: auto;"> | ||||
|         <clr-datagrid style="width: max-content; min-width: 100%;"> | ||||
|           <!-- Generate columns dynamically based on JSON keys --> | ||||
|           <clr-dg-column *ngFor="let header of getJsonHeaders(rowSelected)" style="min-width: 150px;"> | ||||
|             <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||
|               {{header}} | ||||
|             </ng-container> | ||||
|           </clr-dg-column> | ||||
| 
 | ||||
|           <!-- Generate rows dynamically from JSON data --> | ||||
|           <clr-dg-row *ngFor="let item of getJsonData(rowSelected); let i = index" [clrDgItem]="item"> | ||||
|             <clr-dg-cell *ngFor="let header of getJsonHeaders(rowSelected)" style="min-width: 150px;"> | ||||
|               <span [title]="item[header]" | ||||
|                 style="display: inline-block; max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> | ||||
|                 {{item[header]}} | ||||
|               </span> | ||||
|             </clr-dg-cell> | ||||
|           </clr-dg-row> | ||||
| 
 | ||||
|           <clr-dg-footer> | ||||
|             <clr-dg-pagination #jsonPagination [clrDgPageSize]="5"> | ||||
|               <clr-dg-page-size [clrPageSizeOptions]="[5, 10, 20]">Items per page</clr-dg-page-size> | ||||
|               {{jsonPagination.firstItem + 1}} - {{jsonPagination.lastItem + 1}} | ||||
|               of {{getJsonData(rowSelected).length}} items | ||||
|             </clr-dg-pagination> | ||||
|           </clr-dg-footer> | ||||
|         </clr-datagrid> | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <!-- JSON view below grid --> | ||||
|     <textarea class="form-control" style="width:100%; height: 200px;" readonly>{{rowSelected}}</textarea> | ||||
|   </div> | ||||
| </clr-modal> | ||||
| 
 | ||||
| @ -641,11 +711,12 @@ | ||||
|                   </select> | ||||
|                 </div> | ||||
|                 <div class="constant-input-container"> | ||||
|                   <input type="text" class="constant-input" formControlName="constant" placeholder="Or enter constant value" /> | ||||
|                   <input type="text" class="constant-input" formControlName="constant" | ||||
|                     placeholder="Or enter constant value" /> | ||||
|                 </div> | ||||
|                 <div class="remove-btn-container"> | ||||
|                   <button type="button" class="btn btn-icon btn-danger remove-field-btn" (click)="removeFieldComponent(i)" | ||||
|                     *ngIf="getFieldComponents().length > 1"> | ||||
|                   <button type="button" class="btn btn-icon btn-danger remove-field-btn" | ||||
|                     (click)="removeFieldComponent(i)" *ngIf="getFieldComponents().length > 1"> | ||||
|                     <clr-icon shape="trash"></clr-icon> | ||||
|                   </button> | ||||
|                 </div> | ||||
| @ -681,7 +752,7 @@ | ||||
|                 <td class="operation-cell">{{ field.operation }}</td> | ||||
|                 <td class="expression-cell"> | ||||
|                   <span *ngIf="field.operation === 'complex'">{{ field.complexEquation }}</span> | ||||
|                   <span *ngIf="field.operation !== 'complex'"> | ||||
|                   <span *ngIf="field.operation !== 'complex' && field.type !== 'groupby'"> | ||||
|                     <span *ngFor="let component of field.fieldComponents; let last = last"> | ||||
|                       <span *ngIf="component.field && !component.isConstant">{{ component.field }}</span> | ||||
|                       <span *ngIf="component.isConstant">"{{ component.constant }}"</span> | ||||
| @ -689,9 +760,24 @@ | ||||
|                       <span *ngIf="!last"> {{ getOperationSymbol(field.operation) }} </span> | ||||
|                     </span> | ||||
|                   </span> | ||||
|                   <span *ngIf="field.type === 'groupby'"> | ||||
|                     GROUP BY: {{ field.groupFields.join(', ') }} | ||||
|                     <div *ngIf="field.aggregations && field.aggregations.length > 0"> | ||||
|                       <small> | ||||
|                         <div *ngFor="let agg of field.aggregations"> | ||||
|                           {{ agg.operation.toUpperCase() }}({{ agg.field }}) | ||||
|                         </div> | ||||
|                       </small> | ||||
|                     </div> | ||||
|                   </span> | ||||
|                 </td> | ||||
|                 <td class="actions-cell"> | ||||
|                   <button class="btn btn-icon btn-danger delete-field-btn" (click)="deleteCalculatedField(field.id)"> | ||||
|                 <td> | ||||
|                   <button class="btn btn-icon btn-danger" (click)="deleteCalculatedField(field.id)" | ||||
|                     *ngIf="field.type !== 'groupby'"> | ||||
|                     <clr-icon shape="trash"></clr-icon> | ||||
|                   </button> | ||||
|                   <button class="btn btn-icon btn-danger" (click)="removeGroupByConfig(field.id)" | ||||
|                     *ngIf="field.type === 'groupby'"> | ||||
|                     <clr-icon shape="trash"></clr-icon> | ||||
|                   </button> | ||||
|                 </td> | ||||
| @ -732,15 +818,76 @@ | ||||
|   </div> | ||||
| </clr-modal> | ||||
| 
 | ||||
| <!-- Group By Modal --> | ||||
| <clr-modal [(clrModalOpen)]="showGroupByModal" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true"> | ||||
|   <h3 class="modal-title">Group By Configuration</h3> | ||||
|   <div class="modal-body"> | ||||
|     <div class="clr-row"> | ||||
|       <div class="clr-col-12"> | ||||
|         <h4>Group By Fields</h4> | ||||
|         <div class="field-container"> | ||||
|           <span *ngFor="let key of availableKeys" class="field-tag" [class.selected]="isGroupByFieldSelected(key)" | ||||
|             (click)="isGroupByFieldSelected(key) ? removeGroupByField(key) : addGroupByField(key)"> | ||||
|             {{ key }} | ||||
|           </span> | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="clr-col-12" style="margin-top: 20px;"> | ||||
|         <h4>Selected Group By Fields</h4> | ||||
|         <div class="selected-fields-container"> | ||||
|           <span *ngFor="let field of selectedGroupByFields" class="selected-field-tag"> | ||||
|             {{ field }} | ||||
|             <button class="btn btn-icon btn-sm" (click)="removeGroupByField(field)"> | ||||
|               <clr-icon shape="times"></clr-icon> | ||||
|             </button> | ||||
|           </span> | ||||
|           <div *ngIf="selectedGroupByFields.length === 0" class="no-selection"> | ||||
|             No fields selected for grouping | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="clr-col-12" style="margin-top: 20px;"> | ||||
|         <h4>Aggregation Operations</h4> | ||||
|         <div class="aggregation-container"> | ||||
|           <div *ngFor="let agg of selectedAggregationFields; let i = index" class="aggregation-row"> | ||||
|             <div class="clr-row"> | ||||
|               <div class="clr-col-5"> | ||||
|                 <label>Field</label> | ||||
|                 <select class="clr-select" [(ngModel)]="agg.field"> | ||||
|                   <option value="">Select Field</option> | ||||
|                   <option *ngFor="let key of availableKeys" [value]="key">{{ key }}</option> | ||||
|                 </select> | ||||
|               </div> | ||||
|               <div class="clr-col-5"> | ||||
|                 <label>Operation</label> | ||||
|                 <select class="clr-select" [(ngModel)]="agg.operation"> | ||||
|                   <option *ngFor="let op of aggregationOperations" [value]="op.value">{{ op.label }}</option> | ||||
|                 </select> | ||||
|               </div> | ||||
|               <div class="clr-col-2"> | ||||
|                 <button class="btn btn-icon btn-danger" (click)="removeAggregationField(i)" style="margin-top: 20px;"> | ||||
|                   <clr-icon shape="trash"></clr-icon> | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|           <button class="btn btn-sm" (click)="addAggregationField()" style="margin-top: 10px;"> | ||||
|             <clr-icon shape="plus"></clr-icon> Add Aggregation | ||||
|           </button> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class="modal-footer"> | ||||
|     <button type="button" class="btn btn-outline" (click)="showGroupByModal = false">Cancel</button> | ||||
|     <button type="button" class="btn btn-primary" (click)="applyGroupBy()" | ||||
|       [disabled]="selectedGroupByFields.length === 0"> | ||||
|       Apply Group By | ||||
|     </button> | ||||
|   </div> | ||||
| </clr-modal> | ||||
| 
 | ||||
| <!-- htmlpopup --> | ||||
| @ -295,3 +295,92 @@ | ||||
|     margin-bottom: 8px; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* Group By Modal Styles */ | ||||
| .field-container { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
|   gap: 8px; | ||||
|   margin-top: 10px; | ||||
| } | ||||
| 
 | ||||
| .field-tag { | ||||
|   display: inline-flex; | ||||
|   align-items: center; | ||||
|   background-color: #e3f2fd; | ||||
|   border: 1px solid #bbdefb; | ||||
|   border-radius: 20px; | ||||
|   padding: 6px 12px; | ||||
|   margin: 4px; | ||||
|   font-size: 13px; | ||||
|   font-family: monospace; | ||||
|   cursor: pointer; | ||||
|   transition: all 0.2s; | ||||
| } | ||||
| 
 | ||||
| .field-tag:hover { | ||||
|   background-color: #bbdefb; | ||||
|   transform: translateY(-2px); | ||||
|   box-shadow: 0 2px 4px rgba(0,0,0,0.1); | ||||
| } | ||||
| 
 | ||||
| .field-tag.selected { | ||||
|   background-color: #1976d2; | ||||
|   color: white; | ||||
|   border-color: #1976d2; | ||||
| } | ||||
| 
 | ||||
| .selected-fields-container { | ||||
|   min-height: 50px; | ||||
|   padding: 10px; | ||||
|   border: 1px dashed #ccc; | ||||
|   border-radius: 4px; | ||||
|   background-color: #f9f9f9; | ||||
| } | ||||
| 
 | ||||
| .selected-field-tag { | ||||
|   display: inline-flex; | ||||
|   align-items: center; | ||||
|   background-color: #1976d2; | ||||
|   color: white; | ||||
|   border-radius: 20px; | ||||
|   padding: 6px 12px; | ||||
|   margin: 4px; | ||||
|   font-size: 13px; | ||||
| } | ||||
| 
 | ||||
| .selected-field-tag .btn-icon { | ||||
|   margin-left: 8px; | ||||
|   padding: 2px; | ||||
|   color: white; | ||||
| } | ||||
| 
 | ||||
| .no-selection { | ||||
|   color: #999; | ||||
|   font-style: italic; | ||||
|   padding: 10px; | ||||
| } | ||||
| 
 | ||||
| .aggregation-container { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| 
 | ||||
| .aggregation-row { | ||||
|   background-color: #f5f5f5; | ||||
|   padding: 15px; | ||||
|   border-radius: 4px; | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .aggregation-row label { | ||||
|   display: block; | ||||
|   margin-bottom: 5px; | ||||
|   font-weight: 500; | ||||
| } | ||||
| 
 | ||||
| .clr-select { | ||||
|   width: 100%; | ||||
|   padding: 5px; | ||||
|   border: 1px solid #ccc; | ||||
|   border-radius: 4px; | ||||
| } | ||||
|  | ||||
| @ -76,6 +76,25 @@ export class Data_lakeComponent implements OnInit { | ||||
|   currentConstantValue = ''; | ||||
|   pendingEquationUpdate = ''; | ||||
|    | ||||
|   // New properties for group by functionality
 | ||||
|   groupByFields: string[] = []; | ||||
|   selectedGroupByFields: string[] = []; | ||||
|   showGroupByModal = false; | ||||
|    | ||||
|   // Aggregation operations
 | ||||
|   aggregationOperations = [ | ||||
|     { value: 'count', label: 'Count' }, | ||||
|     { value: 'sum', label: 'Sum' }, | ||||
|     { value: 'avg', label: 'Average' }, | ||||
|     { value: 'min', label: 'Minimum' }, | ||||
|     { value: 'max', label: 'Maximum' }, | ||||
|     { value: 'median', label: 'Median' }, | ||||
|     { value: 'mode', label: 'Mode' }, | ||||
|     { value: 'stdev', label: 'Standard Deviation' } | ||||
|   ]; | ||||
|    | ||||
|   selectedAggregationFields: { field: string; operation: string }[] = []; | ||||
|    | ||||
|   constructor( | ||||
|     private extensionService: ExtensionService, | ||||
|     private userInfoService: UserInfoService, | ||||
| @ -745,6 +764,7 @@ export class Data_lakeComponent implements OnInit { | ||||
|       this.ngOnInit(); | ||||
|     }, 500); | ||||
|   } | ||||
|    | ||||
|   goToAdd(row) { | ||||
|     this.modalAdd = true; | ||||
|     this.addCronExpression = ''; | ||||
| @ -807,8 +827,10 @@ export class Data_lakeComponent implements OnInit { | ||||
|           this.product[index].iscalculatedfield = true; | ||||
|         } | ||||
|          | ||||
|         // Close the modal
 | ||||
|         // Close the modal only when called directly from the UI
 | ||||
|         if (this.calculatedFieldModalOpen) { | ||||
|           this.calculatedFieldModalOpen = false; | ||||
|         } | ||||
|       }, | ||||
|       (error) => { | ||||
|         console.error('Error updating calculated fields:', error); | ||||
| @ -968,4 +990,195 @@ export class Data_lakeComponent implements OnInit { | ||||
|     console.log('Validation result:', isValid); | ||||
|     console.log('Defined constants:', this.getDefinedConstants()); | ||||
|   } | ||||
|    | ||||
|   // Method to open group by modal
 | ||||
|   openGroupByModal(dataLakeItem: any) { | ||||
|     this.selectedDataLakeItem = dataLakeItem; | ||||
|      | ||||
|     // Fetch available keys if not already fetched
 | ||||
|     if (this.availableKeys.length === 0) { | ||||
|       this.fetchAvailableKeys(dataLakeItem); | ||||
|     } | ||||
|      | ||||
|     // Initialize selected group by fields as empty array
 | ||||
|     this.selectedGroupByFields = []; | ||||
|     this.selectedAggregationFields = []; | ||||
|     this.showGroupByModal = true; | ||||
|   } | ||||
|    | ||||
|   // Method to add a field to group by selection
 | ||||
|   addGroupByField(field: string) { | ||||
|     if (!this.selectedGroupByFields.includes(field)) { | ||||
|       this.selectedGroupByFields.push(field); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // Method to remove a field from group by selection
 | ||||
|   removeGroupByField(field: string) { | ||||
|     const index = this.selectedGroupByFields.indexOf(field); | ||||
|     if (index > -1) { | ||||
|       this.selectedGroupByFields.splice(index, 1); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // Method to add an aggregation field
 | ||||
|   addAggregationField() { | ||||
|     this.selectedAggregationFields.push({ field: '', operation: 'count' }); | ||||
|   } | ||||
|    | ||||
|   // Method to remove an aggregation field
 | ||||
|   removeAggregationField(index: number) { | ||||
|     this.selectedAggregationFields.splice(index, 1); | ||||
|   } | ||||
|    | ||||
|   // Method to update aggregation field
 | ||||
|   updateAggregationField(index: number, field: string, operation: string) { | ||||
|     this.selectedAggregationFields[index] = { field, operation }; | ||||
|   } | ||||
|    | ||||
|   // Method to apply group by
 | ||||
|   applyGroupBy() { | ||||
|     if (this.selectedGroupByFields.length === 0) { | ||||
|       this.toastr.error('Please select at least one field for grouping'); | ||||
|       return; | ||||
|     } | ||||
|      | ||||
|     // Validate aggregation fields
 | ||||
|     for (const agg of this.selectedAggregationFields) { | ||||
|       if (!agg.field) { | ||||
|         this.toastr.error('Please select a field for all aggregation operations'); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     // Create group by configuration
 | ||||
|     const groupByConfig = { | ||||
|       id: Date.now(), | ||||
|       type: 'groupby', | ||||
|       groupFields: [...this.selectedGroupByFields], | ||||
|       aggregations: [...this.selectedAggregationFields], | ||||
|       timestamp: new Date().toISOString() | ||||
|     }; | ||||
|      | ||||
|     // Add to calculated fields
 | ||||
|     this.calculatedFields.push(groupByConfig); | ||||
|     this.toastr.success('Group by configuration added successfully'); | ||||
|      | ||||
|     // Update the calculated fields in the backend
 | ||||
|     this.updateCalculatedFieldsAfterGroupBy(); | ||||
|      | ||||
|     this.showGroupByModal = false; | ||||
|   } | ||||
|    | ||||
|   // New method to update calculated fields after adding group by configuration
 | ||||
|   updateCalculatedFieldsAfterGroupBy() { | ||||
|     if (!this.selectedDataLakeItem || this.calculatedFields.length === 0) { | ||||
|       return; | ||||
|     } | ||||
|      | ||||
|     // Convert calculated fields to JSON string
 | ||||
|     const calculatedFieldJson = JSON.stringify(this.calculatedFields); | ||||
|      | ||||
|     // Call the service method to update the record
 | ||||
|     this.mainService.updateCalculatedFields( | ||||
|       this.selectedDataLakeItem.id,  | ||||
|       calculatedFieldJson,  | ||||
|       true // iscalculatedfield = true
 | ||||
|     ).subscribe( | ||||
|       (response) => { | ||||
|         console.log('Calculated fields updated successfully:', response); | ||||
|         this.toastr.success('Group by configuration saved successfully'); | ||||
|          | ||||
|         // Update the local data
 | ||||
|         const index = this.product.findIndex(item => item.id === this.selectedDataLakeItem.id); | ||||
|         if (index !== -1) { | ||||
|           this.product[index].calculated_field_json = calculatedFieldJson; | ||||
|           this.product[index].iscalculatedfield = true; | ||||
|         } | ||||
|       }, | ||||
|       (error) => { | ||||
|         console.error('Error updating calculated fields:', error); | ||||
|         this.toastr.error('Failed to save group by configuration'); | ||||
|       } | ||||
|     ); | ||||
|   } | ||||
|    | ||||
|   // Method to remove group by configuration
 | ||||
|   removeGroupByConfig(id: number) { | ||||
|     this.calculatedFields = this.calculatedFields.filter(field => field.id !== id || field.type !== 'groupby'); | ||||
|     this.toastr.success('Group by configuration removed'); | ||||
|   } | ||||
|    | ||||
|   // Method to check if a field is selected for group by
 | ||||
|   isGroupByFieldSelected(field: string): boolean { | ||||
|     return this.selectedGroupByFields.includes(field); | ||||
|   } | ||||
| 
 | ||||
|   // Helper method to get the count of calculated fields
 | ||||
|   getCalculatedFieldsCount(calculatedFieldJson: string): number { | ||||
|     try { | ||||
|       const fields = JSON.parse(calculatedFieldJson); | ||||
|       return Array.isArray(fields) ? fields.length : 0; | ||||
|     } catch (e) { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Helper method to get the count of group by configurations
 | ||||
|   getGroupByFieldsCount(groupByJson: string): number { | ||||
|     try { | ||||
|       const configs = JSON.parse(groupByJson); | ||||
|       return Array.isArray(configs) ? configs.length : 0; | ||||
|     } catch (e) { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Helper method to check if the selected data is JSON
 | ||||
|   isJsonData(data: any): boolean { | ||||
|     if (!data) return false; | ||||
|      | ||||
|     try { | ||||
|       const parsed = typeof data === 'string' ? JSON.parse(data) : data; | ||||
|       return Array.isArray(parsed) && parsed.length > 0; | ||||
|     } catch (e) { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Helper method to get JSON headers for grid columns
 | ||||
|   getJsonHeaders(data: any): string[] { | ||||
|     if (!this.isJsonData(data)) return []; | ||||
|      | ||||
|     try { | ||||
|       const parsed = typeof data === 'string' ? JSON.parse(data) : data; | ||||
|       if (Array.isArray(parsed) && parsed.length > 0) { | ||||
|         // Get all unique keys from the first few items
 | ||||
|         const headers = new Set<string>(); | ||||
|         const sampleItems = parsed.slice(0, 3); // Check first 3 items for headers
 | ||||
|          | ||||
|         sampleItems.forEach(item => { | ||||
|           if (typeof item === 'object' && item !== null) { | ||||
|             Object.keys(item).forEach(key => headers.add(key)); | ||||
|           } | ||||
|         }); | ||||
|          | ||||
|         return Array.from(headers); | ||||
|       } | ||||
|       return []; | ||||
|     } catch (e) { | ||||
|       return []; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Helper method to get JSON data for grid rows
 | ||||
|   getJsonData(data: any): any[] { | ||||
|     if (!this.isJsonData(data)) return []; | ||||
|      | ||||
|     try { | ||||
|       return typeof data === 'string' ? JSON.parse(data) : data; | ||||
|     } catch (e) { | ||||
|       return []; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user