From 56e1e3b0fe2953c4e41e6a60ee2714863fc52ec8 Mon Sep 17 00:00:00 2001 From: Gaurav Kumar Date: Sat, 18 Oct 2025 18:22:00 +0530 Subject: [PATCH] aggregation --- .../Data_lake/Data_lake.component.html | 421 ++++++++++++------ .../Data_lake/Data_lake.component.scss | 91 +++- .../Data_lake/Data_lake.component.ts | 217 ++++++++- 3 files changed, 589 insertions(+), 140 deletions(-) diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.html index d25241e..506a5d4 100644 --- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.html +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.html @@ -17,145 +17,181 @@ - - - - Loading ... - -
{{error}}
-
+ +
+ + + + Loading ... + +
{{error}}
+
- Name - + Name + - Url - + Url + + + Url Endpoint + + + schedule + - schedule - + cron job + - cron job - + json + + + + + Group By JSON + - json - + + Batch Volume + + + + SureConnect + + + + Calculated Fields + - Url Endpoint - - - Batch Volume - - - SureConnect - - - - Calculated Fields - - - - - - Action - - - - - - {{user.name }} - - - {{user.url}} - - - {{user.schedule }} - - - {{user.cron_job }} - - - - - - -
- - {{user.url | slice:0:30}}{{user.url.length > 30 ? '...' : ''}} - - -
-
- {{user.batch_volume}} - - {{user.sureconnect_name}} - - - - - - -
Who Column
-
Account ID: {{user.accountId}}
-
Created At: {{user.createdAt| date}}
-
Created By: {{user.createdBy}}
-
Updated At: {{user.updatedAt | date}}
-
Updated By: {{user.updatedBy}}
-
-
+ + + Action + + - - + - - -
+ {{user.name }} - - + +
+ + {{user.url | slice:0:30}}{{user.url.length > 30 ? '...' : ''}} + + +
+
- - - - -
- - - Users per page - {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} - of {{pagination.totalItems}} users - - -
+ + +
+ + {{user.url | slice:0:30}}{{user.url_endpoint.length > 30 ? '...' : ''}} + + +
+
+ + {{user.schedule }} + + + {{user.cron_job }} + + + + + + + + + {{user.batch_volume}} + + {{user.sureconnect_name}} + + + + + + + +
+ + + +
Who Column
+
Account ID: {{user.accountId}}
+
Created At: {{user.createdAt| date}}
+
Created By: {{user.createdBy}}
+
Updated At: {{user.updatedAt | date}}
+
Updated By: {{user.updatedBy}}
+
+
+ + + + + + + + + +
+
+ + + + + + + + + + + + + Users per page + {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} + of {{pagination.totalItems}} users + + + +
+
+ + + + + + \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.scss index d33d645..e638025 100644 --- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.scss +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.scss @@ -294,4 +294,93 @@ .constant-input-container { margin-bottom: 8px; } -} \ No newline at end of file +} + +/* 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; +} diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.ts index d65d619..ac4cc80 100644 --- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.ts +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/Data_lake/Data_lake.component.ts @@ -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 - this.calculatedFieldModalOpen = false; + // 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(); + 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 []; + } + } }