This commit is contained in:
string 2025-10-16 08:37:51 +05:30
parent 64752c0970
commit 16c83ec322
3 changed files with 378 additions and 137 deletions

View File

@ -55,6 +55,9 @@
<clr-dg-column [clrDgField]="'sure_connect_id'"> <ng-container *clrDgHideableColumn="{hidden: false}"> SureConnect
</ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="'calculated_field_json'"> <ng-container *clrDgHideableColumn="{hidden: false}"> Calculated Fields
</ng-container></clr-dg-column>
<!-- who column -->
<clr-dg-column> <ng-container *clrDgHideableColumn="{hidden: false}">
<clr-icon shape="bars"></clr-icon> Action
@ -82,7 +85,8 @@
<clr-dg-cell>
<div style="display: flex; align-items: center; max-width: 200px;">
<span style="margin-right: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-grow: 1;"
<span
style="margin-right: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex-grow: 1;"
title="{{user.url}}" (click)="showFullUrl(user.url)">
{{user.url | slice:0:30}}{{user.url.length > 30 ? '...' : ''}}
</span>
@ -93,7 +97,10 @@
</clr-dg-cell>
<clr-dg-cell>{{user.batch_volume}}</clr-dg-cell>
<clr-dg-cell>{{getSureConnectNameById(user.sure_connect_id)}}</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
shape="details" *ngIf="user.calculated_field_json"></clr-icon></clr-dg-cell>
<!-- who column -->
<clr-dg-cell>
@ -114,6 +121,11 @@
<button class="btn btn-icon" (click)="updateJson(user.id)" title="Update JSON">
<clr-icon shape="refresh"></clr-icon>
</button>
<!-- Calculated Field button -->
<button class="btn btn-icon" (click)="fetchAvailableKeys(user)" title="Create Calculated Field">
<clr-icon shape="calculator"></clr-icon>
</button>
</clr-dg-cell>
<!-- who colmn -->
@ -256,7 +268,8 @@
[style.color]="item.conditionValue == app[transform(item.fieldtext) ] ? item.conditiontextcolor : item.textcolor">
<img id="filePreview" [src]="item.imageURL" alt="File Preview"
[style.width]="item.imagewidth !== '' ? item.imagewidth + 'px' : '100px'"
[style.height]="item.imagewidth !== '' ? item.imagewidth + 'px' : '100px'"></div>
[style.height]="item.imagewidth !== '' ? item.imagewidth + 'px' : '100px'">
</div>
</div>
</ng-container>
</div>
@ -292,17 +305,6 @@
<h3 class="modal-title">Update Data lake
<!--update button -->
</h3>
<div class="modal-body" *ngIf="rowSelected.id">
<h2 class="heading">{{rowSelected.id}}</h2>
@ -329,7 +331,9 @@
<div class="clr-col-sm-12">
<label>cron job</label>
<input class="clr-input" type="text" [(ngModel)]="rowSelected.cron_job" name="cron_job" />
<app-cron-job-builder [cronExpression]="editCronExpression" (cronExpressionChange)="onEditCronExpressionChange($event)" instanceId="edit-form-{{rowSelected.id}}"></app-cron-job-builder>
<app-cron-job-builder [cronExpression]="editCronExpression"
(cronExpressionChange)="onEditCronExpressionChange($event)"
instanceId="edit-form-{{rowSelected.id}}"></app-cron-job-builder>
</div>
<div class="clr-col-sm-12">
@ -350,25 +354,14 @@
<div class="clr-col-sm-12">
<label>SureConnect</label>
<select class="clr-input" [(ngModel)]="rowSelected.sure_connect_id" name="sure_connect_id" (change)="onEditSureConnectChange($event)">
<select class="clr-input" [(ngModel)]="rowSelected.sure_connect_id" name="sure_connect_id">
<option value="">Select SureConnect</option>
<option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.name}}</option>
<option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.connection_name}}
</option>
</select>
</div>
</div>
<!-- form code start -->
<div *ngIf="checkFormCode">
<h4 style="font-weight: 300;display: inline;">Extension</h4>
@ -405,6 +398,9 @@
</form>
</div>
</clr-modal>
<!-- DELETE FORM ..... -->
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<div class="modal-body" *ngIf="rowSelected.id">
<h1 class="delete">Are You Sure Want to delete?</h1>
@ -415,21 +411,11 @@
</div>
</div>
</clr-modal>
<!-- ADD FORM ..... -->
<clr-modal [(clrModalOpen)]="modalAdd" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Add Data lake
<!-- aeroplane icon -->
&nbsp; &nbsp; &nbsp; &nbsp;
<a *ngIf="userrole?.includes('ADMIN')" style="float: right;" href="javascript:void(0)" role="tooltip"
@ -466,7 +452,8 @@
<div class="clr-col-sm-12">
<label> cron job</label>
<input class="clr-input" type="text" formControlName="cron_job" />
<app-cron-job-builder [cronExpression]="addCronExpression" (cronExpressionChange)="onAddCronExpressionChange($event)" instanceId="add-form"></app-cron-job-builder>
<app-cron-job-builder [cronExpression]="addCronExpression"
(cronExpressionChange)="onAddCronExpressionChange($event)" instanceId="add-form"></app-cron-job-builder>
</div>
<div class="clr-col-sm-12">
@ -487,9 +474,10 @@
<div class="clr-col-sm-12">
<label>SureConnect</label>
<select class="clr-input" formControlName="sure_connect_id" (change)="onAddSureConnectChange($event)">
<select formControlName="sure_connect_id">
<option value="">Select SureConnect</option>
<option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.name}}</option>
<option *ngFor="let sureConnect of sureConnectList" [value]="sureConnect.id">{{sureConnect.connection_name}}
</option>
</select>
</div>
@ -528,6 +516,116 @@
</div>
</clr-modal>
<!-- Calculated Field Modal -->
<clr-modal [(clrModalOpen)]="calculatedFieldModalOpen" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<h3 class="modal-title">Create Calculated Field</h3>
<div class="modal-body">
<form [formGroup]="calculatedFieldForm">
<div class="clr-row">
<div class="clr-col-12">
<h4>Available Keys from API:</h4>
<ul>
<li *ngFor="let key of availableKeys">{{ key }}</li>
</ul>
</div>
<div class="clr-col-12">
<label>Calculated Field Name</label>
<input class="clr-input" type="text" formControlName="fieldName" placeholder="Enter field name" />
</div>
<div class="clr-col-12">
<label>Operation</label>
<select formControlName="operation">
<option value="">Select Operation</option>
<option value="add">Addition (+)</option>
<option value="subtract">Subtraction (-)</option>
<option value="multiply">Multiplication (*)</option>
<option value="divide">Division (/)</option>
<option value="percentage">Percentage (%)</option>
<option value="concat">Concatenation (||)</option>
</select>
</div>
<!-- Multiple Fields Section -->
<div class="clr-col-12" *ngIf="calculatedFieldForm.get('operation')?.value">
<label>Fields and Constants</label>
<div class="clr-row">
<div class="clr-col-12">
<div formArrayName="fieldComponents">
<div *ngFor="let fieldComponent of getFieldComponents().controls; let i = index"
[formGroupName]="i" class="clr-row field-component-row">
<div class="clr-col-5">
<select formControlName="field">
<option value="">Select Field</option>
<option *ngFor="let key of availableKeys" [value]="key">{{ key }}</option>
</select>
</div>
<div class="clr-col-5">
<input type="text" formControlName="constant" placeholder="Or enter constant value" />
</div>
<div class="clr-col-2">
<button type="button" class="btn btn-icon btn-danger" (click)="removeFieldComponent(i)"
*ngIf="getFieldComponents().length > 1">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
</div>
</div>
<button type="button" class="btn btn-sm" (click)="addFieldComponent()">
<clr-icon shape="plus"></clr-icon> Add Field/Constant
</button>
</div>
</div>
</div>
</div>
</form>
<div class="clr-row" style="margin-top: 20px;">
<div class="clr-col-12">
<h4>Created Calculated Fields:</h4>
<table class="table">
<thead>
<tr>
<th>Field Name</th>
<th>Operation</th>
<th>Fields/Values</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let field of calculatedFields">
<td>{{ field.fieldName }}</td>
<td>{{ field.operation }}</td>
<td>
<span *ngFor="let component of field.fieldComponents; let last = last">
<span *ngIf="component.field && !component.isConstant">{{ component.field }}</span>
<span *ngIf="component.isConstant">"{{ component.constant }}"</span>
<span *ngIf="!component.field && component.constant">"{{ component.constant }}"</span>
<span *ngIf="!last"> {{ getOperationSymbol(field.operation) }} </span>
</span>
</td>
<td>
<button class="btn btn-icon btn-danger" (click)="deleteCalculatedField(field.id)">
<clr-icon shape="trash"></clr-icon>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<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-success" (click)="updateCalculatedFields()"
[disabled]="calculatedFields.length === 0">
Update Record
</button>
</div>
</clr-modal>

View File

@ -8,6 +8,8 @@ import { DashboardContentModel2 } from 'src/app/models/builder/dashboard';
import { Data_lakecardvariable } from './Data_lake_cardvariable';
import { UserInfoService } from 'src/app/services/user-info.service';
import { SureconnectService } from '../sureconnect/sureconnect.service';
import { HttpClient } from '@angular/common/http';
import { ApiRequestService } from 'src/app/services/api/api-request.service';
declare var JsBarcode: any;
@Component({
selector: 'app-Data_lake',
@ -60,6 +62,14 @@ export class Data_lakeComponent implements OnInit {
sureConnectList;
selectedSureConnect: any = null;
// Calculated field properties
calculatedFieldModalOpen = false;
availableKeys: string[] = [];
selectedDataLakeItem: any = null;
calculatedFieldForm: FormGroup;
calculatedFields: any[] = [];
constantCounter = 1; // Persistent counter for unique constant names
constructor(
private extensionService: ExtensionService,
private userInfoService: UserInfoService,
@ -67,7 +77,9 @@ export class Data_lakeComponent implements OnInit {
private alertService: AlertService,
private toastr: ToastrService,
private _fb: FormBuilder,
private sureConnectService: SureconnectService
private sureConnectService: SureconnectService,
private http: HttpClient,
private apiRequest: ApiRequestService
) { }
private editInterval: any;
// component button
@ -120,15 +132,37 @@ export class Data_lakeComponent implements OnInit {
console.log(this.entryForm.value);
// form code end
// Initialize calculated field form with FormArray for multiple fields
this.calculatedFieldForm = this._fb.group({
fieldName: [''],
operation: [''],
fieldComponents: this._fb.array([this.createFieldComponent()])
});
}
// Helper method to create a field component group
createFieldComponent(): FormGroup {
return this._fb.group({
field: [''],
constant: ['']
});
}
// Getter for field components FormArray
getFieldComponents(): FormArray {
return this.calculatedFieldForm.get('fieldComponents') as FormArray;
}
// Method to add a new field component
addFieldComponent(): void {
this.getFieldComponents().push(this.createFieldComponent());
}
// Method to remove a field component
removeFieldComponent(index: number): void {
if (this.getFieldComponents().length > 1) {
this.getFieldComponents().removeAt(index);
}
}
ngOnDestroy(): void {
if (this.editInterval) {
@ -138,15 +172,6 @@ export class Data_lakeComponent implements OnInit {
error;
getData() {
this.mainService.getAll().subscribe((data) => {
@ -165,7 +190,7 @@ export class Data_lakeComponent implements OnInit {
// Fetch SureConnect list
getSureConnectList() {
this.sureConnectService.getAll().subscribe((data) => {
this.sureConnectService.getAll().subscribe((data: any[]) => {
this.sureConnectList = data;
console.log('SureConnect List:', this.sureConnectList);
}, (error) => {
@ -173,14 +198,144 @@ export class Data_lakeComponent implements OnInit {
});
}
// Get SureConnect name by ID for display in grid
getSureConnectNameById(id: number): string {
if (!id || !this.sureConnectList || this.sureConnectList.length === 0) {
return '';
// Get operation symbol for display
getOperationSymbol(operation: string): string {
switch(operation) {
case 'add': return '+';
case 'subtract': return '-';
case 'multiply': return '*';
case 'divide': return '/';
case 'percentage': return '%';
case 'concat': return '||'; // Concatenation symbol
default: return '';
}
}
const sureConnect = this.sureConnectList.find(item => item.id === id);
return sureConnect ? sureConnect.name : '';
// Fetch available keys from API
fetchAvailableKeys(dataLakeItem: any) {
if (!dataLakeItem.url || !dataLakeItem.sure_connect_id) {
this.toastr.error('URL and SureConnect ID are required to fetch keys');
return;
}
this.selectedDataLakeItem = dataLakeItem;
// Call the service method to get all keys
this.mainService.fetchAvailableKeys(dataLakeItem.url, dataLakeItem.sure_connect_id).subscribe(
(keys: string[]) => {
this.availableKeys = keys;
// Reset the calculated field form to ensure it starts fresh
this.resetCalculatedFieldForm();
this.calculatedFieldModalOpen = true;
console.log('Available keys:', keys);
},
(error) => {
console.error('Error fetching keys:', error);
this.toastr.error('Failed to fetch available keys from API');
}
);
}
// Reset the calculated field form to initial state
resetCalculatedFieldForm(): void {
this.calculatedFieldForm.reset({
fieldName: '',
operation: '',
fieldComponents: [{}] // Start with one empty field component
});
// Ensure we have exactly one empty field component
const fieldComponents = this.getFieldComponents();
fieldComponents.clear();
fieldComponents.push(this.createFieldComponent());
// Reset the constant counter for new calculations
this.constantCounter = 1;
}
// Add calculated field
addCalculatedField() {
const formData = this.calculatedFieldForm.value;
if (!formData.fieldName || !formData.operation) {
this.toastr.error('Field name and operation are required');
return;
}
// Filter out empty field components
const validFieldComponents = formData.fieldComponents.filter(component =>
component.field || component.constant
);
if (validFieldComponents.length === 0) {
this.toastr.error('At least one field or constant is required');
return;
}
// Validate constant values - must be numeric for all operations except concatenation
if (formData.operation !== 'concat') {
for (const component of validFieldComponents) {
if (component.constant && component.constant.trim() !== '') {
const numericValue = Number(component.constant);
if (isNaN(numericValue)) {
this.toastr.error('Constant values must be numeric for this operation');
return;
}
}
}
}
// Validate that constant values are unique within this calculated field
const constantValues = validFieldComponents
.map(component => component.constant)
.filter(constant => constant && constant.trim() !== '');
if (constantValues.length !== new Set(constantValues).size) {
this.toastr.error('Constant values must be unique within a calculated field');
return;
}
// Generate unique names for constants using the persistent counter
const processedFieldComponents = validFieldComponents.map(component => {
if (component.constant && component.constant.trim() !== '') {
// Generate a unique name for the constant using the persistent counter
const constantName = `constant_${this.constantCounter++}`;
return {
field: constantName,
constant: component.constant,
isConstant: true // Flag to indicate this is a constant with a generated name
};
}
return {
field: component.field,
constant: component.constant,
isConstant: false // Flag to indicate this is a regular field
};
});
// Create calculated field object with multiple field components
const calculatedField = {
id: Date.now(), // Simple ID generation
fieldName: formData.fieldName,
operation: formData.operation,
fieldComponents: processedFieldComponents
};
this.calculatedFields.push(calculatedField);
this.toastr.success('Calculated field added successfully');
// Reset form but keep one empty field component
this.calculatedFieldForm.reset({
fieldName: '',
operation: '',
fieldComponents: [{}]
});
}
// Delete calculated field
deleteCalculatedField(id: number) {
this.calculatedFields = this.calculatedFields.filter(field => field.id !== id);
this.toastr.success('Calculated field deleted');
}
onEdit(row) {
@ -210,17 +365,6 @@ export class Data_lakeComponent implements OnInit {
onUpdate(id) {
this.modalEdit = false;
//console.log("in update");
console.log("id " + id);
console.log(this.rowSelected);
@ -237,15 +381,6 @@ export class Data_lakeComponent implements OnInit {
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
@ -323,36 +458,11 @@ export class Data_lakeComponent implements OnInit {
}
}
// Handle SureConnect selection change in add form
onAddSureConnectChange(event: any) {
const selectedId = event.target.value;
if (this.entryForm && this.entryForm.get('sure_connect_id')) {
this.entryForm.get('sure_connect_id')?.setValue(selectedId);
}
}
// Handle SureConnect selection change in edit form
onEditSureConnectChange(event: any) {
const selectedId = event.target.value;
if (this.rowSelected) {
this.rowSelected.sure_connect_id = selectedId;
}
}
onCreate() {
this.modalAdd = false;
this.mainService.create(this.entryForm.value).subscribe(
(data) => {
console.log(data);
@ -365,15 +475,6 @@ export class Data_lakeComponent implements OnInit {
}, (error) => {
console.log(error);
if (error.status >= 200 && error.status <= 299) {
@ -400,9 +501,7 @@ export class Data_lakeComponent implements OnInit {
if (this.entryForm.get('cron_job')) {
this.entryForm.get('cron_job')?.setValue('');
}
if (this.entryForm.get('sure_connect_id')) {
this.entryForm.get('sure_connect_id')?.setValue(null);
}
}
}
submitted = false;
@ -422,16 +521,45 @@ export class Data_lakeComponent implements OnInit {
goTourlUrl(val) { window.open(val) }
rsModaljson = false;
goToReplaceStringjson(row) {
this.rowSelected = row; this.rsModaljson = true;
}
// updateaction
// Generate JSON from calculated fields and update the record
updateCalculatedFields() {
if (!this.selectedDataLakeItem || this.calculatedFields.length === 0) {
this.toastr.error('No calculated fields to update');
return;
}
// Convert calculated fields to JSON string
const calculatedFieldJson = JSON.stringify(this.calculatedFields);
// Call the service method to update the record
this.mainService.updateCalculatedFields(
this.selectedDataLakeItem.id,
calculatedFieldJson,
true // iscalculatedfield = true
).subscribe(
(response) => {
console.log('Calculated fields updated successfully:', response);
this.toastr.success('Calculated fields updated successfully');
// Update the local data
const index = this.product.findIndex(item => item.id === this.selectedDataLakeItem.id);
if (index !== -1) {
this.product[index].calculated_field_json = calculatedFieldJson;
this.product[index].iscalculatedfield = true;
}
// Close the modal
this.calculatedFieldModalOpen = false;
},
(error) => {
console.error('Error updating calculated fields:', error);
this.toastr.error('Failed to update calculated fields');
}
);
}
}

View File

@ -36,5 +36,20 @@ export class Data_lakeservice{
return this.apiRequest.put(_http, {});
}
// Method to fetch available keys from API
fetchAvailableKeys(url: string, sureId: number): Observable<string[]> {
const apiUrl = `chart/getAllKeys?apiUrl=${encodeURIComponent(url)}&sureId=${sureId}`;
return this.apiRequest.get(apiUrl);
}
// Method to update calculated fields for a data lake item
updateCalculatedFields(id: number, calculatedFieldJson: string, isCalculatedField: boolean): Observable<any> {
const _http = this.baseURL + "/" + id;
const data = {
calculated_field_json: calculatedFieldJson,
iscalculatedfield: isCalculatedField
};
return this.apiRequest.put(_http, data);
}
// updateaction
}