This commit is contained in:
Gaurav Kumar
2025-11-04 17:41:18 +05:30
parent 29e50253af
commit 0e6e4899e5
3 changed files with 216 additions and 46 deletions

View File

@@ -60,6 +60,7 @@ export class EditnewdashComponent implements OnInit {
// Add availableKeys property for compact filter // Add availableKeys property for compact filter
availableKeys: string[] = []; availableKeys: string[] = [];
// Initialize with default widgets and update dynamically
WidgetsMock: WidgetModel[] = [ WidgetsMock: WidgetModel[] = [
{ {
name: 'Common Filter', name: 'Common Filter',
@@ -77,26 +78,26 @@ export class EditnewdashComponent implements OnInit {
name: 'Line Chart', name: 'Line Chart',
identifier: 'line_chart' identifier: 'line_chart'
}, },
{ // {
name: 'Bar Chart', // name: 'Bar Chart',
identifier: 'bar_chart' // identifier: 'bar_chart'
}, // },
{ // {
name: 'Pie Chart', // name: 'Pie Chart',
identifier: 'pie_chart' // identifier: 'pie_chart'
}, // },
{ // {
name: 'Polar Area Chart', // name: 'Polar Area Chart',
identifier: 'polar_area_chart' // identifier: 'polar_area_chart'
}, // },
{ // {
name: 'Bubble Chart', // name: 'Bubble Chart',
identifier: 'bubble_chart' // identifier: 'bubble_chart'
}, // },
{ // {
name: 'Scatter Chart', // name: 'Scatter Chart',
identifier: 'scatter_chart' // identifier: 'scatter_chart'
}, // },
{ {
name: 'Dynamic Chart', name: 'Dynamic Chart',
identifier: 'dynamic_chart' identifier: 'dynamic_chart'
@@ -208,6 +209,9 @@ export class EditnewdashComponent implements OnInit {
// Add drilldown column data property // Add drilldown column data property
drilldownColumnData = []; // Add drilldown column data property drilldownColumnData = []; // Add drilldown column data property
// Add chart types property for dynamic chart selection
chartTypes: any[] = [];
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private router: Router, private router: Router,
private dashboardService: Dashboard3Service, private dashboardService: Dashboard3Service,
@@ -302,12 +306,46 @@ export class EditnewdashComponent implements OnInit {
apiUrl: [''] apiUrl: ['']
}); });
// Load chart types for dynamic chart selection
this.loadChartTypesForSelection();
// Load sureconnect data first, then load dashboard data // Load sureconnect data first, then load dashboard data
this.loadSureconnectData(); this.loadSureconnectData();
// Load common filter data if it exists // Load common filter data if it exists
this.loadCommonFilterData(); this.loadCommonFilterData();
} }
// Add method to load all chart types for dynamic selection
loadChartTypesForSelection() {
console.log('Loading chart types for selection');
this.dynamicChartLoader.loadActiveChartTypes().subscribe({
next: (chartTypes) => {
console.log('Loaded chart types for selection:', chartTypes);
this.chartTypes = chartTypes;
// Convert each chart type to a WidgetModel
const newWidgets = chartTypes.map(ct => ({
name: ct.displayName || ct.name,
// identifier: ct.name.toLowerCase().replace(/\s+/g, '_')
identifier: `${ct.name.toLowerCase().replace(/\s+/g, '_')}_chart`
}));
// Filter out duplicates by identifier
const existingIds = new Set(this.WidgetsMock.map(w => w.identifier));
const uniqueNewWidgets = newWidgets.filter(w => !existingIds.has(w.identifier));
// Append unique new widgets to WidgetsMock
this.WidgetsMock = [...this.WidgetsMock, ...uniqueNewWidgets];
console.log('Updated WidgetsMock:', this.WidgetsMock);
},
error: (error) => {
console.error('Error loading chart types for selection:', error);
}
});
}
// Add method to load sureconnect data // Add method to load sureconnect data
loadSureconnectData() { loadSureconnectData() {
@@ -2151,20 +2189,7 @@ export class EditnewdashComponent implements OnInit {
}); });
} }
// Add method to load all chart types for dynamic selection
loadChartTypesForSelection() {
console.log('Loading chart types for selection');
this.dynamicChartLoader.loadActiveChartTypes().subscribe({
next: (chartTypes) => {
console.log('Loaded chart types for selection:', chartTypes);
// Here you would update the UI to show available chart types
// For example, populate a dropdown or list
},
error: (error) => {
console.error('Error loading chart types for selection:', error);
}
});
}
// Add method to create a dynamic chart with configuration from database // Add method to create a dynamic chart with configuration from database
createDynamicChart(chartTypeName: string, maxChartId: number) { createDynamicChart(chartTypeName: string, maxChartId: number) {
@@ -2212,24 +2237,24 @@ export class EditnewdashComponent implements OnInit {
error: (error) => { error: (error) => {
console.error(`Error loading configuration for ${chartTypeName}:`, error); console.error(`Error loading configuration for ${chartTypeName}:`, error);
// Fallback to default configuration // Fallback to default configuration
this.createDefaultChart(chartTypeName, maxChartId); // this.createDefaultChart(chartTypeName, maxChartId);
} }
}); });
} else { } else {
console.warn(`Chart type ${chartTypeName} not found, using default configuration`); console.warn(`Chart type ${chartTypeName} not found, using default configuration`);
this.createDefaultChart(chartTypeName, maxChartId); // this.createDefaultChart(chartTypeName, maxChartId);
} }
}, },
error: (error) => { error: (error) => {
console.error(`Error finding chart type ${chartTypeName}:`, error); console.error('Error loading configuration for chart type:', error);
// Fallback to default configuration // Fallback to default configuration
this.createDefaultChart(chartTypeName, maxChartId); // this.createDefaultChart(chartType.name, chartType.displayName || chartType.name);
} }
}); });
} }
// Fallback method to create default chart configuration // Fallback method to create default chart configuration
createDefaultChart(chartTypeName: string, maxChartId: number) { createDefaultChart(chartTypeName: string, chartDisplayName: string) {
console.log(`Creating default chart for ${chartTypeName}`); console.log(`Creating default chart for ${chartTypeName}`);
// Map chart type names to chart types // Map chart type names to chart types
@@ -2247,6 +2272,18 @@ export class EditnewdashComponent implements OnInit {
// Get the chart type from the name // Get the chart type from the name
const chartType = chartTypeMap[chartTypeName.toLowerCase()] || 'bar'; const chartType = chartTypeMap[chartTypeName.toLowerCase()] || 'bar';
// Safely calculate maxChartId, handling cases where chartid might be NaN or missing
let maxChartId = 0;
if (this.dashboardArray && this.dashboardArray.length > 0) {
const validChartIds = this.dashboardArray
.map(item => item.chartid)
.filter(chartid => typeof chartid === 'number' && !isNaN(chartid));
if (validChartIds.length > 0) {
maxChartId = Math.max(...validChartIds);
}
}
const chartItem = { const chartItem = {
cols: 5, cols: 5,
rows: 6, rows: 6,
@@ -2254,7 +2291,7 @@ export class EditnewdashComponent implements OnInit {
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: UnifiedChartComponent, component: UnifiedChartComponent,
name: this.getChartDisplayName(chartTypeName), name: chartDisplayName,
chartType: chartType, chartType: chartType,
xAxis: '', xAxis: '',
yAxis: '', yAxis: '',
@@ -2263,9 +2300,17 @@ export class EditnewdashComponent implements OnInit {
}; };
this.dashboardArray.push(chartItem); this.dashboardArray.push(chartItem);
console.log(`Created default chart:`, chartItem); console.log('Created default chart:', chartItem);
// Update the dashboard collection
this.dashboardCollection.dashboard = this.dashboardArray.slice();
// Force gridster to refresh
if (this.options && this.options.api) {
this.options.api.optionsChanged();
}
} }
// Helper method to get display name for chart type // Helper method to get display name for chart type
getChartDisplayName(chartTypeName: string): string { getChartDisplayName(chartTypeName: string): string {
const displayNameMap = { const displayNameMap = {

View File

@@ -1,4 +1,7 @@
<div class="chart-container" *ngIf="!noDataAvailable && !isLoading"> <div class="chart-container" *ngIf="!noDataAvailable && !isLoading">
<!-- Dynamic template container -->
<div class="dynamic-template-container" *ngIf="dynamicTemplate" [innerHTML]="dynamicTemplate"></div>
<!-- Back button for drilldown navigation --> <!-- Back button for drilldown navigation -->
<div class="drilldown-back" *ngIf="currentDrilldownLevel > 0"> <div class="drilldown-back" *ngIf="currentDrilldownLevel > 0">
<button class="btn btn-sm btn-secondary" (click)="navigateBack()"> <button class="btn btn-sm btn-secondary" (click)="navigateBack()">
@@ -27,7 +30,7 @@
<!-- Render different chart types based on chartType input --> <!-- Render different chart types based on chartType input -->
<div class="chart-wrapper"> <div class="chart-wrapper">
<!-- Bar Chart --> <!-- Bar Chart -->
<div *ngIf="chartType === 'bar'" class="chart-canvas-container"> <!-- <div *ngIf="chartType === 'bar'" class="chart-canvas-container">
<canvas baseChart <canvas baseChart
[datasets]="chartData" [datasets]="chartData"
[labels]="chartLabels" [labels]="chartLabels"
@@ -37,7 +40,7 @@
(chartClick)="chartClicked($event)" (chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)"> (chartHover)="chartHovered($event)">
</canvas> </canvas>
</div> </div> -->
<!-- Line Chart --> <!-- Line Chart -->
<div *ngIf="chartType === 'line'" class="chart-canvas-container"> <div *ngIf="chartType === 'line'" class="chart-canvas-container">

View File

@@ -1,9 +1,10 @@
import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges, ViewChild } from '@angular/core'; import { Component, Input, OnInit, OnChanges, OnDestroy, SimpleChanges, ViewChild, ElementRef, Renderer2 } from '@angular/core';
import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service'; import { Dashboard3Service } from '../../../../../../services/builder/dashboard3.service';
import { FilterService } from '../../common-filter/filter.service'; import { FilterService } from '../../common-filter/filter.service';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { BaseChartDirective } from 'ng2-charts'; import { BaseChartDirective } from 'ng2-charts';
import { ChartConfiguration, ChartDataset } from 'chart.js'; import { ChartConfiguration, ChartDataset } from 'chart.js';
import { DynamicChartLoaderService } from '../../chart-config/dynamic-chart-loader.service';
@Component({ @Component({
selector: 'app-unified-chart', selector: 'app-unified-chart',
@@ -75,9 +76,17 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
private documentClickHandler: ((event: MouseEvent) => void) | null = null; private documentClickHandler: ((event: MouseEvent) => void) | null = null;
private filtersInitialized: boolean = false; private filtersInitialized: boolean = false;
// Dynamic template properties
dynamicTemplate: string = '';
dynamicStyles: string = '';
dynamicOptions: any = null;
constructor( constructor(
private dashboardService: Dashboard3Service, private dashboardService: Dashboard3Service,
private filterService: FilterService private filterService: FilterService,
private dynamicChartLoader: DynamicChartLoaderService,
private renderer: Renderer2,
private el: ElementRef
) { } ) { }
ngOnInit(): void { ngOnInit(): void {
@@ -110,6 +119,10 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
// Initialize chart options with default structure // Initialize chart options with default structure
this.initializeChartOptions(); this.initializeChartOptions();
// Load dynamic template and options for this chart type
this.loadDynamicChartConfig();
this.fetchChartData(); this.fetchChartData();
} }
@@ -179,6 +192,11 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
}); });
} }
// Load dynamic template and options if chart type changed
if (chartTypeChanged) {
this.loadDynamicChartConfig();
}
// Only fetch data if the actual chart configuration changed and we're not already fetching // Only fetch data if the actual chart configuration changed and we're not already fetching
if (!this.isFetchingData && (chartTypeChanged || xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || drilldownFiltersChanged || if (!this.isFetchingData && (chartTypeChanged || xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged || drilldownFiltersChanged ||
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged || drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
@@ -217,6 +235,104 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
} }
} }
// Load dynamic chart configuration (template, styles, and options) for the current chart type
private loadDynamicChartConfig(): void {
if (!this.chartType) {
console.log('No chart type specified, skipping dynamic chart config loading');
return;
}
console.log(`Loading dynamic chart configuration for chart type: ${this.chartType}`);
// Get chart type by name and load its configuration
this.dynamicChartLoader.getChartTypeByName(this.chartType).subscribe({
next: (chartType) => {
if (chartType) {
console.log('Found chart type:', chartType);
// Load the complete configuration for this chart type
this.dynamicChartLoader.loadChartConfiguration(chartType.id).subscribe({
next: (config) => {
console.log('Loaded chart configuration:', config);
// Apply the first template if available
if (config.templates && config.templates.length > 0) {
const defaultTemplate = config.templates.find(t => t.isDefault) || config.templates[0];
if (defaultTemplate) {
this.dynamicTemplate = defaultTemplate.templateHtml || '';
this.dynamicStyles = defaultTemplate.templateCss || '';
// Apply styles to the component
this.applyDynamicStyles();
console.log('Applied dynamic template and styles');
}
}
// Apply dynamic options if available
if (config.dynamicFields && config.dynamicFields.length > 0) {
// Find the field that contains chart options
const optionsField = config.dynamicFields.find(field =>
field.fieldName === 'chartOptions' || field.fieldName.toLowerCase().includes('options'));
if (optionsField && optionsField.fieldOptions) {
try {
this.dynamicOptions = JSON.parse(optionsField.fieldOptions);
console.log('Applied dynamic chart options:', this.dynamicOptions);
// Merge dynamic options with current chart options
this.mergeDynamicOptions();
} catch (e) {
console.error('Error parsing dynamic chart options:', e);
}
}
}
},
error: (error) => {
console.error('Error loading chart configuration:', error);
}
});
} else {
console.log(`Chart type ${this.chartType} not found in database`);
}
},
error: (error) => {
console.error('Error loading chart type:', error);
}
});
}
// Merge dynamic options with current chart options
private mergeDynamicOptions(): void {
if (this.dynamicOptions) {
// Merge dynamic options with existing chart options
this.chartOptions = { ...this.chartOptions, ...this.dynamicOptions };
// If we have a chart instance, update it
if (this.chart) {
this.chart.options = this.chartOptions;
this.chart.render();
}
}
}
// Apply dynamic styles to the component
private applyDynamicStyles(): void {
// Remove any previously applied dynamic styles
const existingStyles = this.el.nativeElement.querySelectorAll('.dynamic-chart-styles');
existingStyles.forEach((style: HTMLElement) => {
style.remove();
});
// Apply new styles if available
if (this.dynamicStyles) {
const styleElement = this.renderer.createElement('style');
this.renderer.setAttribute(styleElement, 'class', 'dynamic-chart-styles');
this.renderer.setProperty(styleElement, 'textContent', this.dynamicStyles);
this.renderer.appendChild(this.el.nativeElement, styleElement);
}
}
// Check if filters are available // Check if filters are available
hasFilters(): boolean { hasFilters(): boolean {
const hasBaseFilters = this.baseFilters && this.baseFilters.length > 0; const hasBaseFilters = this.baseFilters && this.baseFilters.length > 0;
@@ -349,6 +465,12 @@ export class UnifiedChartComponent implements OnInit, OnChanges, OnDestroy {
} }
}; };
// If we have dynamic options, use them instead of the default ones
if (this.dynamicOptions) {
this.mergeDynamicOptions();
return;
}
switch (this.chartType) { switch (this.chartType) {
case 'bar': case 'bar':
this.initializeBarChartOptions(); this.initializeBarChartOptions();