data lake
This commit is contained in:
		
							parent
							
								
									251bc56428
								
							
						
					
					
						commit
						7f80ea6330
					
				| @ -51,15 +51,17 @@ | |||||||
| 
 | 
 | ||||||
|       <clr-dg-column [clrDgField]="'batch_volume'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Batch Volume |       <clr-dg-column [clrDgField]="'batch_volume'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Batch Volume | ||||||
|         </ng-container></clr-dg-column> |         </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> |         </ng-container></clr-dg-column> | ||||||
|          | 
 | ||||||
|       <clr-dg-column [clrDgField]="'calculated_field_json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Calculated Fields |       <clr-dg-column [clrDgField]="'calculated_field_json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||||
|  |           Calculated Fields | ||||||
|         </ng-container></clr-dg-column> |         </ng-container></clr-dg-column> | ||||||
| 
 | 
 | ||||||
|       <!-- who column --> |       <!-- who column --> | ||||||
|       <clr-dg-column> <ng-container *clrDgHideableColumn="{hidden: false}"> |       <clr-dg-column> | ||||||
|  |         <ng-container *clrDgHideableColumn="{hidden: false}"> | ||||||
|           <clr-icon shape="bars"></clr-icon> Action |           <clr-icon shape="bars"></clr-icon> Action | ||||||
|         </ng-container></clr-dg-column> |         </ng-container></clr-dg-column> | ||||||
|       <!-- end --> |       <!-- end --> | ||||||
| @ -96,11 +98,12 @@ | |||||||
|           </div> |           </div> | ||||||
|         </clr-dg-cell> |         </clr-dg-cell> | ||||||
|         <clr-dg-cell>{{user.batch_volume}}</clr-dg-cell> |         <clr-dg-cell>{{user.batch_volume}}</clr-dg-cell> | ||||||
|          | 
 | ||||||
|         <clr-dg-cell>{{user.sureconnect_name}}</clr-dg-cell> |         <clr-dg-cell>{{user.sureconnect_name}}</clr-dg-cell> | ||||||
|          | 
 | ||||||
|         <clr-dg-cell (click)="goToReplaceStringjson(user.calculated_field_json)" style="cursor: pointer; align-items: center;"><clr-icon |         <clr-dg-cell (click)="goToReplaceStringjson(user.calculated_field_json)" | ||||||
|             shape="details" *ngIf="user.calculated_field_json"></clr-icon></clr-dg-cell> |           style="cursor: pointer; align-items: center;"><clr-icon shape="details" | ||||||
|  |             *ngIf="user.calculated_field_json"></clr-icon></clr-dg-cell> | ||||||
| 
 | 
 | ||||||
|         <!-- who column --> |         <!-- who column --> | ||||||
|         <clr-dg-cell> |         <clr-dg-cell> | ||||||
| @ -165,7 +168,9 @@ | |||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </ng-template><ng-container *ngIf="isCardview"> |   </ng-template> | ||||||
|  | 
 | ||||||
|  |   <ng-container *ngIf="isCardview"> | ||||||
|     <div *ngIf="product; else showInfo" class="clr-row clr-align-items-start clr-justify-content-start"> |     <div *ngIf="product; else showInfo" class="clr-row clr-align-items-start clr-justify-content-start"> | ||||||
|       <div *ngFor="let app of product| filter:search; let index = i" class="clr-col-auto"> |       <div *ngFor="let app of product| filter:search; let index = i" class="clr-col-auto"> | ||||||
|         <div class="clr-row"> |         <div class="clr-row"> | ||||||
| @ -227,6 +232,7 @@ | |||||||
|                       {{afterText(item.fieldtext)}} |                       {{afterText(item.fieldtext)}} | ||||||
|                     </div> |                     </div> | ||||||
| 
 | 
 | ||||||
|  |                     | ||||||
|                     <div *ngIf="item.name === 'Line'" class="title-card card-title" |                     <div *ngIf="item.name === 'Line'" class="title-card card-title" | ||||||
|                       [style.text-align]="item.alignment !== '' ? item.alignment : 'left'" |                       [style.text-align]="item.alignment !== '' ? item.alignment : 'left'" | ||||||
|                       [style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'" |                       [style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'" | ||||||
| @ -240,8 +246,7 @@ | |||||||
|                       <hr> |                       <hr> | ||||||
|                     </div> |                     </div> | ||||||
| 
 | 
 | ||||||
| 
 |  <div *ngIf="item.name === 'Icon'" class="icon-card" | ||||||
|                     <div *ngIf="item.name === 'Icon'" class="icon-card" |  | ||||||
|                       [style.text-align]="item.alignment !== '' ? item.alignment : 'left'" |                       [style.text-align]="item.alignment !== '' ? item.alignment : 'left'" | ||||||
|                       [style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'" |                       [style.line-height]="item.textlineheight !== '' ? item.textlineheight : '1'" | ||||||
|                       [style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'" |                       [style.font-family]="item.fontName !== '' ? item.fontName : 'Metropolis'" | ||||||
| @ -282,16 +287,6 @@ | |||||||
| </div> | </div> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| <clr-modal [(clrModalOpen)]="rsModaljson" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true"> | <clr-modal [(clrModalOpen)]="rsModaljson" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true"> | ||||||
|   <div class="modal-body"> |   <div class="modal-body"> | ||||||
|     <textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea> |     <textarea class="form-control" style="width:100%; height: 400px;" readonly>{{rowSelected}}</textarea> | ||||||
| @ -474,7 +469,7 @@ | |||||||
| 
 | 
 | ||||||
|         <div class="clr-col-sm-12"> |         <div class="clr-col-sm-12"> | ||||||
|           <label>SureConnect</label> |           <label>SureConnect</label> | ||||||
|           <select  formControlName="sure_connect_id"> |           <select formControlName="sure_connect_id"> | ||||||
|             <option value="">Select SureConnect</option> |             <option value="">Select SureConnect</option> | ||||||
|             <option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.connection_name}} |             <option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.connection_name}} | ||||||
|             </option> |             </option> | ||||||
| @ -522,21 +517,27 @@ | |||||||
|   <div class="modal-body"> |   <div class="modal-body"> | ||||||
|     <form [formGroup]="calculatedFieldForm"> |     <form [formGroup]="calculatedFieldForm"> | ||||||
|       <div class="clr-row"> |       <div class="clr-row"> | ||||||
|         <div class="clr-col-12"> |         <div class="clr-col-12 calculated-section"> | ||||||
|           <h4>Available Keys from API:</h4> |           <h4 class="section-title"> | ||||||
|           <ul> |             <clr-icon shape="key" class="section-icon"></clr-icon> | ||||||
|             <li *ngFor="let key of availableKeys">{{ key }}</li> |             Available Keys from API | ||||||
|           </ul> |           </h4> | ||||||
|  |           <div class="field-container"> | ||||||
|  |             <span *ngFor="let key of availableKeys" class="field-tag" (click)="addFieldToEquation(key)"> | ||||||
|  |               <clr-icon shape="data-field" class="field-icon"></clr-icon> | ||||||
|  |               {{ key }} | ||||||
|  |             </span> | ||||||
|  |           </div> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="clr-col-12"> |         <div class="clr-col-12 calculated-section"> | ||||||
|           <label>Calculated Field Name</label> |           <label class="field-label">Calculated Field Name</label> | ||||||
|           <input class="clr-input" type="text" formControlName="fieldName" placeholder="Enter field name" /> |           <input class="clr-input field-input" type="text" formControlName="fieldName" placeholder="Enter field name" /> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="clr-col-12"> |         <div class="clr-col-12 calculated-section"> | ||||||
|           <label>Operation</label> |           <label class="field-label">Operation</label> | ||||||
|           <select formControlName="operation"> |           <select class="field-input" formControlName="operation"> | ||||||
|             <option value="">Select Operation</option> |             <option value="">Select Operation</option> | ||||||
|             <option value="add">Addition (+)</option> |             <option value="add">Addition (+)</option> | ||||||
|             <option value="subtract">Subtraction (-)</option> |             <option value="subtract">Subtraction (-)</option> | ||||||
| @ -544,88 +545,193 @@ | |||||||
|             <option value="divide">Division (/)</option> |             <option value="divide">Division (/)</option> | ||||||
|             <option value="percentage">Percentage (%)</option> |             <option value="percentage">Percentage (%)</option> | ||||||
|             <option value="concat">Concatenation (||)</option> |             <option value="concat">Concatenation (||)</option> | ||||||
|  |             <option value="complex">Complex Equation</option> | ||||||
|           </select> |           </select> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|  |         <!-- Complex Equation Section --> | ||||||
|  |         <div class="clr-col-12 calculated-section" *ngIf="calculatedFieldForm.get('operation')?.value === 'complex'"> | ||||||
|  |           <label class="field-label">Complex Equation</label> | ||||||
|  |           <textarea class="clr-textarea equation-input" formControlName="complexEquation" | ||||||
|  |             placeholder="Enter complex equation using actual field names" rows="3"></textarea> | ||||||
|  |           <small class="clr-subtext equation-hint"> | ||||||
|  |             Use actual field names from the available keys list above, or predefined constants (constant_X). | ||||||
|  |             Example: (field1 + field2) * constant_1 - (field3 / field4) | ||||||
|  |           </small> | ||||||
|  | 
 | ||||||
|  |           <!-- Available Operators --> | ||||||
|  |           <div class="operators-container"> | ||||||
|  |             <h5 class="subsection-title"> | ||||||
|  |               <clr-icon shape="calculator" class="subsection-icon"></clr-icon> | ||||||
|  |               Available Operators | ||||||
|  |             </h5> | ||||||
|  |             <div class="operator-tags"> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('+')">+</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('-')">-</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('*')">×</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('/')">÷</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('(')">(</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation(')')">)</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('[')">[</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation(']')">]</span> | ||||||
|  |               <!-- <span class="operator-tag" (click)="addOperatorToEquation('{')">{</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('}')">}</span> --> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('^')">^</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('%')">%</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('=')">=</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('>')">></span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('<')"><</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('>=')">>=</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('<=')"><=</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('!=')">!=</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('&&')">&&</span> | ||||||
|  |               <span class="operator-tag" (click)="addOperatorToEquation('||')">||</span> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  | 
 | ||||||
|  |           <!-- Available Fields --> | ||||||
|  |           <div class="fields-container"> | ||||||
|  |             <h5 class="subsection-title"> | ||||||
|  |               <clr-icon shape="data-field" class="subsection-icon"></clr-icon> | ||||||
|  |               Available Fields | ||||||
|  |             </h5> | ||||||
|  |             <div class="field-tags"> | ||||||
|  |               <span *ngFor="let key of availableKeys" class="field-tag" (click)="addFieldToEquation(key)"> | ||||||
|  |                 <clr-icon shape="data-field" class="field-icon"></clr-icon> | ||||||
|  |                 {{ key }} | ||||||
|  |               </span> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  | 
 | ||||||
|  |           <!-- Defined Constants --> | ||||||
|  |           <div class="constants-container" *ngIf="getDefinedConstants().length > 0"> | ||||||
|  |             <h5 class="subsection-title"> | ||||||
|  |               <clr-icon shape="pin" class="subsection-icon"></clr-icon> | ||||||
|  |               Defined Constants | ||||||
|  |             </h5> | ||||||
|  |             <div class="constant-tags"> | ||||||
|  |               <span *ngFor="let constant of getDefinedConstants()" class="constant-tag" | ||||||
|  |                 (click)="addFieldToEquation(constant)"> | ||||||
|  |                 <clr-icon shape="pin" class="constant-icon"></clr-icon> | ||||||
|  |                 {{ constant }} | ||||||
|  |               </span> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  | 
 | ||||||
|  |           <!-- Add New Constant --> | ||||||
|  |           <div class="new-constant-container"> | ||||||
|  |             <button class="btn btn-sm btn-secondary add-constant-btn" (click)="addNewConstantToEquation()"> | ||||||
|  |               <clr-icon shape="plus"></clr-icon> Add New Constant | ||||||
|  |             </button> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  | 
 | ||||||
|         <!-- Multiple Fields Section --> |         <!-- Multiple Fields Section --> | ||||||
|         <div class="clr-col-12" *ngIf="calculatedFieldForm.get('operation')?.value"> |         <div class="clr-col-12 calculated-section" | ||||||
|           <label>Fields and Constants</label> |           *ngIf="calculatedFieldForm.get('operation')?.value && calculatedFieldForm.get('operation')?.value !== 'complex'"> | ||||||
|           <div class="clr-row"> |           <label class="field-label">Fields and Constants</label> | ||||||
|             <div class="clr-col-12"> |           <div class="field-components-container"> | ||||||
|               <div formArrayName="fieldComponents"> |             <div formArrayName="fieldComponents"> | ||||||
|                 <div *ngFor="let fieldComponent of getFieldComponents().controls; let i = index"  |               <div *ngFor="let fieldComponent of getFieldComponents().controls; let i = index" [formGroupName]="i" | ||||||
|                      [formGroupName]="i" class="clr-row field-component-row"> |                 class="field-component-row"> | ||||||
|                   <div class="clr-col-5"> |                 <div class="field-select-container"> | ||||||
|                     <select formControlName="field"> |                   <select class="field-select" formControlName="field"> | ||||||
|                       <option value="">Select Field</option> |                     <option value="">Select Field</option> | ||||||
|                       <option *ngFor="let key of availableKeys" [value]="key">{{ key }}</option> |                     <option *ngFor="let key of availableKeys" [value]="key">{{ key }}</option> | ||||||
|                     </select> |                   </select> | ||||||
|                   </div> |                 </div> | ||||||
|                   <div class="clr-col-5"> |                 <div class="constant-input-container"> | ||||||
|                     <input type="text" formControlName="constant" placeholder="Or enter constant value" /> |                   <input type="text" class="constant-input" formControlName="constant" placeholder="Or enter constant value" /> | ||||||
|                   </div> |                 </div> | ||||||
|                   <div class="clr-col-2"> |                 <div class="remove-btn-container"> | ||||||
|                     <button type="button" class="btn btn-icon btn-danger" (click)="removeFieldComponent(i)"  |                   <button type="button" class="btn btn-icon btn-danger remove-field-btn" (click)="removeFieldComponent(i)" | ||||||
|                             *ngIf="getFieldComponents().length > 1"> |                     *ngIf="getFieldComponents().length > 1"> | ||||||
|                       <clr-icon shape="trash"></clr-icon> |                     <clr-icon shape="trash"></clr-icon> | ||||||
|                     </button> |                   </button> | ||||||
|                   </div> |  | ||||||
|                 </div> |                 </div> | ||||||
|               </div> |               </div> | ||||||
|               <button type="button" class="btn btn-sm" (click)="addFieldComponent()"> |  | ||||||
|                 <clr-icon shape="plus"></clr-icon> Add Field/Constant |  | ||||||
|               </button> |  | ||||||
|             </div> |             </div> | ||||||
|  |             <button type="button" class="btn btn-sm add-field-btn" (click)="addFieldComponent()"> | ||||||
|  |               <clr-icon shape="plus"></clr-icon> Add Field/Constant | ||||||
|  |             </button> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </form> |     </form> | ||||||
| 
 | 
 | ||||||
|     <div class="clr-row" style="margin-top: 20px;"> |     <div class="clr-row created-fields-section"> | ||||||
|       <div class="clr-col-12"> |       <div class="clr-col-12"> | ||||||
|         <h4>Created Calculated Fields:</h4> |         <h4 class="section-title"> | ||||||
|         <table class="table"> |           <clr-icon shape="list" class="section-icon"></clr-icon> | ||||||
|           <thead> |           Created Calculated Fields | ||||||
|             <tr> |         </h4> | ||||||
|               <th>Field Name</th> |         <div class="table-container"> | ||||||
|               <th>Operation</th> |           <table class="table calculated-fields-table"> | ||||||
|               <th>Fields/Values</th> |             <thead> | ||||||
|               <th>Actions</th> |               <tr> | ||||||
|             </tr> |                 <th>Field Name</th> | ||||||
|           </thead> |                 <th>Operation</th> | ||||||
|           <tbody> |                 <th>Fields/Values</th> | ||||||
|             <tr *ngFor="let field of calculatedFields"> |                 <th>Actions</th> | ||||||
|               <td>{{ field.fieldName }}</td> |               </tr> | ||||||
|               <td>{{ field.operation }}</td> |             </thead> | ||||||
|               <td> |             <tbody> | ||||||
|                 <span *ngFor="let component of field.fieldComponents; let last = last"> |               <tr *ngFor="let field of calculatedFields"> | ||||||
|                   <span *ngIf="component.field && !component.isConstant">{{ component.field }}</span> |                 <td class="field-name-cell">{{ field.fieldName }}</td> | ||||||
|                   <span *ngIf="component.isConstant">"{{ component.constant }}"</span> |                 <td class="operation-cell">{{ field.operation }}</td> | ||||||
|                   <span *ngIf="!component.field && component.constant">"{{ component.constant }}"</span> |                 <td class="expression-cell"> | ||||||
|                   <span *ngIf="!last"> {{ getOperationSymbol(field.operation) }} </span> |                   <span *ngIf="field.operation === 'complex'">{{ field.complexEquation }}</span> | ||||||
|                 </span> |                   <span *ngIf="field.operation !== 'complex'"> | ||||||
|               </td> |                     <span *ngFor="let component of field.fieldComponents; let last = last"> | ||||||
|               <td> |                       <span *ngIf="component.field && !component.isConstant">{{ component.field }}</span> | ||||||
|                 <button class="btn btn-icon btn-danger" (click)="deleteCalculatedField(field.id)"> |                       <span *ngIf="component.isConstant">"{{ component.constant }}"</span> | ||||||
|                   <clr-icon shape="trash"></clr-icon> |                       <span *ngIf="!component.field && component.constant">"{{ component.constant }}"</span> | ||||||
|                 </button> |                       <span *ngIf="!last"> {{ getOperationSymbol(field.operation) }} </span> | ||||||
|               </td> |                     </span> | ||||||
|             </tr> |                   </span> | ||||||
|           </tbody> |                 </td> | ||||||
|         </table> |                 <td class="actions-cell"> | ||||||
|  |                   <button class="btn btn-icon btn-danger delete-field-btn" (click)="deleteCalculatedField(field.id)"> | ||||||
|  |                     <clr-icon shape="trash"></clr-icon> | ||||||
|  |                   </button> | ||||||
|  |                 </td> | ||||||
|  |               </tr> | ||||||
|  |             </tbody> | ||||||
|  |           </table> | ||||||
|  |         </div> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   </div> |   </div> | ||||||
|   <div class="modal-footer"> |   <div class="modal-footer"> | ||||||
|     <button type="button" class="btn btn-outline" (click)="calculatedFieldModalOpen = false">Cancel</button> |     <button type="button" class="btn btn-outline" (click)="calculatedFieldModalOpen = false">Cancel</button> | ||||||
|     <button type="button" class="btn btn-primary" (click)="addCalculatedField()">Add Field</button> |     <button type="button" class="btn btn-primary" (click)="addCalculatedField()">Add Field</button> | ||||||
|     <button type="button" class="btn btn-success" (click)="updateCalculatedFields()"  |     <button type="button" class="btn btn-success" (click)="updateCalculatedFields()" | ||||||
|             [disabled]="calculatedFields.length === 0"> |       [disabled]="calculatedFields.length === 0"> | ||||||
|       Update Record |       Update Record | ||||||
|     </button> |     </button> | ||||||
|   </div> |   </div> | ||||||
| </clr-modal> | </clr-modal> | ||||||
| 
 | 
 | ||||||
|  | <!-- Constant Value Modal --> | ||||||
|  | <clr-modal [(clrModalOpen)]="constantValueModalOpen" [clrModalSize]="'sm'" [clrModalStaticBackdrop]="true"> | ||||||
|  |   <h3 class="modal-title">Define Constant Value</h3> | ||||||
|  |   <div class="modal-body"> | ||||||
|  |     <div class="clr-row"> | ||||||
|  |       <div class="clr-col-12"> | ||||||
|  |         <p>Enter a value for constant: <strong>{{ currentConstantName }}</strong></p> | ||||||
|  |       </div> | ||||||
|  |       <div class="clr-col-12"> | ||||||
|  |         <label>Constant Value</label> | ||||||
|  |         <input class="clr-input" type="text" [(ngModel)]="currentConstantValue" placeholder="Enter constant value" /> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  |   <div class="modal-footer"> | ||||||
|  |     <button type="button" class="btn btn-outline" (click)="cancelConstantValue()">Cancel</button> | ||||||
|  |     <button type="button" class="btn btn-primary" (click)="saveConstantValue()">Save</button> | ||||||
|  |   </div> | ||||||
|  | </clr-modal> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,85 +1,297 @@ | |||||||
| //@import "../../../../assets/scss/var"; | /* Calculated Fields Modal Styles */ | ||||||
| .s-info-bar { | 
 | ||||||
|   display: flex; | .calculated-section { | ||||||
|   flex-direction: row; |   margin-bottom: 20px; | ||||||
|   justify-content: space-between; |   padding: 15px; | ||||||
|   button { |   border-radius: 8px; | ||||||
|     outline: none; |   background-color: #f9f9f9; | ||||||
|   } |   box-shadow: 0 2px 4px rgba(0,0,0,0.05); | ||||||
| } |  | ||||||
| .delete,.heading{ |  | ||||||
|   text-align: center; |  | ||||||
|   color: red; |  | ||||||
| } |  | ||||||
| .entry-pg { |  | ||||||
|   width: 750px; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .button1::after { | .section-title { | ||||||
|   content: none; |   color: #0072a0; | ||||||
| } |  | ||||||
| .button1:hover::after { |  | ||||||
|   content: "ADD ROWS"; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .section { |  | ||||||
|   background-color: #dddddd; |  | ||||||
|   height: 40px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .section p { |  | ||||||
|   //color: white; |  | ||||||
|   padding: 10px; |  | ||||||
|   font-size: 18px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .clr-input { |  | ||||||
|   color: #212529; |  | ||||||
|   border: 1px solid #ced4da; |  | ||||||
|   border-radius: 0.25rem; |  | ||||||
|   padding: 0.75rem 0.75rem; |  | ||||||
|   margin-top: 3px; |  | ||||||
|   width: 100%; |  | ||||||
|   margin-bottom: 10px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .clr-file { |  | ||||||
|   color: #212529; |  | ||||||
|   border: 1px solid #ced4da; |  | ||||||
|   border-radius: 0.25rem; |  | ||||||
|   //padding: 0.6rem 0.75rem; |  | ||||||
|   margin-top: 3px; |  | ||||||
|   width: 100%; |  | ||||||
|   margin-bottom: 10px; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .center { |  | ||||||
|   text-align: center; |  | ||||||
| } |  | ||||||
| select{ |  | ||||||
|   width: 100%; |  | ||||||
|   margin-top: 3px; |  | ||||||
|   padding: 5px 5px; |  | ||||||
|   border: 1px solid #ccc; |  | ||||||
|   border-radius: 4px; |  | ||||||
| } |  | ||||||
| input[type=text],[type=date],[type=number],textarea { |  | ||||||
|   width: 100%; |  | ||||||
|   padding: 15px 15px; |  | ||||||
|   background-color:rgb(255, 255, 255); |  | ||||||
|  // margin: 8px 0; |  | ||||||
|   display: inline-block; |  | ||||||
|   border: 1px solid #ccc; |  | ||||||
|   border-radius: 4px; |  | ||||||
|   box-sizing: border-box; |  | ||||||
| } |  | ||||||
| .error_mess { |  | ||||||
|   color: red; |  | ||||||
| } |  | ||||||
| .universal-section-header { |  | ||||||
|   margin: 24px 0 10px 0; |  | ||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
|   color: #1a237e; |   margin-bottom: 15px; | ||||||
|   letter-spacing: 0.5px; |   display: flex; | ||||||
|   font-size: 1.25rem; |   align-items: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .section-icon { | ||||||
|  |   margin-right: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-label { | ||||||
|  |   display: block; | ||||||
|  |   margin-bottom: 8px; | ||||||
|  |   font-weight: 500; | ||||||
|  |   color: #333; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-input { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 10px; | ||||||
|  |   border: 1px solid #ccc; | ||||||
|  |   border-radius: 4px; | ||||||
|  |   font-size: 14px; | ||||||
|  |   transition: border-color 0.3s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-input:focus { | ||||||
|  |   border-color: #0072a0; | ||||||
|  |   outline: none; | ||||||
|  |   box-shadow: 0 0 0 2px rgba(0, 114, 160, 0.2); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .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-icon { | ||||||
|  |   margin-right: 5px; | ||||||
|  |   color: #1976d2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .equation-input { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 12px; | ||||||
|  |   border: 1px solid #ccc; | ||||||
|  |   border-radius: 6px; | ||||||
|  |   font-family: monospace; | ||||||
|  |   font-size: 14px; | ||||||
|  |   margin-bottom: 8px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .equation-hint { | ||||||
|  |   display: block; | ||||||
|  |   margin-bottom: 15px; | ||||||
|  |   color: #666; | ||||||
|  |   font-style: italic; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .operators-container, | ||||||
|  | .fields-container, | ||||||
|  | .constants-container, | ||||||
|  | .new-constant-container { | ||||||
|  |   margin-bottom: 20px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .subsection-title { | ||||||
|  |   color: #555; | ||||||
|  |   font-weight: 500; | ||||||
|  |   margin-bottom: 10px; | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .subsection-icon { | ||||||
|  |   margin-right: 8px; | ||||||
|  |   color: #0072a0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .operator-tags { | ||||||
|  |   display: flex; | ||||||
|  |   flex-wrap: wrap; | ||||||
|  |   gap: 6px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .operator-tag { | ||||||
|  |   display: inline-flex; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   background-color: #0072a0; | ||||||
|  |   color: white; | ||||||
|  |   border: 1px solid #005a80; | ||||||
|  |   border-radius: 4px; | ||||||
|  |   padding: 6px 10px; | ||||||
|  |   font-size: 14px; | ||||||
|  |   font-family: monospace; | ||||||
|  |   cursor: pointer; | ||||||
|  |   transition: all 0.2s; | ||||||
|  |   min-width: 36px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .operator-tag:hover { | ||||||
|  |   background-color: #005a80; | ||||||
|  |   transform: scale(1.1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-tags { | ||||||
|  |   display: flex; | ||||||
|  |   flex-wrap: wrap; | ||||||
|  |   gap: 6px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .constant-tags { | ||||||
|  |   display: flex; | ||||||
|  |   flex-wrap: wrap; | ||||||
|  |   gap: 6px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .constant-tag { | ||||||
|  |   display: inline-flex; | ||||||
|  |   align-items: center; | ||||||
|  |   background-color: #4caf50; | ||||||
|  |   color: white; | ||||||
|  |   border: 1px solid #388e3c; | ||||||
|  |   border-radius: 20px; | ||||||
|  |   padding: 6px 12px; | ||||||
|  |   margin: 4px; | ||||||
|  |   font-size: 13px; | ||||||
|  |   font-family: monospace; | ||||||
|  |   cursor: pointer; | ||||||
|  |   transition: all 0.2s; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .constant-tag:hover { | ||||||
|  |   background-color: #388e3c; | ||||||
|  |   transform: translateY(-2px); | ||||||
|  |   box-shadow: 0 2px 4px rgba(0,0,0,0.1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .constant-icon { | ||||||
|  |   margin-right: 5px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .add-constant-btn { | ||||||
|  |   background-color: #ff9800; | ||||||
|  |   border-color: #f57c00; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .add-constant-btn:hover { | ||||||
|  |   background-color: #f57c00; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-components-container { | ||||||
|  |   background-color: white; | ||||||
|  |   border: 1px solid #e0e0e0; | ||||||
|  |   border-radius: 6px; | ||||||
|  |   padding: 15px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-component-row { | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   margin-bottom: 10px; | ||||||
|  |   gap: 10px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-select-container, | ||||||
|  | .constant-input-container { | ||||||
|  |   flex: 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-select, | ||||||
|  | .constant-input { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 8px; | ||||||
|  |   border: 1px solid #ccc; | ||||||
|  |   border-radius: 4px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .remove-field-btn { | ||||||
|  |   padding: 6px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .add-field-btn { | ||||||
|  |   margin-top: 10px; | ||||||
|  |   background-color: #1976d2; | ||||||
|  |   border-color: #1976d2; | ||||||
|  |   color: white; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .add-field-btn:hover { | ||||||
|  |   background-color: #1565c0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .created-fields-section { | ||||||
|  |   margin-top: 25px; | ||||||
|  |   padding-top: 20px; | ||||||
|  |   border-top: 1px solid #eee; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .table-container { | ||||||
|  |   overflow-x: auto; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .calculated-fields-table { | ||||||
|  |   width: 100%; | ||||||
|  |   border-collapse: collapse; | ||||||
|  |   box-shadow: 0 1px 3px rgba(0,0,0,0.1); | ||||||
|  |   border-radius: 6px; | ||||||
|  |   overflow: hidden; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .calculated-fields-table th { | ||||||
|  |   background-color: #f5f5f5; | ||||||
|  |   padding: 12px 15px; | ||||||
|  |   text-align: left; | ||||||
|  |   font-weight: 600; | ||||||
|  |   color: #333; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .calculated-fields-table td { | ||||||
|  |   padding: 12px 15px; | ||||||
|  |   border-bottom: 1px solid #eee; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .field-name-cell { | ||||||
|  |   font-weight: 500; | ||||||
|  |   color: #0072a0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .operation-cell { | ||||||
|  |   font-family: monospace; | ||||||
|  |   background-color: #e3f2fd; | ||||||
|  |   border-radius: 4px; | ||||||
|  |   padding: 4px 8px; | ||||||
|  |   display: inline-block; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .expression-cell { | ||||||
|  |   font-family: monospace; | ||||||
|  |   font-size: 13px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .actions-cell { | ||||||
|  |   text-align: center; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .delete-field-btn { | ||||||
|  |   padding: 6px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Responsive adjustments */ | ||||||
|  | @media (max-width: 768px) { | ||||||
|  |   .field-component-row { | ||||||
|  |     flex-direction: column; | ||||||
|  |     align-items: stretch; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   .field-select-container, | ||||||
|  |   .constant-input-container { | ||||||
|  |     margin-bottom: 8px; | ||||||
|  |   } | ||||||
| } | } | ||||||
| @ -70,6 +70,12 @@ export class Data_lakeComponent implements OnInit { | |||||||
|   calculatedFields: any[] = []; |   calculatedFields: any[] = []; | ||||||
|   constantCounter = 1; // Persistent counter for unique constant names
 |   constantCounter = 1; // Persistent counter for unique constant names
 | ||||||
| 
 | 
 | ||||||
|  |   // New properties for constant value input
 | ||||||
|  |   constantValueModalOpen = false; | ||||||
|  |   currentConstantName = ''; | ||||||
|  |   currentConstantValue = ''; | ||||||
|  |   pendingEquationUpdate = ''; | ||||||
|  |    | ||||||
|   constructor( |   constructor( | ||||||
|     private extensionService: ExtensionService, |     private extensionService: ExtensionService, | ||||||
|     private userInfoService: UserInfoService, |     private userInfoService: UserInfoService, | ||||||
| @ -136,8 +142,16 @@ export class Data_lakeComponent implements OnInit { | |||||||
|     this.calculatedFieldForm = this._fb.group({ |     this.calculatedFieldForm = this._fb.group({ | ||||||
|       fieldName: [''], |       fieldName: [''], | ||||||
|       operation: [''], |       operation: [''], | ||||||
|  |       complexEquation: [''], // Add complex equation field
 | ||||||
|       fieldComponents: this._fb.array([this.createFieldComponent()]) |       fieldComponents: this._fb.array([this.createFieldComponent()]) | ||||||
|     }); |     }); | ||||||
|  |      | ||||||
|  |     // Add real-time validation for complex equation
 | ||||||
|  |     this.calculatedFieldForm.get('complexEquation')?.valueChanges.subscribe(value => { | ||||||
|  |       if (this.calculatedFieldForm.get('operation')?.value === 'complex' && value) { | ||||||
|  |         this.analyzeComplexEquation(value); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   // Helper method to create a field component group
 |   // Helper method to create a field component group
 | ||||||
| @ -241,6 +255,7 @@ export class Data_lakeComponent implements OnInit { | |||||||
|     this.calculatedFieldForm.reset({ |     this.calculatedFieldForm.reset({ | ||||||
|       fieldName: '', |       fieldName: '', | ||||||
|       operation: '', |       operation: '', | ||||||
|  |       complexEquation: '', | ||||||
|       fieldComponents: [{}] // Start with one empty field component
 |       fieldComponents: [{}] // Start with one empty field component
 | ||||||
|     }); |     }); | ||||||
|      |      | ||||||
| @ -257,11 +272,73 @@ export class Data_lakeComponent implements OnInit { | |||||||
|   addCalculatedField() { |   addCalculatedField() { | ||||||
|     const formData = this.calculatedFieldForm.value; |     const formData = this.calculatedFieldForm.value; | ||||||
| 
 | 
 | ||||||
|     if (!formData.fieldName || !formData.operation) { |     if (!formData.fieldName || (!formData.operation && formData.operation !== 'complex')) { | ||||||
|       this.toastr.error('Field name and operation are required'); |       this.toastr.error('Field name and operation are required'); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Handle complex equation separately
 | ||||||
|  |     if (formData.operation === 'complex') { | ||||||
|  |       if (!formData.complexEquation || formData.complexEquation.trim() === '') { | ||||||
|  |         this.toastr.error('Complex equation is required'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Validate complex equation format
 | ||||||
|  |       if (!this.validateComplexEquation(formData.complexEquation)) { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Extract constants used in the equation
 | ||||||
|  |       const fieldRefs = this.extractFieldReferences(formData.complexEquation); | ||||||
|  |       const equationConstants: any[] = []; | ||||||
|  |        | ||||||
|  |       for (const fieldRef of fieldRefs) { | ||||||
|  |         // Check if it's a constant (constant_X format)
 | ||||||
|  |         if (fieldRef.startsWith('constant_') && /^\d+$/.test(fieldRef.substring(9))) { | ||||||
|  |           // Find the constant value from existing calculated fields
 | ||||||
|  |           let constantValue = ''; | ||||||
|  |           for (const field of this.calculatedFields) { | ||||||
|  |             if (field.operation === 'constant' && field.fieldName === fieldRef) { | ||||||
|  |               if (field.fieldComponents && field.fieldComponents.length > 0) { | ||||||
|  |                 constantValue = field.fieldComponents[0].constant; | ||||||
|  |                 break; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |            | ||||||
|  |           if (constantValue) { | ||||||
|  |             equationConstants.push({ | ||||||
|  |               field: fieldRef, | ||||||
|  |               constant: constantValue, | ||||||
|  |               isConstant: true | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Create calculated field object for complex equation
 | ||||||
|  |       const calculatedField = { | ||||||
|  |         id: Date.now(), | ||||||
|  |         fieldName: formData.fieldName, | ||||||
|  |         operation: 'complex', | ||||||
|  |         complexEquation: formData.complexEquation, | ||||||
|  |         fieldComponents: equationConstants // Include constants used in the equation
 | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       this.calculatedFields.push(calculatedField); | ||||||
|  |       this.toastr.success('Complex calculated field added successfully'); | ||||||
|  | 
 | ||||||
|  |       // Reset form but keep one empty field component
 | ||||||
|  |       this.calculatedFieldForm.reset({ | ||||||
|  |         fieldName: '', | ||||||
|  |         operation: '', | ||||||
|  |         complexEquation: '', | ||||||
|  |         fieldComponents: [{}] | ||||||
|  |       }); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Filter out empty field components
 |     // Filter out empty field components
 | ||||||
|     const validFieldComponents = formData.fieldComponents.filter(component =>  |     const validFieldComponents = formData.fieldComponents.filter(component =>  | ||||||
|       component.field || component.constant |       component.field || component.constant | ||||||
| @ -281,9 +358,9 @@ export class Data_lakeComponent implements OnInit { | |||||||
|             this.toastr.error('Constant values must be numeric for this operation'); |             this.toastr.error('Constant values must be numeric for this operation'); | ||||||
|             return; |             return; | ||||||
|           } |           } | ||||||
|           } |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|  |     } | ||||||
|      |      | ||||||
|     // Validate that constant values are unique within this calculated field
 |     // Validate that constant values are unique within this calculated field
 | ||||||
|     const constantValues = validFieldComponents |     const constantValues = validFieldComponents | ||||||
| @ -328,10 +405,187 @@ export class Data_lakeComponent implements OnInit { | |||||||
|     this.calculatedFieldForm.reset({ |     this.calculatedFieldForm.reset({ | ||||||
|       fieldName: '', |       fieldName: '', | ||||||
|       operation: '', |       operation: '', | ||||||
|  |       complexEquation: '', | ||||||
|       fieldComponents: [{}] |       fieldComponents: [{}] | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   // Validate complex equation format
 | ||||||
|  |   validateComplexEquation(equation: string): boolean { | ||||||
|  |     // Updated validation to include additional operators
 | ||||||
|  |     const validPattern = /^[a-zA-Z0-9_+\-*/().\[\]{}^%>=<!&|\s]+$/; | ||||||
|  |     if (!validPattern.test(equation)) { | ||||||
|  |       this.toastr.error('Invalid complex equation format. Only alphanumeric characters, underscores, and operators (+, -, *, /, (, ), [, ], {, }, ^, %, =, >, <, !, &, |) are allowed.'); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Check for empty equation
 | ||||||
|  |     if (!equation || equation.trim() === '') { | ||||||
|  |       this.toastr.error('Complex equation cannot be empty'); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Extract all field/constant references from the equation
 | ||||||
|  |     const fieldRefs = this.extractFieldReferences(equation); | ||||||
|  |      | ||||||
|  |     // Validate each reference
 | ||||||
|  |     const invalidReferences: string[] = []; | ||||||
|  |     for (const fieldRef of fieldRefs) { | ||||||
|  |       // Skip if it's a direct numeric value
 | ||||||
|  |       if (!isNaN(Number(fieldRef))) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Check if it's a predefined constant (constant_X format)
 | ||||||
|  |       if (fieldRef.startsWith('constant_') && /^\d+$/.test(fieldRef.substring(9))) { | ||||||
|  |         // Check if this constant has been defined in previous calculated fields
 | ||||||
|  |         let constantFound = false; | ||||||
|  |         for (const field of this.calculatedFields) { | ||||||
|  |           if (field.operation === 'constant' && field.fieldName === fieldRef) { | ||||||
|  |             constantFound = true; | ||||||
|  |             break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if (!constantFound) { | ||||||
|  |           invalidReferences.push(`Referenced constant '${fieldRef}' has not been defined`); | ||||||
|  |         } | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Check if field exists in available keys
 | ||||||
|  |       if (!this.availableKeys.includes(fieldRef)) { | ||||||
|  |         invalidReferences.push(`Field '${fieldRef}' not found in available keys`); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Show all validation errors
 | ||||||
|  |     if (invalidReferences.length > 0) { | ||||||
|  |       invalidReferences.forEach(error => this.toastr.error(error)); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Try to parse the equation to check for basic syntax errors
 | ||||||
|  |     try { | ||||||
|  |       this.parseEquation(equation); | ||||||
|  |     } catch (error) { | ||||||
|  |       this.toastr.error(`Invalid equation syntax: ${error.message}`); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Additional validation for complex expressions
 | ||||||
|  |     this.analyzeComplexEquation(equation); | ||||||
|  |      | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Analyze complex equation and provide warnings
 | ||||||
|  |   analyzeComplexEquation(equation: string): void { | ||||||
|  |     // Check for potentially problematic patterns
 | ||||||
|  |     if (/[+\-*/]{3,}/.test(equation)) { | ||||||
|  |       this.toastr.warning('Equation contains multiple consecutive operators which may cause unexpected results'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check for unbalanced expressions
 | ||||||
|  |     const operators = equation.match(/[+\-*/]/g) || []; | ||||||
|  |     const operands = equation.match(/[a-zA-Z0-9_]+/g) || []; | ||||||
|  |      | ||||||
|  |     if (operators.length > 0 && operands.length === 0) { | ||||||
|  |       this.toastr.warning('Equation contains operators but no operands (fields or constants)'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check for division by zero patterns
 | ||||||
|  |     if (/\/\s*0(?!\d)/.test(equation)) { | ||||||
|  |       this.toastr.warning('Equation may contain division by zero'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check for excessive nesting
 | ||||||
|  |     let parenDepth = 0; | ||||||
|  |     let maxParenDepth = 0; | ||||||
|  |     for (const char of equation) { | ||||||
|  |       if (char === '(') { | ||||||
|  |         parenDepth++; | ||||||
|  |         maxParenDepth = Math.max(maxParenDepth, parenDepth); | ||||||
|  |       } else if (char === ')') { | ||||||
|  |         parenDepth--; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     if (maxParenDepth > 10) { | ||||||
|  |       this.toastr.warning('Equation has deep nesting which may affect performance'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check for repeated field usage
 | ||||||
|  |     const fieldRefs = this.extractFieldReferences(equation); | ||||||
|  |     const fieldCounts: {[key: string]: number} = {}; | ||||||
|  |     fieldRefs.forEach(field => { | ||||||
|  |       if (!isNaN(Number(field))) return; // Skip numbers
 | ||||||
|  |       fieldCounts[field] = (fieldCounts[field] || 0) + 1; | ||||||
|  |     }); | ||||||
|  |      | ||||||
|  |     Object.keys(fieldCounts).forEach(field => { | ||||||
|  |       if (fieldCounts[field] > 3) { | ||||||
|  |         this.toastr.warning(`Field '${field}' is used ${fieldCounts[field]} times in the equation`); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Extract field references from equation
 | ||||||
|  |   extractFieldReferences(equation: string): string[] { | ||||||
|  |     // Remove all operators and parentheses to isolate field names
 | ||||||
|  |     const cleanEquation = equation.replace(/[+\-*/()[\]{}^%>=<!&|\s]+/g, ' '); | ||||||
|  |     // Split by whitespace and filter out empty strings and numbers
 | ||||||
|  |     return cleanEquation.split(/\s+/).filter(token => token.length > 0); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Simple equation parser to check syntax (basic implementation)
 | ||||||
|  |   parseEquation(equation: string): void { | ||||||
|  |     // Remove spaces
 | ||||||
|  |     const cleanEquation = equation.replace(/\s/g, ''); | ||||||
|  |      | ||||||
|  |     // Check for balanced parentheses
 | ||||||
|  |     let parenCount = 0; | ||||||
|  |     for (const char of cleanEquation) { | ||||||
|  |       if (char === '(') parenCount++; | ||||||
|  |       if (char === ')') parenCount--; | ||||||
|  |       if (parenCount < 0) throw new Error('Mismatched parentheses'); | ||||||
|  |     } | ||||||
|  |     if (parenCount !== 0) throw new Error('Mismatched parentheses'); | ||||||
|  |      | ||||||
|  |     // Check for balanced square brackets
 | ||||||
|  |     let bracketCount = 0; | ||||||
|  |     for (const char of cleanEquation) { | ||||||
|  |       if (char === '[') bracketCount++; | ||||||
|  |       if (char === ']') bracketCount--; | ||||||
|  |       if (bracketCount < 0) throw new Error('Mismatched square brackets'); | ||||||
|  |     } | ||||||
|  |     if (bracketCount !== 0) throw new Error('Mismatched square brackets'); | ||||||
|  |      | ||||||
|  |     // Check for balanced curly braces
 | ||||||
|  |     let braceCount = 0; | ||||||
|  |     for (const char of cleanEquation) { | ||||||
|  |       if (char === '{') braceCount++; | ||||||
|  |       if (char === '}') braceCount--; | ||||||
|  |       if (braceCount < 0) throw new Error('Mismatched curly braces'); | ||||||
|  |     } | ||||||
|  |     if (braceCount !== 0) throw new Error('Mismatched curly braces'); | ||||||
|  |      | ||||||
|  |     // Check for invalid sequences
 | ||||||
|  |     if (/[+\-*/]{2,}/.test(cleanEquation)) { | ||||||
|  |       throw new Error('Invalid operator sequence'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check that equation doesn't start or end with an operator (except minus for negative numbers)
 | ||||||
|  |     if (/^[+*/^%=<>|&]/.test(cleanEquation) || /[+\-*/^%=<>|&]$/.test(cleanEquation)) { | ||||||
|  |       throw new Error('Equation cannot start or end with an operator'); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Check for empty parentheses
 | ||||||
|  |     if (/\(\)/.test(cleanEquation)) { | ||||||
|  |       throw new Error('Empty parentheses are not allowed'); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Delete calculated field
 |   // Delete calculated field
 | ||||||
|   deleteCalculatedField(id: number) { |   deleteCalculatedField(id: number) { | ||||||
|     this.calculatedFields = this.calculatedFields.filter(field => field.id !== id); |     this.calculatedFields = this.calculatedFields.filter(field => field.id !== id); | ||||||
| @ -562,4 +816,156 @@ export class Data_lakeComponent implements OnInit { | |||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   // Add operator to complex equation
 | ||||||
|  |   addOperatorToEquation(operator: string) { | ||||||
|  |     const equationControl = this.calculatedFieldForm.get('complexEquation'); | ||||||
|  |     if (equationControl) { | ||||||
|  |       const currentValue = equationControl.value || ''; | ||||||
|  |       equationControl.setValue(currentValue + operator); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Add field or constant to complex equation
 | ||||||
|  |   addFieldToEquation(field: string) { | ||||||
|  |     const equationControl = this.calculatedFieldForm.get('complexEquation'); | ||||||
|  |     if (equationControl) { | ||||||
|  |       const currentValue = equationControl.value || ''; | ||||||
|  |       // Add space before and after if needed
 | ||||||
|  |       const newValue = currentValue ? `${currentValue} ${field} ` : `${field} `; | ||||||
|  |       equationControl.setValue(newValue); | ||||||
|  |        | ||||||
|  |       // Validate after adding field
 | ||||||
|  |       if (this.calculatedFieldForm.get('operation')?.value === 'complex') { | ||||||
|  |         this.analyzeComplexEquation(equationControl.value); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Get all defined constants from existing calculated fields
 | ||||||
|  |   getDefinedConstants(): string[] { | ||||||
|  |     const constants: string[] = []; | ||||||
|  |     this.calculatedFields.forEach(field => { | ||||||
|  |       // Check for actual constant operations
 | ||||||
|  |       if (field.operation === 'constant' && field.fieldName) { | ||||||
|  |         constants.push(field.fieldName); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     return constants; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Add a new constant to the equation
 | ||||||
|  |   addNewConstantToEquation() { | ||||||
|  |     // Generate a new constant name
 | ||||||
|  |     this.currentConstantName = `constant_${this.constantCounter}`; | ||||||
|  |      | ||||||
|  |     // Open the constant value modal
 | ||||||
|  |     this.currentConstantValue = ''; | ||||||
|  |     this.constantValueModalOpen = true; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Save constant value and update equation
 | ||||||
|  |   saveConstantValue() { | ||||||
|  |     if (this.currentConstantValue === '') { | ||||||
|  |       this.toastr.error('Constant value is required'); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Validate constant value based on operation type
 | ||||||
|  |     const operation = this.calculatedFieldForm.get('operation')?.value; | ||||||
|  |     if (operation !== 'concat' && operation !== 'complex') { | ||||||
|  |       const numericValue = Number(this.currentConstantValue); | ||||||
|  |       if (isNaN(numericValue)) { | ||||||
|  |         this.toastr.error('Constant values must be numeric for this operation'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // For non-complex operations, add to field components directly
 | ||||||
|  |     if (operation && operation !== 'complex') { | ||||||
|  |       const fieldComponents = this.getFieldComponents(); | ||||||
|  |       fieldComponents.push(this._fb.group({ | ||||||
|  |         field: [this.currentConstantName], | ||||||
|  |         constant: [this.currentConstantValue] | ||||||
|  |       })); | ||||||
|  |     } else if (operation === 'complex') { | ||||||
|  |       // For complex equations, add to the equation and create a constant field
 | ||||||
|  |       const equationControl = this.calculatedFieldForm.get('complexEquation'); | ||||||
|  |       if (equationControl) { | ||||||
|  |         const currentValue = equationControl.value || ''; | ||||||
|  |         const newValue = currentValue ? `${currentValue} ${this.currentConstantName} ` : `${this.currentConstantName} `; | ||||||
|  |         equationControl.setValue(newValue); | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       // Also create a constant field that can be referenced
 | ||||||
|  |       const constantField = { | ||||||
|  |         id: Date.now(), | ||||||
|  |         fieldName: this.currentConstantName, | ||||||
|  |         operation: 'constant', | ||||||
|  |         fieldComponents: [{ | ||||||
|  |           field: this.currentConstantName, | ||||||
|  |           constant: this.currentConstantValue, | ||||||
|  |           isConstant: true | ||||||
|  |         }] | ||||||
|  |       }; | ||||||
|  |        | ||||||
|  |       this.calculatedFields.push(constantField); | ||||||
|  |     } else { | ||||||
|  |       // If no operation is selected, just create the constant field
 | ||||||
|  |       const constantField = { | ||||||
|  |         id: Date.now(), | ||||||
|  |         fieldName: this.currentConstantName, | ||||||
|  |         operation: 'constant', | ||||||
|  |         fieldComponents: [{ | ||||||
|  |           field: this.currentConstantName, | ||||||
|  |           constant: this.currentConstantValue, | ||||||
|  |           isConstant: true | ||||||
|  |         }] | ||||||
|  |       }; | ||||||
|  |        | ||||||
|  |       this.calculatedFields.push(constantField); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     // Increment the counter for next constant
 | ||||||
|  |     this.constantCounter++; | ||||||
|  |      | ||||||
|  |     // Close modal and show success message
 | ||||||
|  |     this.constantValueModalOpen = false; | ||||||
|  |     this.toastr.success(`Constant ${this.currentConstantName} added with value ${this.currentConstantValue}`); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Cancel constant value input
 | ||||||
|  |   cancelConstantValue() { | ||||||
|  |     this.constantValueModalOpen = false; | ||||||
|  |     this.currentConstantName = ''; | ||||||
|  |     this.currentConstantValue = ''; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   // Test method to verify constant validation
 | ||||||
|  |   testConstantFunctionality() { | ||||||
|  |     // Clear existing calculated fields for testing
 | ||||||
|  |     this.calculatedFields = []; | ||||||
|  |      | ||||||
|  |     // Add a test constant
 | ||||||
|  |     const testConstant = { | ||||||
|  |       id: Date.now(), | ||||||
|  |       fieldName: 'constant_1', | ||||||
|  |       operation: 'constant', | ||||||
|  |       fieldComponents: [{ | ||||||
|  |         field: 'constant_1', | ||||||
|  |         constant: '15', | ||||||
|  |         isConstant: true | ||||||
|  |       }] | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     this.calculatedFields.push(testConstant); | ||||||
|  |      | ||||||
|  |     // Test validation
 | ||||||
|  |     const testEquation = 'pincode + mobno * constant_1'; | ||||||
|  |     const isValid = this.validateComplexEquation(testEquation); | ||||||
|  |      | ||||||
|  |     console.log('Test equation:', testEquation); | ||||||
|  |     console.log('Validation result:', isValid); | ||||||
|  |     console.log('Defined constants:', this.getDefinedConstants()); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ | |||||||
| 
 | 
 | ||||||
|     <div class="clr-col-4" style="text-align: right;"> |     <div class="clr-col-4" style="text-align: right;"> | ||||||
| 
 | 
 | ||||||
|       <button id="add" class="btn btn-primary" *ngIf="mcreate == 'true'"  (click)="goToAdd()"> |       <button id="add" class="btn btn-primary"  (click)="goToAdd()"> | ||||||
|         <clr-icon shape="plus"></clr-icon>ADD |         <clr-icon shape="plus"></clr-icon>ADD | ||||||
|       </button> |       </button> | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -31,12 +31,12 @@ export class SureconnectComponent implements OnInit { | |||||||
|   ngOnInit(): void { |   ngOnInit(): void { | ||||||
|     this.showdata = this.menuGroupService.getdata(); |     this.showdata = this.menuGroupService.getdata(); | ||||||
|     console.log(this.showdata); |     console.log(this.showdata); | ||||||
|     this.mcreate = this.showdata.mcreate; |     // this.mcreate = this.showdata.mcreate;
 | ||||||
|     console.log(this.mcreate); |     // console.log(this.mcreate);
 | ||||||
|     this.mdelete = this.showdata.mdelete |     // this.mdelete = this.showdata.mdelete
 | ||||||
|     console.log(this.mdelete); |     // console.log(this.mdelete);
 | ||||||
|     this.medit = this.showdata.medit |     // this.medit = this.showdata.medit
 | ||||||
|     console.log(this.medit); |     // console.log(this.medit);
 | ||||||
|     this.getall(); |     this.getall(); | ||||||
|   } |   } | ||||||
|   getall() { |   getall() { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user