data lake
This commit is contained in:
parent
251bc56428
commit
7f80ea6330
@ -55,11 +55,13 @@
|
|||||||
<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 -->
|
||||||
@ -99,8 +101,9 @@
|
|||||||
|
|
||||||
<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,75 +545,160 @@
|
|||||||
<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>
|
||||||
@ -620,12 +706,32 @@
|
|||||||
<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 {
|
|
||||||
|
.calculated-section {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
color: #0072a0;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
align-items: center;
|
||||||
justify-content: space-between;
|
}
|
||||||
button {
|
|
||||||
outline: none;
|
.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.delete,.heading{
|
|
||||||
text-align: center;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
.entry-pg {
|
|
||||||
width: 750px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button1::after {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
color: #1a237e;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
@ -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