dashboard

This commit is contained in:
string 2025-10-25 20:08:04 +05:30
parent f2b6a4d145
commit 8266bfdc01
3 changed files with 684 additions and 27 deletions

View File

@ -23,18 +23,6 @@
<!-- Main Dashboard Content --> <!-- Main Dashboard Content -->
<div class="main-content"> <div class="main-content">
<!-- KPI Metrics -->
<!-- <div class="kpi-section">
<div class="kpi-card total-leads">
<div class="kpi-title">Total Leads</div>
<div class="kpi-value">1,248</div>
</div>
<div class="kpi-card total-deals">
<div class="kpi-title">Total Deals</div>
<div class="kpi-value">842</div>
</div>
</div> -->
<!-- Deleted Items Section --> <!-- Deleted Items Section -->
<div class="deleted-items-section" *ngIf="deletedItems.length > 0"> <div class="deleted-items-section" *ngIf="deletedItems.length > 0">
<h3>Deleted Items</h3> <h3>Deleted Items</h3>
@ -52,9 +40,6 @@
</div> </div>
<!-- Dashboard Grid with Drag and Drop --> <!-- Dashboard Grid with Drag and Drop -->
<!-- <div class="drop-zone-indicator" *ngIf="dashboard.length === 0">
<p>Drag components here from the sidebar</p>
</div> -->
<gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent; min-height: 500px;"> <gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent; min-height: 500px;">
<gridster-item [item]="item" *ngFor="let item of dashboard"> <gridster-item [item]="item" *ngFor="let item of dashboard">
<!-- Remove Button --> <!-- Remove Button -->
@ -62,6 +47,11 @@
<clr-icon shape="trash"></clr-icon> <clr-icon shape="trash"></clr-icon>
</button> </button>
<!-- Edit Button -->
<button class="btn btn-icon" style="margin-top: 10px; float: right;" (click)="editGadget(item)">
<clr-icon shape="pencil"></clr-icon>
</button>
<!-- Drag Handle --> <!-- Drag Handle -->
<button class="btn btn-icon drag-handler" style="margin-left: 10px; margin-top: 10px;"> <button class="btn btn-icon drag-handler" style="margin-left: 10px; margin-top: 10px;">
<clr-icon shape="drag-handle"></clr-icon> <clr-icon shape="drag-handle"></clr-icon>
@ -96,4 +86,361 @@
</gridster> </gridster>
</div> </div>
</div> </div>
</div> </div>
<!-- Configuration Modal -->
<clr-modal [(clrModalOpen)]="modeledit" [clrModalStaticBackdrop]="true" clrModalSize="lg">
<h3 class="modal-title">Configure Chart</h3>
<div class="modal-body" *ngIf="selectedItem">
<form [formGroup]="configForm" class="clr-form-horizontal">
<div class="clr-row">
<div class="clr-col-sm-12">
<label for="charttitle">Chart Title</label>
<input id="charttitle" type="text" formControlName="charttitle" class="clr-input">
</div>
</div>
<!-- Connection Selection Field -->
<div class="clr-row">
<div class="clr-col-sm-12">
<label for="connection">Connection</label>
<select id="connection" formControlName="connection" class="clr-select">
<option value="">Select Connection</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.connection_name || conn.id}}
</option>
</select>
<div class="clr-subtext">Select a SureConnect connection to use for this chart</div>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
<div class="clr-col-sm-12">
<div class="clr-form-control" style="margin-top: 5px;margin-bottom: 10px;">
<div class="clr-control-container">
<div class="clr-checkbox-wrapper">
<input type="checkbox" id="chartlegend" formControlName="chartlegend" class="clr-checkbox" />
<label for="chartlegend" class="clr-control-label">Show Chart Legend</label>
</div>
<div class="clr-checkbox-wrapper">
<input type="checkbox" id="showlabel" formControlName="showlabel" class="clr-checkbox" />
<label for="showlabel" class="clr-control-label">Show Chart Label</label>
</div>
</div>
</div>
</div>
</div>
<div class="clr-row">
<div class="clr-col-sm-12">
<label for="table">Api Url</label>
<div>
<input type="text" id="table" formControlName="table" class="clr-input" style="width:90%">&nbsp;
<span>
<button class="btn btn-icon btn-primary" style="margin: 0px;" (click)="getColumns(configForm.value.connection, configForm.value.table)">
<clr-icon shape="redo"></clr-icon>
</button>
</span>
</div>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
<div class="clr-col-sm-12">
<label for="xAxis">X-Axis</label>
<select id="xAxis" formControlName="xAxis">
<option value="null">choose Column</option>
<option *ngFor="let data of columnData" [value]="data">{{data}}</option>
</select>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
<div class="clr-col-sm-12">
<label for="yAxis">Y-Axis (Numeric)</label>
<clr-combobox-container style="margin-top: 10px !important;">
<clr-combobox id="yAxis" formControlName="yAxis" clrMulti="true" required>
<ng-container *clrOptionSelected="let selected">
{{selected}}
</ng-container>
<clr-options>
<clr-option *clrOptionItems="let state of columnData" [clrValue]="state">
{{state}}
</clr-option>
</clr-options>
</clr-combobox>
</clr-combobox-container>
</div>
</div>
<!-- Base API Filters -->
<div class="clr-row" style="margin-top: 15px;">
<div class="clr-col-sm-12">
<h5>Base API Filters</h5>
<!-- Add Base Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addBaseFilter()" style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
<!-- Base Filter Fields List -->
<div *ngFor="let filter of selectedItem?.baseFilters; let i = index"
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Filter {{i + 1}}</span>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-row" style="margin-top: 8px;">
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Field Name" />
</div>
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" />
</div>
<div class="clr-col-sm-2">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Base Drilldown Configuration Section -->
<div class="clr-row" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
<div class="clr-col-sm-12">
<h4>Base Drilldown Configuration</h4>
<div class="clr-form-control">
<div class="clr-control-container">
<div class="clr-checkbox-wrapper">
<input type="checkbox" id="drilldownEnabled" [(ngModel)]="selectedItem.drilldownEnabled"
[ngModelOptions]="{standalone: true}" class="clr-checkbox" />
<label for="drilldownEnabled" class="clr-control-label">Enable Base Drilldown</label>
</div>
</div>
</div>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
<div class="clr-col-sm-12">
<label for="drilldownApiUrl">Base Drilldown API URL</label>
<div>
<input type="text" id="drilldownApiUrl" [(ngModel)]="selectedItem.drilldownApiUrl"
[ngModelOptions]="{standalone: true}" class="clr-input" style="width:90%">&nbsp;
<span>
<button class="btn btn-icon btn-primary" style="margin: 0px;"
(click)="refreshDrilldownColumns()" [disabled]="!selectedItem.drilldownApiUrl">
<clr-icon shape="redo"></clr-icon>
</button>
</span>
</div>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
<div class="clr-col-sm-12">
<label for="drilldownXAxis">Base Drilldown X-Axis</label>
<select id="drilldownXAxis" [(ngModel)]="selectedItem.drilldownXAxis" [ngModelOptions]="{standalone: true}">
<option value="">Select X-Axis Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled && selectedItem?.name !== 'Deal Details'">
<div class="clr-col-sm-12">
<label for="drilldownYAxis">Base Drilldown Y-Axis</label>
<select id="drilldownYAxis" [(ngModel)]="selectedItem.drilldownYAxis" [ngModelOptions]="{standalone: true}">
<option value="">Select Y-Axis Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select>
</div>
</div>
<!-- Base Drilldown Parameter Configuration -->
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
<div class="clr-col-sm-12">
<label for="drilldownParameter">Base Drilldown Parameter</label>
<select id="drilldownParameter" [(ngModel)]="selectedItem.drilldownParameter" [ngModelOptions]="{standalone: true}">
<option value="">Select Parameter Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select>
</div>
</div>
<!-- Base Drilldown Filter Configuration -->
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled" style="margin-top: 15px;">
<div class="clr-col-sm-12">
<h5>Base Drilldown Filters</h5>
<!-- Add Drilldown Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addDrilldownFilter()" style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
<!-- Drilldown Filter Fields List -->
<div *ngFor="let filter of selectedItem?.drilldownFilters; let i = index"
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Filter {{i + 1}}</span>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-row" style="margin-top: 8px;">
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Field Name" />
</div>
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" />
</div>
<div class="clr-col-sm-2">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownFilter(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Multi-Layer Drilldown Configurations -->
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
<div class="clr-col-sm-12">
<h4>Multi-Layer Drilldown Configurations</h4>
<button class="btn btn-sm btn-primary" (click)="addDrilldownLayer()">
<clr-icon shape="plus"></clr-icon> Add Drilldown Layer
</button>
</div>
</div>
<!-- Dynamic Drilldown Layers -->
<div class="clr-row" *ngFor="let layer of selectedItem?.drilldownLayers; let i = index">
<div class="clr-col-sm-12" style="margin-top: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<h5>Drilldown Layer {{i + 1}}</h5>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownLayer(i)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-form-control">
<div class="clr-control-container">
<div class="clr-checkbox-wrapper">
<input type="checkbox" [id]="'layerEnabled' + i" [(ngModel)]="layer.enabled"
[ngModelOptions]="{standalone: true}" class="clr-checkbox" />
<label [for]="'layerEnabled' + i" class="clr-control-label">Enable Layer {{i + 1}} Drilldown</label>
</div>
</div>
</div>
<div class="clr-row">
<div class="clr-col-sm-12">
<label [for]="'layerApiUrl' + i">Layer {{i + 1}} API URL</label>
<div>
<input type="text" [id]="'layerApiUrl' + i" class="clr-input"
[(ngModel)]="layer.apiUrl" style="width:90%" [ngModelOptions]="{standalone: true}">&nbsp;
<span>
<button class="btn btn-icon btn-primary" style="margin: 0px;"
(click)="refreshDrilldownLayerColumns(i)" [disabled]="!layer.apiUrl">
<clr-icon shape="redo"></clr-icon>
</button>
</span>
</div>
</div>
</div>
<div class="clr-row">
<div class="clr-col-sm-12">
<label [for]="'layerXAxis' + i">Layer {{i + 1}} X-Axis</label>
<select [id]="'layerXAxis' + i" [(ngModel)]="layer.xAxis" [ngModelOptions]="{standalone: true}">
<option value="">Select X-Axis Column</option>
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
</select>
</div>
</div>
<div class="clr-row" *ngIf="selectedItem?.name !== 'Deal Details'">
<div class="clr-col-sm-12">
<label [for]="'layerYAxis' + i">Layer {{i + 1}} Y-Axis</label>
<select [id]="'layerYAxis' + i" [(ngModel)]="layer.yAxis" [ngModelOptions]="{standalone: true}">
<option value="">Select Y-Axis Column</option>
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
</select>
</div>
</div>
<!-- Parameter Selection for Drilldown Layer -->
<div class="clr-row">
<div class="clr-col-sm-12">
<label [for]="'layerParameter' + i">Layer {{i + 1}} Parameter</label>
<select [id]="'layerParameter' + i" [(ngModel)]="layer.parameter" [ngModelOptions]="{standalone: true}">
<option value="">Select Parameter Column</option>
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
</select>
</div>
</div>
<!-- Layer Filter Configuration -->
<div class="clr-row" style="margin-top: 15px;">
<div class="clr-col-sm-12">
<h5>Layer {{i + 1}} Filters</h5>
<!-- Add Layer Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addLayerFilter(i)" style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter
</button>
<!-- Layer Filter Fields List -->
<div *ngFor="let filter of layer.filters; let j = index"
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Filter {{j + 1}}</span>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeLayerFilter(i, j)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
<div class="clr-row" style="margin-top: 8px;">
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Field Name" />
</div>
<div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" />
</div>
<div class="clr-col-sm-2">
<button class="btn btn-icon btn-danger btn-sm" (click)="removeLayerFilter(i, j)">
<clr-icon shape="trash"></clr-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="cancelConfiguration()">Cancel</button>
<button type="button" class="btn btn-primary" (click)="saveConfiguration()">Save</button>
</div>
</clr-modal>

View File

@ -1,11 +1,31 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { GridsterConfig, GridsterItem } from 'angular-gridster2'; import { GridsterConfig, GridsterItem } from 'angular-gridster2';
import { FormBuilder, FormGroup } from '@angular/forms';
import { DatastoreService } from 'src/app/services/fnd/datastore.service';
import { AlertsService } from 'src/app/services/fnd/alerts.service';
import { SureconnectService } from '../../sureconnect/sureconnect.service';
interface ShieldDashboardItem extends GridsterItem { interface ShieldDashboardItem extends GridsterItem {
chartType: string; chartType: string;
name: string; name: string;
id: number; id: number;
component?: any; component?: any;
// Configuration properties
charttitle?: string;
connection?: string;
table?: string;
xAxis?: string;
yAxis?: string[];
chartlegend?: boolean;
showlabel?: boolean;
baseFilters?: any[];
drilldownEnabled?: boolean;
drilldownApiUrl?: string;
drilldownXAxis?: string;
drilldownYAxis?: string;
drilldownParameter?: string;
drilldownFilters?: any[];
drilldownLayers?: any[];
} }
interface WidgetModel { interface WidgetModel {
@ -22,6 +42,12 @@ export class ShieldDashboardComponent implements OnInit {
options: GridsterConfig; options: GridsterConfig;
dashboard: Array<ShieldDashboardItem>; dashboard: Array<ShieldDashboardItem>;
// Configuration modal
configModalOpen = false;
modeledit = false; // Add this to match the main dashboard pattern
configForm: FormGroup;
selectedItem: ShieldDashboardItem | null = null;
// Component palette // Component palette
showComponentPalette = false; showComponentPalette = false;
WidgetsMock: WidgetModel[] = [ WidgetsMock: WidgetModel[] = [
@ -51,10 +77,22 @@ export class ShieldDashboardComponent implements OnInit {
} }
]; ];
// Services data
storedata: any[] = [];
columnData: any[] = [];
sureconnectData: any[] = [];
drilldownColumnData: any[] = [];
layerColumnData: { [key: number]: any[] } = {};
// Keep track of deleted items // Keep track of deleted items
deletedItems: Array<ShieldDashboardItem> = []; deletedItems: Array<ShieldDashboardItem> = [];
constructor() { } constructor(
private _fb: FormBuilder,
private datastoreService: DatastoreService,
private alertService: AlertsService,
private sureconnectService: SureconnectService
) { }
ngOnInit(): void { ngOnInit(): void {
this.options = { this.options = {
@ -81,6 +119,33 @@ export class ShieldDashboardComponent implements OnInit {
// Initialize the dashboard with empty canvas // Initialize the dashboard with empty canvas
this.dashboard = []; this.dashboard = [];
// Initialize form
this.configForm = this._fb.group({
charttitle: [''],
connection: [''],
table: [''],
xAxis: [''],
yAxis: [''],
chartlegend: [true],
showlabel: [true]
});
// Load service data
this.loadServicesData();
}
// Load initial data from services
loadServicesData() {
// Load sureconnect data
this.sureconnectService.getAll().subscribe((data: any[]) => {
this.sureconnectData = data;
});
// Load datastore data
this.datastoreService.getAll().subscribe((data) => {
this.storedata = data as any[];
});
} }
// Toggle component palette visibility // Toggle component palette visibility
@ -128,7 +193,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'bar-chart', chartType: 'bar-chart',
name: 'Bar Chart', name: 'Bar Chart',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
break; break;
case "doughnut_chart": case "doughnut_chart":
@ -142,7 +212,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'donut-chart', chartType: 'donut-chart',
name: 'End Customer Donut', name: 'End Customer Donut',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
} else { } else {
newItem = { newItem = {
@ -152,7 +227,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'donut-chart', chartType: 'donut-chart',
name: 'Segment Penetration Donut', name: 'Segment Penetration Donut',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
} }
break; break;
@ -164,7 +244,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'map-chart', chartType: 'map-chart',
name: 'Map Chart', name: 'Map Chart',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
break; break;
case "grid_view": case "grid_view":
@ -175,7 +260,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'data-table', chartType: 'data-table',
name: 'Data Table', name: 'Data Table',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
break; break;
case "to_do_chart": case "to_do_chart":
@ -186,7 +276,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'deal-details', chartType: 'deal-details',
name: 'Deal Details', name: 'Deal Details',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
break; break;
case "line_chart": case "line_chart":
@ -197,7 +292,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: 'quarterwise-flow', chartType: 'quarterwise-flow',
name: 'Quarterwise Flow', name: 'Quarterwise Flow',
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
break; break;
default: default:
@ -208,7 +308,12 @@ export class ShieldDashboardComponent implements OnInit {
x: 0, x: 0,
chartType: componentType, chartType: componentType,
name: componentType, name: componentType,
id: newId id: newId,
chartlegend: true,
showlabel: true,
baseFilters: [],
drilldownEnabled: false,
drilldownLayers: []
}; };
} }
@ -256,7 +361,22 @@ export class ShieldDashboardComponent implements OnInit {
// Only pass properties that are relevant to chart components // Only pass properties that are relevant to chart components
const chartInputs = { const chartInputs = {
chartType: item.chartType, chartType: item.chartType,
name: item.name name: item.name,
charttitle: item.charttitle,
connection: item.connection,
table: item.table,
xAxis: item.xAxis,
yAxis: item.yAxis,
chartlegend: item.chartlegend,
showlabel: item.showlabel,
baseFilters: item.baseFilters || [],
drilldownEnabled: item.drilldownEnabled,
drilldownApiUrl: item.drilldownApiUrl,
drilldownXAxis: item.drilldownXAxis,
drilldownYAxis: item.drilldownYAxis,
drilldownParameter: item.drilldownParameter,
drilldownFilters: item.drilldownFilters || [],
drilldownLayers: item.drilldownLayers || []
}; };
// Remove undefined properties to avoid passing unnecessary data // Remove undefined properties to avoid passing unnecessary data
@ -268,4 +388,193 @@ export class ShieldDashboardComponent implements OnInit {
return chartInputs; return chartInputs;
} }
// Open configuration modal for a chart
editGadget(item: ShieldDashboardItem) {
console.log('Opening configuration modal for item:', item);
this.selectedItem = item;
this.modeledit = true; // Use modeledit instead of configModalOpen
// Initialize form with item data
this.configForm.patchValue({
charttitle: item.charttitle || '',
connection: item.connection || '',
table: item.table || '',
xAxis: item.xAxis || '',
yAxis: item.yAxis || [],
chartlegend: item.chartlegend !== undefined ? item.chartlegend : true,
showlabel: item.showlabel !== undefined ? item.showlabel : true
});
console.log('Form values after patch:', this.configForm.value);
// Load columns if table is set
if (item.table) {
this.getColumns(item.connection, item.table);
}
// Load drilldown columns if drilldown API URL is set
if (item.drilldownApiUrl) {
this.refreshDrilldownColumns();
}
}
// Save configuration changes
saveConfiguration() {
if (this.selectedItem) {
const formData = this.configForm.value;
console.log('Saving configuration:', formData);
// Update the selected item with form data
Object.assign(this.selectedItem, formData);
// Close the modal
this.modeledit = false; // Use modeledit instead of configModalOpen
this.selectedItem = null;
}
}
// Cancel configuration changes
cancelConfiguration() {
console.log('Canceling configuration');
this.modeledit = false; // Use modeledit instead of configModalOpen
this.selectedItem = null;
}
// Get tables from datastore
getTables(id: string) {
this.alertService.getTablefromstore(parseInt(id, 10)).subscribe(gateway => {
console.log(gateway);
// Handle table data
}, (error) => {
console.log(error);
});
}
// Get columns from API
getColumns(connectionId: string, table: string) {
const connId = connectionId ? parseInt(connectionId, 10) : undefined;
this.alertService.getColumnfromurl(table, connId).subscribe(data => {
console.log('Column data:', data);
this.columnData = data;
}, (error) => {
console.log(error);
this.columnData = [];
});
}
// Refresh drilldown columns
refreshDrilldownColumns() {
if (this.selectedItem && this.selectedItem.drilldownApiUrl) {
const connId = this.selectedItem.connection ? parseInt(this.selectedItem.connection, 10) : undefined;
this.alertService.getColumnfromurl(this.selectedItem.drilldownApiUrl, connId).subscribe(data => {
console.log('Drilldown column data:', data);
this.drilldownColumnData = data;
}, (error) => {
console.log('Error fetching drilldown columns:', error);
this.drilldownColumnData = [];
});
}
}
// Add base filter
addBaseFilter() {
if (this.selectedItem) {
if (!this.selectedItem.baseFilters) {
this.selectedItem.baseFilters = [];
}
this.selectedItem.baseFilters.push({ field: '', value: '' });
}
}
// Remove base filter
removeBaseFilter(index: number) {
if (this.selectedItem && this.selectedItem.baseFilters) {
this.selectedItem.baseFilters.splice(index, 1);
}
}
// Add drilldown filter
addDrilldownFilter() {
if (this.selectedItem) {
if (!this.selectedItem.drilldownFilters) {
this.selectedItem.drilldownFilters = [];
}
this.selectedItem.drilldownFilters.push({ field: '', value: '' });
}
}
// Remove drilldown filter
removeDrilldownFilter(index: number) {
if (this.selectedItem && this.selectedItem.drilldownFilters) {
this.selectedItem.drilldownFilters.splice(index, 1);
}
}
// Add drilldown layer
addDrilldownLayer() {
if (this.selectedItem) {
if (!this.selectedItem.drilldownLayers) {
this.selectedItem.drilldownLayers = [];
}
this.selectedItem.drilldownLayers.push({
enabled: false,
apiUrl: '',
xAxis: '',
yAxis: '',
parameter: '',
filters: []
});
}
}
// Remove drilldown layer
removeDrilldownLayer(index: number) {
if (this.selectedItem && this.selectedItem.drilldownLayers) {
this.selectedItem.drilldownLayers.splice(index, 1);
}
}
// Add layer filter
addLayerFilter(layerIndex: number) {
if (this.selectedItem && this.selectedItem.drilldownLayers) {
const layer = this.selectedItem.drilldownLayers[layerIndex];
if (layer) {
if (!layer.filters) {
layer.filters = [];
}
layer.filters.push({ field: '', value: '' });
}
}
}
// Refresh drilldown columns for a specific layer
refreshDrilldownLayerColumns(layerIndex: number) {
if (this.selectedItem && this.selectedItem.drilldownLayers && this.selectedItem.drilldownLayers[layerIndex]) {
const layer = this.selectedItem.drilldownLayers[layerIndex];
if (layer && layer.apiUrl) {
const connId = this.selectedItem.connection ? parseInt(this.selectedItem.connection, 10) : undefined;
this.alertService.getColumnfromurl(layer.apiUrl, connId).subscribe(data => {
console.log(`Drilldown layer ${layerIndex} column data:`, data);
// Store layer column data in the layerColumnData property
this.layerColumnData[layerIndex] = data;
}, (error) => {
console.log(`Error fetching drilldown layer ${layerIndex} columns:`, error);
this.layerColumnData[layerIndex] = [];
});
}
}
}
// Remove layer filter
removeLayerFilter(layerIndex: number, filterIndex: number) {
if (this.selectedItem && this.selectedItem.drilldownLayers) {
const layer = this.selectedItem.drilldownLayers[layerIndex];
if (layer && layer.filters) {
layer.filters.splice(filterIndex, 1);
}
}
}
} }

View File

@ -1,6 +1,6 @@
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core'; import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ClarityModule } from '@clr/angular'; import { ClarityModule } from '@clr/angular';
import { GridsterModule } from 'angular-gridster2'; import { GridsterModule } from 'angular-gridster2';
import { NgChartsModule } from 'ng2-charts'; import { NgChartsModule } from 'ng2-charts';
@ -32,6 +32,7 @@ import { LoadingShimmerComponent } from './components/loading-shimmer/loading-sh
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,
ReactiveFormsModule,
ClarityModule, ClarityModule,
GridsterModule, GridsterModule,
NgChartsModule, NgChartsModule,