26 Commits

Author SHA1 Message Date
Gaurav Kumar
3cff84c448 working unified chart with different type chart 2025-11-18 19:12:02 +05:30
Gaurav Kumar
807058e40d chart 2025-11-01 16:20:59 +05:30
Gaurav Kumar
c6022b0e22 bar chart 2025-11-01 12:34:16 +05:30
Gaurav Kumar
9aed6e0d43 Update unified-chart.component.html 2025-11-01 12:18:01 +05:30
Gaurav Kumar
64b664e625 Update editnewdash.component.ts 2025-11-01 11:00:10 +05:30
Gaurav Kumar
49f1a2fbf2 Update unified-chart.component.ts 2025-11-01 10:54:41 +05:30
Gaurav Kumar
6bfe890cd9 Update editnewdash.component.ts 2025-11-01 10:03:00 +05:30
Gaurav Kumar
3e70f85644 dashboard 2025-10-31 17:19:18 +05:30
Gaurav Kumar
482805b5cf Update editnewdash.component.ts 2025-10-31 17:17:01 +05:30
Gaurav Kumar
ffda17e6b1 unified 2025-10-31 16:35:15 +05:30
Gaurav Kumar
7396843bc6 Update report-build2all.component.html 2025-10-31 16:03:37 +05:30
Gaurav Kumar
4f75ecb3e0 builder 2025-10-31 15:51:28 +05:30
Gaurav Kumar
7c1a487114 dashboard 2025-10-31 10:47:43 +05:30
Gaurav Kumar
47e9fb92e3 Update compact-filter.component.ts 2025-10-30 12:46:39 +05:30
Gaurav Kumar
7f735dcada Update editnewdash.component.ts 2025-10-30 12:29:22 +05:30
Gaurav Kumar
bd315f42a3 compact 2025-10-29 17:55:05 +05:30
Gaurav Kumar
e8c1f46430 Update editnewdash.component.html 2025-10-29 17:30:13 +05:30
Gaurav Kumar
fa96ca81bd runner 2025-10-29 17:18:26 +05:30
Gaurav Kumar
c384f44c0c doughnut 2025-10-29 17:01:50 +05:30
Gaurav Kumar
50df914ca9 pie 2025-10-29 16:52:45 +05:30
Gaurav Kumar
e0bd888c45 polr 2025-10-29 16:14:45 +05:30
Gaurav Kumar
02b82fcaf8 Update polar-chart.component.ts 2025-10-29 16:07:59 +05:30
Gaurav Kumar
557afc348f bubble 2025-10-29 15:55:01 +05:30
Gaurav Kumar
1dec787062 Update bubble-chart.component.ts 2025-10-29 15:50:08 +05:30
Gaurav Kumar
8853cf75cf Update bubble-chart.component.ts 2025-10-29 15:42:21 +05:30
Gaurav Kumar
ad57f11f8a bubble 2025-10-29 15:34:10 +05:30
33 changed files with 5290 additions and 971 deletions

View File

@@ -1,8 +1,9 @@
export class ReportBuilder { export class ReportBuilder {
public report_id: number; public report_id: number;
public report_name:string; public report_name: string;
public description: string; public description: string;
public report_tags: string; public report_tags: string;
public servicename:string; public servicename: string;
// Add SureConnect reference
public sureConnectId: number | null;
} }

View File

@@ -23,8 +23,22 @@ export interface DashboardContentModel {
component?: any; component?: any;
name: string; name: string;
type?:string; type?:string;
// Common properties // Chart properties
xAxis?: string;
yAxis?: string | string[];
chartType?: string;
charttitle?: string;
chartlegend?: boolean;
showlabel?: boolean;
chartcolor?: boolean;
slices?: boolean;
donut?: boolean;
charturl?: string;
chartparameter?: string;
datastore?: string;
table?: string; table?: string;
datasource?: string;
fieldName?: string;
connection?: string; connection?: string;
baseFilters?: any[]; baseFilters?: any[];
// Common filter properties // Common filter properties
@@ -37,6 +51,11 @@ export interface DashboardContentModel {
drilldownParameter?: string; drilldownParameter?: string;
drilldownFilters?: any[]; drilldownFilters?: any[];
drilldownLayers?: any[]; drilldownLayers?: any[];
// Compact filter properties
filterKey?: string;
filterType?: string;
filterLabel?: string;
filterOptions?: string[];
} }
export interface DashboardModel { export interface DashboardModel {

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>gaurav</title>
</head>
<body>
<h1>this is h1</h1>
<h2>this is h1</h2>
<h3>this is h1</h3>
<h4>this is h1</h4>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ipsa fuga, asperiores mollitia iste vitae repellendus adipisci atque eum corrupti ad placeat unde voluptatum quia perferendis neque expedita, sequi iure quo. Ut error adipisci ex cum sint, suscipit, voluptatem repellat nemo dolorum unde dolores quasi aut. A earum quo mollitia voluptatibus!</p>
</body>
</html>

View File

@@ -79,7 +79,12 @@
<!-- Multi-Select Filter --> <!-- Multi-Select Filter -->
<div class="filter-control" *ngIf="filterType === 'multiselect'"> <div class="filter-control" *ngIf="filterType === 'multiselect'">
<div class="compact-multiselect-checkboxes" style="max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;"> <div class="compact-multiselect-display" (click)="toggleMultiselectDropdown()" style="padding: 5px; border: 1px solid #ddd; cursor: pointer; background-color: #f8f8f8;">
<span *ngIf="filterValue && filterValue.length > 0">{{ filterValue.length }} selected</span>
<span *ngIf="!filterValue || filterValue.length === 0">{{ filterLabel || filterKey || 'Select options' }}</span>
<clr-icon shape="caret down" style="float: right; margin-top: 3px;"></clr-icon>
</div>
<div class="compact-multiselect-dropdown" *ngIf="showMultiselectDropdown" style="max-height: 200px; overflow-y: auto; border: 1px solid #ddd; border-top: none; padding: 10px; background-color: white; position: absolute; z-index: 1000; width: calc(100% - 2px); box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<div *ngFor="let option of filterOptions" class="clr-checkbox-wrapper" style="margin-bottom: 5px;"> <div *ngFor="let option of filterOptions" class="clr-checkbox-wrapper" style="margin-bottom: 5px;">
<input type="checkbox" <input type="checkbox"
[id]="'multiselect-' + option" [id]="'multiselect-' + option"

View File

@@ -1,4 +1,4 @@
import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core'; import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges, OnDestroy } from '@angular/core';
import { FilterService, Filter } from './filter.service'; import { FilterService, Filter } from './filter.service';
import { AlertsService } from 'src/app/services/fnd/alerts.service'; import { AlertsService } from 'src/app/services/fnd/alerts.service';
@@ -7,7 +7,7 @@ import { AlertsService } from 'src/app/services/fnd/alerts.service';
templateUrl: './compact-filter.component.html', templateUrl: './compact-filter.component.html',
styleUrls: ['./compact-filter.component.scss'] styleUrls: ['./compact-filter.component.scss']
}) })
export class CompactFilterComponent implements OnInit, OnChanges { export class CompactFilterComponent implements OnInit, OnChanges, OnDestroy {
@Input() filterKey: string = ''; @Input() filterKey: string = '';
@Input() filterType: string = 'text'; @Input() filterType: string = 'text';
@Input() filterOptions: string[] = []; @Input() filterOptions: string[] = [];
@@ -23,6 +23,9 @@ export class CompactFilterComponent implements OnInit, OnChanges {
availableKeys: string[] = []; availableKeys: string[] = [];
availableValues: string[] = []; availableValues: string[] = [];
// Multiselect dropdown state
showMultiselectDropdown: boolean = false;
// Configuration properties // Configuration properties
isConfigMode: boolean = false; isConfigMode: boolean = false;
configFilterKey: string = ''; configFilterKey: string = '';
@@ -73,6 +76,24 @@ export class CompactFilterComponent implements OnInit, OnChanges {
} }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
// If filterKey changes, clear the previous filter value and remove old filter from service
if (changes.filterKey) {
// Clear the previous filter value
this.filterValue = '';
// Clear filter options
this.filterOptions = [];
// Clear available values
this.availableValues = [];
// If we had a previous selected filter, clear its value in the service
if (this.selectedFilter && changes.filterKey.previousValue) {
const oldFilterId = changes.filterKey.previousValue;
this.filterService.updateFilterValue(oldFilterId, '');
}
}
// If filterKey or filterType changes, re-register the filter // If filterKey or filterType changes, re-register the filter
if (changes.filterKey || changes.filterType) { if (changes.filterKey || changes.filterType) {
// Load available values for the current filter key if it's a dropdown or multiselect // Load available values for the current filter key if it's a dropdown or multiselect
@@ -201,6 +222,14 @@ export class CompactFilterComponent implements OnInit, OnChanges {
this.onFilterValueChange(dateRange); this.onFilterValueChange(dateRange);
} }
ngOnDestroy(): void {
// Component cleanup - remove this filter from the filter service
if (this.selectedFilter) {
// Use the proper removeFilter method which handles both filter definition and state
this.filterService.removeFilter(this.selectedFilter.id);
}
}
// Load available keys from API // Load available keys from API
loadAvailableKeys(): void { loadAvailableKeys(): void {
if (this.apiUrl) { if (this.apiUrl) {
@@ -278,6 +307,9 @@ export class CompactFilterComponent implements OnInit, OnChanges {
this.apiUrl = config.apiUrl; this.apiUrl = config.apiUrl;
this.connectionId = config.connectionId; this.connectionId = config.connectionId;
// Clear filter value when changing configuration
this.filterValue = '';
// Load available keys if API URL is provided // Load available keys if API URL is provided
if (this.apiUrl) { if (this.apiUrl) {
this.loadAvailableKeys(); this.loadAvailableKeys();
@@ -304,11 +336,23 @@ export class CompactFilterComponent implements OnInit, OnChanges {
// Handle filter key change in configuration // Handle filter key change in configuration
onFilterKeyChange(key: string): void { onFilterKeyChange(key: string): void {
// Clear the previous filter value when changing keys
this.filterValue = '';
// Clear filter options until new values are loaded
this.filterOptions = [];
this.configFilterKey = key; this.configFilterKey = key;
// Load available values for the selected key if it's a dropdown or multiselect // Load available values for the selected key if it's a dropdown or multiselect
if ((this.configFilterType === 'dropdown' || this.configFilterType === 'multiselect') && key) { if ((this.configFilterType === 'dropdown' || this.configFilterType === 'multiselect') && key) {
this.loadAvailableValues(key); this.loadAvailableValues(key);
} }
// Clear the filter service value for the previous filter key
if (this.selectedFilter) {
this.filterService.updateFilterValue(this.selectedFilter.id, '');
}
} }
// Handle API URL change in configuration // Handle API URL change in configuration
@@ -375,4 +419,23 @@ export class CompactFilterComponent implements OnInit, OnChanges {
// Emit the change event // Emit the change event
this.onFilterValueChange(this.filterValue); this.onFilterValueChange(this.filterValue);
} }
// Add method to toggle multiselect dropdown visibility
toggleMultiselectDropdown(): void {
this.showMultiselectDropdown = !this.showMultiselectDropdown;
// Add document click handler to close dropdown when clicking outside
if (this.showMultiselectDropdown) {
setTimeout(() => {
const handleClick = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (!target.closest('.compact-multiselect-display') && !target.closest('.compact-multiselect-dropdown')) {
this.showMultiselectDropdown = false;
document.removeEventListener('click', handleClick);
}
};
document.addEventListener('click', handleClick);
}, 0);
}
}
} }

View File

@@ -7,8 +7,8 @@
</ol> --> </ol> -->
<div style="display: inline;"> <div style="display: inline;">
<button class="btn componentbtn" (click)="toggleMenu()"><clr-icon shape="plus"></clr-icon>component</button> <button class="btn componentbtn" (click)="toggleMenu()" *ngIf="!fromRunner"><clr-icon shape="plus"></clr-icon>component</button>
<button class="btn btn-primary" (click)="openCommonFilterModal()" style="margin-left: 10px;"> <button class="btn btn-primary" (click)="openCommonFilterModal()" style="margin-left: 10px;" *ngIf="!fromRunner">
<clr-icon shape="filter"></clr-icon> Common Filter <clr-icon shape="filter"></clr-icon> Common Filter
</button> </button>
<div style="display: inline;"> <div style="display: inline;">
@@ -22,7 +22,7 @@
</div> </div>
<div class="content-container"> <div class="content-container">
<nav class="sidenav" *ngIf="toggle" style="width: 16%;"> <nav class="sidenav" *ngIf="toggle && !fromRunner" style="width: 16%;">
<ul class="nav-list" style="list-style-type: none;"> <ul class="nav-list" style="list-style-type: none;">
<li *ngFor="let widget of WidgetsMock"> <li *ngFor="let widget of WidgetsMock">
@@ -42,14 +42,14 @@
<gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent;"> <gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent;">
<gridster-item [item]="item" *ngFor="let item of dashboardArray"> <gridster-item [item]="item" *ngFor="let item of dashboardArray">
<!-- <ng-container *ngIf="addToDashboard && item.addToDashboard"> --> <!-- <ng-container *ngIf="addToDashboard && item.addToDashboard"> -->
<button class="btn btn-icon btn-danger" style="margin-left: 10px; margin-top: 10px;" (click)="removeItem(item)"> <button class="btn btn-icon btn-danger" style="margin-left: 10px; margin-top: 10px;" (click)="removeItem(item)" *ngIf="!fromRunner">
<clr-icon shape="trash"></clr-icon> <clr-icon shape="trash"></clr-icon>
</button> </button>
<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;" *ngIf="!fromRunner">
<clr-icon shape="drag-handle"></clr-icon> <clr-icon shape="drag-handle"></clr-icon>
</button> </button>
<button class="btn btn-icon" style="margin-top: 10px; float: right;"> <button class="btn btn-icon" style="margin-top: 10px; float: right;" *ngIf="!fromRunner">
<input type="checkbox" clrToggle [(ngModel)]="item.addToDashboard" name="addToDashboardSwitch" <input type="checkbox" clrToggle [(ngModel)]="item.addToDashboard" name="addToDashboardSwitch"
(change)="toggleAddToDashboard(item)" /> (change)="toggleAddToDashboard(item)" />
</button> </button>
@@ -57,7 +57,7 @@
<!-- <label for="workflow_name">Add to Dasboard</label> <!-- <label for="workflow_name">Add to Dasboard</label>
<input class="btn btn-icon" style="margin-top: 10px;float: right;" type="checkbox" clrToggle value="billable" name="billable" /> <input class="btn btn-icon" style="margin-top: 10px;float: right;" type="checkbox" clrToggle value="billable" name="billable" />
--> -->
<button class="btn btn-icon" style="margin-top: 10px;float: right;" (click)="editGadget(item)"> <button class="btn btn-icon" style="margin-top: 10px;float: right;" (click)="editGadget(item)" *ngIf="!fromRunner">
<clr-icon shape="pencil"></clr-icon> <clr-icon shape="pencil"></clr-icon>
</button> </button>
@@ -72,7 +72,7 @@
</div> </div>
<div style="text-align: center;"> <div style="text-align: center;">
<button class="btn btn-outline" (click)="goBack()">Back</button> <button class="btn btn-outline" (click)="goBack()">Back</button>
<button type="submit" class="btn btn-primary btn-adddata " (click)="UpdateLine()"> <button type="submit" class="btn btn-primary btn-adddata " (click)="UpdateLine()" *ngIf="!fromRunner">
<b>Update</b> <b>Update</b>
</button> </button>
</div> </div>

View File

@@ -26,6 +26,10 @@ import { SureconnectService } from '../sureconnect/sureconnect.service';
import { CommonFilterComponent } from '../common-filter/common-filter.component'; import { CommonFilterComponent } from '../common-filter/common-filter.component';
// Add the CompactFilterComponent import // Add the CompactFilterComponent import
import { CompactFilterComponent } from '../common-filter'; import { CompactFilterComponent } from '../common-filter';
// Add the FilterService import
import { FilterService } from '../common-filter/filter.service';
// Add the UnifiedChartComponent import
import { UnifiedChartComponent } from '../gadgets/unified-chart';
function isNullArray(arr) { function isNullArray(arr) {
return !Array.isArray(arr) || arr.length === 0; return !Array.isArray(arr) || arr.length === 0;
@@ -110,6 +114,10 @@ export class EditnewdashComponent implements OnInit {
{ {
name: 'Compact Filter', name: 'Compact Filter',
identifier: 'compact_filter' identifier: 'compact_filter'
},
{
name: 'Unified Chart',
identifier: 'unified_chart'
} }
] ]
@@ -123,19 +131,20 @@ export class EditnewdashComponent implements OnInit {
protected componentCollection = [ protected componentCollection = [
{ name: "Common Filter", componentInstance: CommonFilterComponent }, { name: "Common Filter", componentInstance: CommonFilterComponent },
{ name: "Line Chart", componentInstance: LineChartComponent }, { name: "Line Chart", componentInstance: UnifiedChartComponent },
{ name: "Doughnut Chart", componentInstance: DoughnutChartComponent }, { name: "Doughnut Chart", componentInstance: UnifiedChartComponent },
{ name: "Radar Chart", componentInstance: RadarChartComponent }, { name: "Radar Chart", componentInstance: UnifiedChartComponent },
{ name: "Bar Chart", componentInstance: BarChartComponent }, { name: "Bar Chart", componentInstance: UnifiedChartComponent },
{ name: "Pie Chart", componentInstance: PieChartComponent }, { name: "Pie Chart", componentInstance: UnifiedChartComponent },
{ name: "Polar Area Chart", componentInstance: PolarChartComponent }, { name: "Polar Area Chart", componentInstance: UnifiedChartComponent },
{ name: "Bubble Chart", componentInstance: BubbleChartComponent }, { name: "Bubble Chart", componentInstance: UnifiedChartComponent },
{ name: "Scatter Chart", componentInstance: ScatterChartComponent }, { name: "Scatter Chart", componentInstance: UnifiedChartComponent },
{ name: "Dynamic Chart", componentInstance: DynamicChartComponent }, { name: "Dynamic Chart", componentInstance: UnifiedChartComponent },
{ name: "Financial Chart", componentInstance: FinancialChartComponent }, { name: "Financial Chart", componentInstance: UnifiedChartComponent },
{ name: "To Do Chart", componentInstance: ToDoChartComponent }, { name: "To Do Chart", componentInstance: ToDoChartComponent },
{ name: "Grid View", componentInstance: GridViewComponent }, { name: "Grid View", componentInstance: GridViewComponent },
{ name: "Compact Filter", componentInstance: CompactFilterComponent }, // Add this line { name: "Compact Filter", componentInstance: CompactFilterComponent },
{ name: "Unified Chart", componentInstance: UnifiedChartComponent },
]; ];
model: any; model: any;
linesdata: any; linesdata: any;
@@ -168,6 +177,7 @@ export class EditnewdashComponent implements OnInit {
yAxis: '', yAxis: '',
xAxis: '', xAxis: '',
connection: '', // Add connection field connection: '', // Add connection field
chartType: '', // Add chartType field
// Drilldown configuration properties (base level) // Drilldown configuration properties (base level)
drilldownEnabled: false, drilldownEnabled: false,
drilldownApiUrl: '', drilldownApiUrl: '',
@@ -203,9 +213,15 @@ export class EditnewdashComponent implements OnInit {
private _fb: FormBuilder, private _fb: FormBuilder,
private datastoreService: DatastoreService, private datastoreService: DatastoreService,
private alertService: AlertsService, private alertService: AlertsService,
private sureconnectService: SureconnectService) { } // Add SureconnectService to constructor private sureconnectService: SureconnectService,
private filterService: FilterService) { } // Add SureconnectService and FilterService to constructor
// Add property to track if coming from dashboard runner
fromRunner: boolean = false;
ngOnInit(): void { ngOnInit(): void {
// Reset the filter service when the component is initialized
this.filterService.resetFilters();
// Grid options // Grid options
this.options = { this.options = {
@@ -231,6 +247,13 @@ export class EditnewdashComponent implements OnInit {
itemResizeCallback: this.itemResize.bind(this) itemResizeCallback: this.itemResize.bind(this)
}; };
// Check if coming from dashboard runner
this.route.queryParams.subscribe(params => {
if (params['fromRunner'] === 'true') {
this.fromRunner = true;
}
});
this.editId = this.route.snapshot.params.id; this.editId = this.route.snapshot.params.id;
console.log(this.editId); console.log(this.editId);
this.dashboardService.getById(this.editId).subscribe((data) => { this.dashboardService.getById(this.editId).subscribe((data) => {
@@ -317,6 +340,9 @@ export class EditnewdashComponent implements OnInit {
dashboardLine: any; dashboardLine: any;
dashboardName: any; dashboardName: any;
getData() { getData() {
// Reset the filter service when switching between dashboard records
this.filterService.resetFilters();
// We get the id in get current router dashboard/:id // We get the id in get current router dashboard/:id
this.route.params.subscribe(params => { this.route.params.subscribe(params => {
// + is used to cast string to int // + is used to cast string to int
@@ -367,6 +393,40 @@ export class EditnewdashComponent implements OnInit {
} }
}); });
// Handle charts that use UnifiedChartComponent but have different names
// After serialization, these charts have component = "Unified Chart" but their name is still "Line Chart", "Pie Chart", etc.
const unifiedChartNames = [
'Radar Chart', 'Line Chart', 'Doughnut Chart', 'Bar Chart',
'Pie Chart', 'Polar Area Chart', 'Bubble Chart', 'Scatter Chart',
'Dynamic Chart', 'Financial Chart'
];
if (dashboard.component === "Unified Chart" && unifiedChartNames.includes(dashboard.name)) {
// Restore the actual UnifiedChartComponent reference
dashboard.component = UnifiedChartComponent;
}
// Map chart names to unified chart types
const chartTypeMap = {
'Radar Chart': 'radar',
'Line Chart': 'line',
'Doughnut Chart': 'doughnut',
'Bar Chart': 'bar',
'Pie Chart': 'pie',
'Polar Area Chart': 'polar',
'Bubble Chart': 'bubble',
'Scatter Chart': 'scatter',
'Dynamic Chart': 'line',
'Financial Chart': 'line'
};
// If this is a chart, set the chartType property
if (chartTypeMap.hasOwnProperty(dashboard.name)) {
dashboard.chartType = chartTypeMap[dashboard.name];
// Keep the original name instead of changing it to "Unified Chart"
// dashboard.name = "Unified Chart";
}
// Ensure compact filter configuration properties are properly initialized // Ensure compact filter configuration properties are properly initialized
if (dashboard.component === 'Compact Filter' || dashboard.name === 'Compact Filter') { if (dashboard.component === 'Compact Filter' || dashboard.name === 'Compact Filter') {
// Make sure all compact filter properties exist // Make sure all compact filter properties exist
@@ -391,6 +451,37 @@ export class EditnewdashComponent implements OnInit {
} }
}); });
// Map unified chart types back to chart names for serialization
const chartNameMap = {
'radar': 'Radar Chart',
'line': 'Line Chart',
'doughnut': 'Doughnut Chart',
'bar': 'Bar Chart',
'pie': 'Pie Chart',
'polar': 'Polar Area Chart',
'bubble': 'Bubble Chart',
'scatter': 'Scatter Chart'
};
// If this is a unified chart, set the name back to the appropriate chart name
if (dashboard.name === 'Unified Chart' && dashboard.chartType && chartNameMap.hasOwnProperty(dashboard.chartType)) {
dashboard.name = chartNameMap[dashboard.chartType];
}
// Also handle the case where the chart already has the correct name
else if (dashboard.chartType && chartNameMap.hasOwnProperty(dashboard.chartType) &&
dashboard.name === chartNameMap[dashboard.chartType]) {
// The name is already correct, no need to change it
dashboard.component = "Unified Chart";
}
// Handle charts that use UnifiedChartComponent but have different names
else if (dashboard.component === UnifiedChartComponent && dashboard.chartType) {
// Preserve the chartType property for UnifiedChartComponent
// The name should already be correct (e.g., "Line Chart", "Pie Chart", etc.)
// Instead of changing the component reference, we preserve it and only change the component name for serialization
// But we need to ensure the component name is set correctly for proper deserialization
dashboard.component = "Unified Chart";
}
// Ensure compact filter configuration properties are preserved // Ensure compact filter configuration properties are preserved
if (dashboard.name === 'Compact Filter') { if (dashboard.name === 'Compact Filter') {
// Make sure all compact filter properties exist // Make sure all compact filter properties exist
@@ -402,6 +493,7 @@ export class EditnewdashComponent implements OnInit {
} }
}); });
} }
// Add method to get available fields for a filter dropdown (excluding already selected fields) // Add method to get available fields for a filter dropdown (excluding already selected fields)
getAvailableFields(filters: any[], currentIndex: number, allFields: string[]): string[] { getAvailableFields(filters: any[], currentIndex: number, allFields: string[]): string[] {
if (!filters || !allFields) { if (!filters || !allFields) {
@@ -435,8 +527,19 @@ export class EditnewdashComponent implements OnInit {
onDrop(ev) { onDrop(ev) {
const componentType = ev.dataTransfer.getData("widgetIdentifier"); const componentType = ev.dataTransfer.getData("widgetIdentifier");
let maxChartId = this.dashboardArray?.reduce((maxId, item) => Math.max(maxId, item.chartid), 0); // 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);
}
}
switch (componentType) { switch (componentType) {
// Handle all chart types by converting them to unified charts
case "radar_chart": case "radar_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
cols: 5, cols: 5,
@@ -444,8 +547,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: RadarChartComponent, component: UnifiedChartComponent,
name: "Radar Chart" name: "Radar Chart",
chartType: 'radar',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "line_chart": case "line_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -454,8 +562,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: LineChartComponent, component: UnifiedChartComponent,
name: "Line Chart" name: "Line Chart",
chartType: 'line',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "doughnut_chart": case "doughnut_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -464,8 +577,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: DoughnutChartComponent, component: UnifiedChartComponent,
name: "Doughnut Chart" name: "Doughnut Chart",
chartType: 'doughnut',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "bar_chart": case "bar_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -474,8 +592,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: BarChartComponent, component: UnifiedChartComponent,
name: "Bar Chart" name: "Bar Chart",
chartType: 'bar',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "pie_chart": case "pie_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -484,8 +607,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: PieChartComponent, component: UnifiedChartComponent,
name: "Pie Chart" name: "Pie Chart",
chartType: 'pie',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "polar_area_chart": case "polar_area_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -494,8 +622,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: PolarChartComponent, component: UnifiedChartComponent,
name: "Polar Area Chart" name: "Polar Area Chart",
chartType: 'polar',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "bubble_chart": case "bubble_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -504,8 +637,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: BubbleChartComponent, component: UnifiedChartComponent,
name: "Bubble Chart" name: "Bubble Chart",
chartType: 'bubble',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "scatter_chart": case "scatter_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -514,8 +652,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: ScatterChartComponent, component: UnifiedChartComponent,
name: "Scatter Chart" name: "Scatter Chart",
chartType: 'scatter',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "dynamic_chart": case "dynamic_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -524,8 +667,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: DynamicChartComponent, component: UnifiedChartComponent,
name: "Dynamic Chart" name: "Dynamic Chart",
chartType: 'line', // Default to line for dynamic chart
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "financial_chart": case "financial_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -534,8 +682,13 @@ export class EditnewdashComponent implements OnInit {
x: 0, x: 0,
y: 0, y: 0,
chartid: maxChartId + 1, chartid: maxChartId + 1,
component: FinancialChartComponent, component: UnifiedChartComponent,
name: "Financial Chart" name: "Financial Chart",
chartType: 'line', // Default to line for financial chart
xAxis: '',
yAxis: '',
table: '',
connection: undefined
}); });
case "to_do_chart": case "to_do_chart":
return this.dashboardArray.push({ return this.dashboardArray.push({
@@ -582,6 +735,22 @@ export class EditnewdashComponent implements OnInit {
component: GridViewComponent, component: GridViewComponent,
name: "Grid View" name: "Grid View"
}); });
case "unified_chart":
return this.dashboardArray.push({
cols: 5,
rows: 6,
x: 0,
y: 0,
chartid: maxChartId + 1,
component: UnifiedChartComponent,
name: "Unified Chart",
// Add default configuration for unified chart
chartType: 'bar',
xAxis: '',
yAxis: '',
table: '',
connection: undefined
});
} }
} }
removeItem(item) { removeItem(item) {
@@ -599,6 +768,12 @@ export class EditnewdashComponent implements OnInit {
modelid: number; modelid: number;
// Update the editGadget method to initialize filter properties // Update the editGadget method to initialize filter properties
editGadget(item) { editGadget(item) {
// If coming from dashboard runner, skip showing the config modal
if (this.fromRunner) {
console.log('Coming from dashboard runner, skipping config modal');
return;
}
this.modeledit = true; this.modeledit = true;
this.modelid = item.chartid; this.modelid = item.chartid;
console.log(this.modelid); console.log(this.modelid);
@@ -628,6 +803,10 @@ export class EditnewdashComponent implements OnInit {
if (item['filterOptions'] === undefined) { if (item['filterOptions'] === undefined) {
this.gadgetsEditdata['filterOptions'] = []; this.gadgetsEditdata['filterOptions'] = [];
} }
// Initialize chartType property if not present (for unified chart)
if (item['chartType'] === undefined) {
this.gadgetsEditdata['chartType'] = 'bar';
}
// Initialize filterOptionsString for compact filter // Initialize filterOptionsString for compact filter
if (item.name === 'Compact Filter') { if (item.name === 'Compact Filter') {
@@ -734,15 +913,34 @@ export class EditnewdashComponent implements OnInit {
this.refreshBaseDrilldownColumns(); this.refreshBaseDrilldownColumns();
} }
if (item.datastore !== undefined || '' || null) { // Check if we have either datastore or table to fetch columns
if ((item.datastore !== undefined && item.datastore !== '' && item.datastore !== null) ||
(item.table !== undefined && item.table !== '' && item.table !== null)) {
const datastore = item.datastore; const datastore = item.datastore;
this.getTables(datastore);
const table = item.table; const table = item.table;
// Fetch tables if datastore is available
if (datastore) {
this.getTables(datastore);
}
// Fetch columns if table is available
if (table) {
this.getColumns(datastore, table); this.getColumns(datastore, table);
}
console.log(item.yAxis); console.log(item.yAxis);
// Set selectedyAxis regardless of whether it's an array or string
if (item.yAxis !== undefined && item.yAxis !== '' && item.yAxis !== null) {
if (isArray(item.yAxis)) { if (isArray(item.yAxis)) {
this.selectedyAxis = item.yAxis; this.selectedyAxis = item.yAxis;
} else {
// For single yAxis values, convert to array
this.selectedyAxis = [item.yAxis];
}
console.log(this.selectedyAxis); console.log(this.selectedyAxis);
} else {
this.selectedyAxis = [];
} }
} else { } else {
this.selectedyAxis = []; this.selectedyAxis = [];
@@ -816,12 +1014,29 @@ export class EditnewdashComponent implements OnInit {
// Update the onSubmit method to properly save filter data // Update the onSubmit method to properly save filter data
onSubmit(id) { onSubmit(id) {
console.log(id); console.log(id);
if (!isNullArray(this.selectedyAxis)) {
console.log("get y-axis array", this.selectedyAxis); // Check if ID is valid, including handling NaN
if (id === null || id === undefined || isNaN(id)) {
console.warn('Chart ID is null, undefined, or NaN, using modelid instead:', this.modelid);
id = this.modelid;
}
// Ensure we have a valid numeric ID
const numId = typeof id === 'number' ? id : parseInt(id, 10);
if (isNaN(numId)) {
console.error('Unable to determine valid chart ID, aborting onSubmit');
return;
}
// Handle both array and string yAxis values
if (this.selectedyAxis !== undefined && this.selectedyAxis !== null &&
((Array.isArray(this.selectedyAxis) && this.selectedyAxis.length > 0) ||
(typeof this.selectedyAxis === 'string' && this.selectedyAxis !== ''))) {
console.log("get y-axis", this.selectedyAxis);
this.entryForm.patchValue({ yAxis: this.selectedyAxis }); this.entryForm.patchValue({ yAxis: this.selectedyAxis });
} }
let formdata = this.entryForm.value; let formdata = this.entryForm.value;
let num = id; let num = numId;
console.log(this.entryForm.value); console.log(this.entryForm.value);
this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => { this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => {
if (item.chartid == num) { if (item.chartid == num) {
@@ -860,6 +1075,18 @@ export class EditnewdashComponent implements OnInit {
xyz.connection = this.gadgetsEditdata.connection || undefined; xyz.connection = this.gadgetsEditdata.connection || undefined;
} }
// For unified chart, preserve chart configuration properties
// Check if this item uses UnifiedChartComponent
const unifiedChartNames = [
'Radar Chart', 'Line Chart', 'Doughnut Chart', 'Bar Chart',
'Pie Chart', 'Polar Area Chart', 'Bubble Chart', 'Scatter Chart',
'Dynamic Chart', 'Financial Chart', 'Unified Chart'
];
if (unifiedChartNames.includes(item.name)) {
xyz.chartType = this.gadgetsEditdata.chartType || 'bar';
}
console.log(xyz); console.log(xyz);
return xyz; return xyz;
} }
@@ -943,6 +1170,55 @@ export class EditnewdashComponent implements OnInit {
return commonFilterInputs; return commonFilterInputs;
} }
// For UnifiedChartComponent, pass chart properties with chartType
// Check for specific chart names that use UnifiedChartComponent
const unifiedChartNames = [
'Radar Chart', 'Line Chart', 'Doughnut Chart', 'Bar Chart',
'Pie Chart', 'Polar Area Chart', 'Bubble Chart', 'Scatter Chart',
'Dynamic Chart', 'Financial Chart', 'Unified Chart'
];
if (unifiedChartNames.includes(item.name)) {
const unifiedChartInputs = {
chartType: item.chartType || 'bar',
xAxis: item.xAxis,
yAxis: item.yAxis,
table: item.table,
datastore: item.datastore,
charttitle: item.charttitle,
chartlegend: item.chartlegend,
showlabel: item.showlabel,
chartcolor: item.chartcolor,
slices: item.slices,
donut: item.donut,
charturl: item.charturl,
chartparameter: item.chartparameter,
datasource: item.datasource,
fieldName: item.name, // Using item.name as fieldName
connection: item['connection'], // Add connection field using bracket notation
// Base drilldown configuration properties
drilldownEnabled: item['drilldownEnabled'],
drilldownApiUrl: item['drilldownApiUrl'],
// Removed drilldownParameterKey since we're using URL templates
drilldownXAxis: item['drilldownXAxis'],
drilldownYAxis: item['drilldownYAxis'],
drilldownParameter: item['drilldownParameter'], // Add drilldown parameter
baseFilters: item['baseFilters'] || [], // Add base filters
drilldownFilters: item['drilldownFilters'] || [], // Add drilldown filters
// Multi-layer drilldown configurations
drilldownLayers: item['drilldownLayers'] || []
};
// Remove undefined properties to avoid passing unnecessary data
Object.keys(unifiedChartInputs).forEach(key => {
if (unifiedChartInputs[key] === undefined) {
delete unifiedChartInputs[key];
}
});
return unifiedChartInputs;
}
// For GridViewComponent, pass chart properties with drilldown support // For GridViewComponent, pass chart properties with drilldown support
if (item.component && item.component.name === 'GridViewComponent') { if (item.component && item.component.name === 'GridViewComponent') {
const gridInputs = { const gridInputs = {
@@ -1028,15 +1304,25 @@ export class EditnewdashComponent implements OnInit {
applyChanges(id) { applyChanges(id) {
console.log('Apply changes for chart ID:', id); console.log('Apply changes for chart ID:', id);
// Check if ID is valid // Check if ID is valid, including handling NaN
if (id === null || id === undefined) { if (id === null || id === undefined || isNaN(id)) {
console.warn('Chart ID is null or undefined, using modelid instead:', this.modelid); console.warn('Chart ID is null, undefined, or NaN, using modelid instead:', this.modelid);
id = this.modelid; id = this.modelid;
} }
// Update the form with selected Y-axis values if it's an array // Ensure we have a valid numeric ID
if (!isNullArray(this.selectedyAxis)) { const numId = typeof id === 'number' ? id : parseInt(id, 10);
console.log("get y-axis array", this.selectedyAxis); if (isNaN(numId)) {
console.error('Unable to determine valid chart ID, aborting applyChanges');
return;
}
// Update the form with selected Y-axis values
// Handle both array and string yAxis values
if (this.selectedyAxis !== undefined && this.selectedyAxis !== null &&
((Array.isArray(this.selectedyAxis) && this.selectedyAxis.length > 0) ||
(typeof this.selectedyAxis === 'string' && this.selectedyAxis !== ''))) {
console.log("get y-axis", this.selectedyAxis);
this.entryForm.patchValue({ yAxis: this.selectedyAxis }); this.entryForm.patchValue({ yAxis: this.selectedyAxis });
} }
@@ -1090,6 +1376,18 @@ export class EditnewdashComponent implements OnInit {
this.gadgetsEditdata.filterOptions = updatedItem.filterOptions; this.gadgetsEditdata.filterOptions = updatedItem.filterOptions;
} }
// For unified chart, preserve chart configuration properties
// Check if this item uses UnifiedChartComponent
const unifiedChartNames = [
'Radar Chart', 'Line Chart', 'Doughnut Chart', 'Bar Chart',
'Pie Chart', 'Polar Area Chart', 'Bubble Chart', 'Scatter Chart',
'Dynamic Chart', 'Financial Chart', 'Unified Chart'
];
if (unifiedChartNames.includes(item.name)) {
updatedItem.chartType = this.gadgetsEditdata.chartType || 'bar';
}
console.log('Updated item:', updatedItem); console.log('Updated item:', updatedItem);
return updatedItem; return updatedItem;
} }
@@ -1127,6 +1425,9 @@ export class EditnewdashComponent implements OnInit {
// Note: We don't close the modal here, allowing the user to make additional changes // Note: We don't close the modal here, allowing the user to make additional changes
// The user can click "Save" when they're done with all changes // The user can click "Save" when they're done with all changes
// Reset the filter service to ensure clean state
this.filterService.resetFilters();
} }
goBack() { goBack() {

View File

@@ -279,19 +279,32 @@
</div> </div>
</div> </div>
<!-- Chart container -->
<div style="position: relative; height: calc(100% - 80px); width: 100%; padding: 0 10px 30px 10px;">
<!-- Loading indicator -->
<div *ngIf="!dataLoaded" style="text-align: center; padding: 20px; color: #666; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; width: 100%;">
Loading data...
</div>
<!-- No data message --> <!-- No data message -->
<div *ngIf="noDataAvailable" style="text-align: center; padding: 20px; color: #666; font-style: italic;"> <div *ngIf="dataLoaded && (noDataAvailable || !isChartDataValid())" style="text-align: center; padding: 20px; color: #666; font-style: italic; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; width: 100%;">
No data available No data available
</div> </div>
<!-- Chart display --> <!-- Chart display - Always render the canvas but conditionally show/hide with CSS -->
<div *ngIf="!noDataAvailable" style="position: relative; height: calc(100% - 50px);">
<canvas baseChart <canvas baseChart
[datasets]="bubbleChartData" [datasets]="bubbleChartData"
[type]="bubbleChartType" [type]="bubbleChartType"
[options]="bubbleChartOptions" [options]="bubbleChartOptions"
(chartHover)="chartHovered($event)" (chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"> (chartClick)="chartClicked($event)"
[style.visibility]="dataLoaded && !noDataAvailable && isChartDataValid() ? 'visible' : 'hidden'"
[style.position]="'absolute'"
[style.top]="'0'"
[style.left]="'0'"
[style.height]="'100%'"
[style.width]="'100%'"
[style.padding]="'0 10px 20px 10px'">
</canvas> </canvas>
</div> </div>
</div> </div>

View File

@@ -37,55 +37,77 @@ export class BubbleChartComponent implements OnInit, OnChanges {
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations @Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
public bubbleChartOptions: ChartConfiguration['options'] = { public bubbleChartOptions: ChartConfiguration['options'] = {
// scales: { responsive: true,
// x: { maintainAspectRatio: false,
// min: 0, scales: {
// max: 30, x: {
// ticks: {} beginAtZero: true,
// }, title: {
// y: { display: true,
// min: 0, text: 'X Axis'
// max: 30, },
// ticks: {} ticks: {
// }, autoSkip: false,
// plugins: { maxRotation: 45,
// title: { minRotation: 45
// display: true, }
// text: 'Bubble Chart' },
// } y: {
// } beginAtZero: true,
// } title: {
display: true,
text: 'Y Axis'
}
}
},
plugins: {
legend: {
display: true,
position: 'top',
},
tooltip: {
enabled: true,
mode: 'point',
intersect: false,
callbacks: {
label: function(context: any) {
const point: any = context.raw;
if (point && point.hasOwnProperty('y') && point.hasOwnProperty('r')) {
const yValue = parseFloat(point.y);
const rValue = parseFloat(point.r);
if (!isNaN(yValue) && !isNaN(rValue)) {
return `Value: ${yValue.toFixed(2)}, Size: ${rValue.toFixed(1)}`;
}
}
return context.dataset.label || '';
}
}
}
},
animation: {
duration: 800,
easing: 'easeInOutQuart'
},
// Enable individual point styling
elements: {
point: {
hoverRadius: 12,
hoverBorderWidth: 3
}
},
// Add padding to ensure x-axis labels are visible
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 30
}
}
}; };
public bubbleChartType: string = 'bubble'; public bubbleChartType: string = 'bubble';
public bubbleChartData: ChartDataset[] = [ public bubbleChartData: ChartDataset[] = [];
{
data: [
{ x: 10, y: 10, r: 10 },
{ x: 15, y: 5, r: 15 },
{ x: 26, y: 12, r: 23 },
{ x: 7, y: 8, r: 8 },
],
label: 'Investment Equities',
backgroundColor: 'rgba(255, 0, 0, 0.6)', // Red
borderColor: 'blue',
hoverBackgroundColor: 'purple',
hoverBorderColor: 'red',
},
{
data: [
{ x: 5, y: 15, r: 12 },
{ x: 20, y: 7, r: 8 },
{ x: 12, y: 18, r: 15 },
{ x: 8, y: 6, r: 10 },
],
label: 'Investment Bonds',
backgroundColor: 'rgba(0, 255, 0, 0.6)', // Green
borderColor: 'green',
hoverBackgroundColor: 'yellow',
hoverBorderColor: 'blue',
},
];
// Multi-layer drilldown state tracking // Multi-layer drilldown state tracking
drilldownStack: any[] = []; // Stack to track drilldown navigation history drilldownStack: any[] = []; // Stack to track drilldown navigation history
@@ -94,6 +116,7 @@ export class BubbleChartComponent implements OnInit, OnChanges {
// No data state // No data state
noDataAvailable: boolean = false; noDataAvailable: boolean = false;
dataLoaded: boolean = false; // Track if data has been loaded
// Flag to prevent infinite loops // Flag to prevent infinite loops
private isFetchingData: boolean = false; private isFetchingData: boolean = false;
@@ -465,45 +488,250 @@ export class BubbleChartComponent implements OnInit, OnChanges {
this.fetchChartData(); this.fetchChartData();
} }
// Helper function to replace alpha value in RGBA color string
private replaceAlpha(color: string, newAlpha: number): string {
// Match rgba(r, g, b, a) format and replace alpha value
return color.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*[\d.]+\)/, `rgba($1, $2, $3, ${newAlpha})`);
}
// Function to generate different colors for bubbles
private generateBubbleColor(index: number, value: number, total: number): string {
// Generate colors based on index or value
// Using HSL color model for better color distribution
const hue = (index * 137.508) % 360; // Golden angle approximation for good distribution
const saturation = 80 + (index % 20); // High saturation for vibrant colors
const lightness = 40 + (index % 30); // Vary lightness for contrast
// Convert HSL to RGB
const h = hue / 360;
const s = saturation / 100;
const l = lightness / 100;
const rgb = this.hslToRgb(h, s, l);
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.7)`;
}
// Helper function to convert HSL to RGB
private hslToRgb(h: number, s: number, l: number): { r: number, g: number, b: number } {
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const hue2rgb = (p: number, q: number, t: number) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
}
// Helper function to calculate logarithmic scaling
private logScale(value: number, min: number, max: number, minRadius: number, maxRadius: number): number {
if (min === max) return (minRadius + maxRadius) / 2;
// Normalize value to 0-1 range
const normalized = (value - min) / (max - min);
// Apply logarithmic scaling (base 10)
// Add 1 to avoid log(0) and scale to 1-10 range
const logValue = Math.log10(normalized * 9 + 1);
// Scale to desired radius range
return minRadius + (logValue / Math.log10(10)) * (maxRadius - minRadius);
}
// Transform data to bubble chart format // Transform data to bubble chart format
private transformToBubbleData(labels: any[], data: any[]): ChartDataset[] { private transformToBubbleData(labels: any[], data: any[]): ChartDataset[] {
// For bubble charts, we need to transform the data into bubble format // For bubble charts, we need to transform the data into bubble format
// Bubble charts expect data in the format: {x: number, y: number, r: number} // Bubble charts expect data in the format: {x: number, y: number, r: number}
console.log('Transforming data to bubble format:', { labels, data }); console.log('Transforming data to bubble format:', { labels, data });
// Handle null/undefined data
if (!labels || !data) {
console.log('Labels or data is null/undefined, returning empty dataset');
return [];
}
// If we have the expected bubble data format, return it as is // If we have the expected bubble data format, return it as is
if (data && data.length > 0 && data[0].data && data[0].data.length > 0 && if (data && data.length > 0 && data[0].data && data[0].data.length > 0 &&
typeof data[0].data[0] === 'object' && data[0].data[0].hasOwnProperty('x') && typeof data[0].data[0] === 'object' && data[0].data[0].hasOwnProperty('x') &&
data[0].data[0].hasOwnProperty('y') && data[0].data[0].hasOwnProperty('r')) { data[0].data[0].hasOwnProperty('y') && data[0].data[0].hasOwnProperty('r')) {
console.log('Data is already in bubble format, returning as is');
return data; return data;
} }
// Otherwise, create a default bubble dataset // Transform the data properly for bubble chart
// Assuming labels are x-values and data[0].data are y-values
if (labels && data && data.length > 0 && data[0].data) {
console.log('Transforming regular data to bubble format');
const yValues = data[0].data;
const label = data[0].label || 'Dataset 1';
// Handle case where yValues might not be an array
if (!Array.isArray(yValues)) {
console.log('yValues is not an array, returning empty dataset');
return [];
}
console.log('yValues type:', typeof yValues);
console.log('yValues length:', yValues.length);
console.log('First few yValues:', yValues.slice(0, 5));
// Find min and max values for scaling
let minValue = Infinity;
let maxValue = -Infinity;
const validYValues = [];
// First pass: collect valid values and find min/max
for (let i = 0; i < yValues.length; i++) {
let y;
if (typeof yValues[i] === 'string') {
y = parseFloat(yValues[i]);
} else {
y = yValues[i];
}
if (!isNaN(y)) {
validYValues.push(y);
minValue = Math.min(minValue, y);
maxValue = Math.max(maxValue, y);
}
}
console.log('Value range:', { minValue, maxValue });
// Adjust radius range based on number of data points
// For fewer points, we can use larger bubbles; for more points, smaller bubbles to prevent overlap
const dataPointCount = Math.min(labels.length, yValues.length);
let minRadius = 3;
let maxRadius = 30;
// Adjust radius range based on data point count
if (dataPointCount > 50) {
minRadius = 2;
maxRadius = 20;
} else if (dataPointCount > 20) {
minRadius = 3;
maxRadius = 25;
}
console.log('Radius range:', { minRadius, maxRadius, dataPointCount });
// Create bubble points from labels (x) and data (y)
const bubblePoints = [];
const bubbleColors = [];
const minLength = Math.min(labels.length, yValues.length);
console.log('Processing data points:', { labels, yValues, minLength });
for (let i = 0; i < minLength; i++) {
// Log each point for debugging
console.log(`Processing point ${i}: label=${labels[i]}, yValue=${yValues[i]}, type=${typeof yValues[i]}`);
// Convert y to number if it's a string
let y;
if (typeof yValues[i] === 'string') {
y = parseFloat(yValues[i]);
console.log(`Converted string yValue to number: ${yValues[i]} -> ${y}`);
} else {
y = yValues[i];
}
// Handle NaN values
if (isNaN(y)) {
console.log(`Skipping point ${i} due to NaN y value: ${yValues[i]}`);
continue;
}
// Calculate radius based on the y-value with logarithmic scaling
const r = this.logScale(y, minValue, maxValue, minRadius, maxRadius);
console.log(`Value: ${y}, Radius: ${r}`);
// For x-value, we'll use the index position since labels are strings
const x = i;
// Generate a unique color for this bubble
const backgroundColor = this.generateBubbleColor(i, y, minLength);
// Store the color for the dataset
bubbleColors.push(backgroundColor);
// Add the point
const point = {
x,
y,
r
};
console.log(`Adding point ${i}:`, point);
bubblePoints.push(point);
}
console.log('Generated bubble points:', bubblePoints);
console.log('Generated bubble points count:', bubblePoints.length);
console.log('Generated bubble colors count:', bubbleColors.length);
// If we have no valid points, return empty array
if (bubblePoints.length === 0) {
console.log('No valid bubble points generated, returning empty dataset');
return [];
}
// Create a single dataset with all bubble points
const bubbleDatasets: ChartDataset[] = [ const bubbleDatasets: ChartDataset[] = [
{ {
data: [ data: bubblePoints,
{ x: 10, y: 10, r: 10 }, label: label,
{ x: 15, y: 5, r: 15 }, backgroundColor: bubbleColors,
{ x: 26, y: 12, r: 23 }, borderColor: bubbleColors.map(color => this.replaceAlpha(color, 1)), // Slightly more opaque border
{ x: 7, y: 8, r: 8 }, hoverBackgroundColor: bubbleColors.map(color => this.replaceAlpha(color, 0.9)),
], hoverBorderColor: 'rgba(255, 255, 255, 1)',
label: 'Dataset 1', borderWidth: 2,
backgroundColor: 'rgba(255, 0, 0, 0.6)', pointHoverRadius: 10,
borderColor: 'blue',
hoverBackgroundColor: 'purple',
hoverBorderColor: 'red',
} }
]; ];
console.log('Transformed bubble data:', bubbleDatasets);
return bubbleDatasets; return bubbleDatasets;
} }
console.log('Could not transform data, returning empty dataset');
// Return empty dataset instead of default data
return [];
}
fetchChartData(): void { fetchChartData(): void {
// Set flag to prevent recursive calls // Set flag to prevent recursive calls
this.isFetchingData = true; this.isFetchingData = true;
this.dataLoaded = false; // Mark data as not loaded yet
this.noDataAvailable = false; // Reset no data flag
console.log('Starting fetchChartData, current state:', {
table: this.table,
xAxis: this.xAxis,
yAxis: this.yAxis,
connection: this.connection
});
// If we're in drilldown mode, fetch the appropriate drilldown data // If we're in drilldown mode, fetch the appropriate drilldown data
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) { if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
console.log('Fetching drilldown data');
this.fetchDrilldownData(); this.fetchDrilldownData();
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
@@ -583,32 +811,82 @@ export class BubbleChartComponent implements OnInit, OnChanges {
this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe( this.dashboardService.getChartData(this.table, 'bubble', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
(data: any) => { (data: any) => {
console.log('Received bubble chart data:', data); console.log('Received bubble chart data:', data);
if (data === null) {
console.warn('Bubble chart API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true;
this.bubbleChartData = [];
// Reset flag after fetching
this.isFetchingData = false;
return;
}
// Handle the actual data structure returned by the API // Reset chart data to empty first
if (data && data.chartLabels && data.chartData) { this.bubbleChartData = [];
if (data === null || data === undefined) {
console.warn('Bubble chart API returned null/undefined data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true;
} else if (data && data.chartLabels && data.chartData) {
// For bubble charts, we need to transform the data into bubble format // For bubble charts, we need to transform the data into bubble format
// Bubble charts expect data in the format: {x: number, y: number, r: number} // Bubble charts expect data in the format: {x: number, y: number, r: number}
this.noDataAvailable = data.chartLabels.length === 0; console.log('Processing chartLabels and chartData format');
this.bubbleChartData = this.transformToBubbleData(data.chartLabels, data.chartData); const transformedData = this.transformToBubbleData(data.chartLabels, data.chartData);
console.log('Transformed data:', transformedData);
// Check if we have valid data
let hasValidData = false;
if (transformedData && transformedData.length > 0) {
for (const dataset of transformedData) {
if (dataset.data && dataset.data.length > 0) {
hasValidData = true;
break;
}
}
}
if (hasValidData) {
// Create a new array reference to trigger change detection
this.bubbleChartData = [...transformedData];
this.noDataAvailable = false;
console.log('Updated bubble chart with data:', this.bubbleChartData); console.log('Updated bubble chart with data:', this.bubbleChartData);
} else {
console.log('No valid data after transformation');
this.noDataAvailable = true;
}
} else if (data && data.labels && data.datasets) { } else if (data && data.labels && data.datasets) {
// Handle the original expected format as fallback // Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0; console.log('Processing labels and datasets format');
this.bubbleChartData = data.datasets; // Check if we have valid data
let hasValidData = false;
if (data.datasets && data.datasets.length > 0) {
for (const dataset of data.datasets) {
if (dataset.data && dataset.data.length > 0) {
hasValidData = true;
break;
}
}
}
if (hasValidData) {
// Create a new array reference to trigger change detection
this.bubbleChartData = [...data.datasets];
this.noDataAvailable = false;
console.log('Updated bubble chart with legacy data format:', this.bubbleChartData); console.log('Updated bubble chart with legacy data format:', this.bubbleChartData);
} else {
console.log('No valid data in legacy format');
this.noDataAvailable = true;
}
} else { } else {
console.warn('Bubble chart received data does not have expected structure', data); console.warn('Bubble chart received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = [];
} }
this.dataLoaded = true; // Mark data as loaded
console.log('Final state after data fetch:', {
noDataAvailable: this.noDataAvailable,
dataLoaded: this.dataLoaded,
bubbleChartDataLength: this.bubbleChartData.length,
isChartDataValid: this.isChartDataValid()
});
// Trigger change detection with a small delay to ensure proper rendering
setTimeout(() => {
this.forceChartUpdate();
}, 100);
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
}, },
@@ -616,15 +894,24 @@ export class BubbleChartComponent implements OnInit, OnChanges {
console.error('Error fetching bubble chart data:', error); console.error('Error fetching bubble chart data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
this.dataLoaded = true;
// Trigger change detection
setTimeout(() => {
this.forceChartUpdate();
}, 100);
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
// Keep default data in case of error
} }
); );
} else { } else {
console.log('Missing required data for bubble chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); console.log('Missing required data for bubble chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
this.dataLoaded = true;
// Trigger change detection
setTimeout(() => {
this.forceChartUpdate();
}, 100);
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
} }
@@ -654,6 +941,10 @@ export class BubbleChartComponent implements OnInit, OnChanges {
console.warn('Invalid drilldown layer index:', layerIndex); console.warn('Invalid drilldown layer index:', layerIndex);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
this.dataLoaded = true;
setTimeout(() => {
this.forceChartUpdate();
}, 100);
return; return;
} }
} }
@@ -665,6 +956,10 @@ export class BubbleChartComponent implements OnInit, OnChanges {
console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel); console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
this.dataLoaded = true;
setTimeout(() => {
this.forceChartUpdate();
}, 100);
return; return;
} }
@@ -758,35 +1053,84 @@ export class BubbleChartComponent implements OnInit, OnChanges {
this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe( this.dashboardService.getChartData(actualApiUrl, 'bubble', drilldownConfig.xAxis, drilldownConfig.yAxis, this.connection, parameterField, parameterValue, filterParams).subscribe(
(data: any) => { (data: any) => {
console.log('Received drilldown data:', data); console.log('Received drilldown data:', data);
if (data === null) {
console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.'); // Reset chart data to empty first
this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
return;
if (data === null || data === undefined) {
console.warn('Drilldown API returned null/undefined data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true;
} else if (data && data.chartLabels && data.chartData) {
// For bubble charts, we need to transform the data into bubble format
const transformedData = this.transformToBubbleData(data.chartLabels, data.chartData);
// Check if we have valid data
let hasValidData = false;
if (transformedData && transformedData.length > 0) {
for (const dataset of transformedData) {
if (dataset.data && dataset.data.length > 0) {
hasValidData = true;
break;
}
}
} }
// Handle the actual data structure returned by the API if (hasValidData) {
if (data && data.chartLabels && data.chartData) { this.bubbleChartData = transformedData;
// For bubble charts, we need to transform the data into bubble format this.noDataAvailable = false;
this.noDataAvailable = data.chartLabels.length === 0;
this.bubbleChartData = this.transformToBubbleData(data.chartLabels, data.chartData);
console.log('Updated bubble chart with drilldown data:', this.bubbleChartData); console.log('Updated bubble chart with drilldown data:', this.bubbleChartData);
} else {
console.log('No valid data after transformation in drilldown');
this.noDataAvailable = true;
}
} else if (data && data.labels && data.datasets) { } else if (data && data.labels && data.datasets) {
// Handle the original expected format as fallback // Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0; // Check if we have valid data
let hasValidData = false;
if (data.datasets && data.datasets.length > 0) {
for (const dataset of data.datasets) {
if (dataset.data && dataset.data.length > 0) {
hasValidData = true;
break;
}
}
}
if (hasValidData) {
this.bubbleChartData = data.datasets; this.bubbleChartData = data.datasets;
this.noDataAvailable = false;
console.log('Updated bubble chart with drilldown legacy data format:', this.bubbleChartData); console.log('Updated bubble chart with drilldown legacy data format:', this.bubbleChartData);
} else {
console.log('No valid data in legacy format in drilldown');
this.noDataAvailable = true;
}
} else { } else {
console.warn('Drilldown received data does not have expected structure', data); console.warn('Drilldown received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = [];
} }
this.dataLoaded = true; // Mark data as loaded
console.log('Final state after drilldown data fetch:', {
noDataAvailable: this.noDataAvailable,
dataLoaded: this.dataLoaded,
bubbleChartDataLength: this.bubbleChartData.length,
isChartDataValid: this.isChartDataValid()
});
// Trigger change detection
setTimeout(() => {
this.forceChartUpdate();
}, 100);
}, },
(error) => { (error) => {
console.error('Error fetching drilldown data:', error); console.error('Error fetching drilldown data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.bubbleChartData = []; this.bubbleChartData = [];
// Keep current data in case of error this.dataLoaded = true;
setTimeout(() => {
this.forceChartUpdate();
}, 100);
} }
); );
} }
@@ -933,4 +1277,52 @@ export class BubbleChartComponent implements OnInit, OnChanges {
public chartHovered(e: any): void { public chartHovered(e: any): void {
console.log('Bubble chart hovered:', e); console.log('Bubble chart hovered:', e);
} }
// Method to check if chart data is valid
public isChartDataValid(): boolean {
console.log('Checking if chart data is valid:', this.bubbleChartData);
if (!this.bubbleChartData || this.bubbleChartData.length === 0) {
console.log('Chart data is null or empty');
return false;
}
// Check if any dataset has data
for (const dataset of this.bubbleChartData) {
console.log('Checking dataset:', dataset);
if (dataset.data && dataset.data.length > 0) {
console.log('Dataset has data, length:', dataset.data.length);
// For bubble charts, check if data points have x, y, r properties
for (const point of dataset.data) {
console.log('Checking point:', point);
if (typeof point === 'object' && point.hasOwnProperty('x') && point.hasOwnProperty('y') && point.hasOwnProperty('r')) {
// Valid bubble point
console.log('Found valid bubble point');
return true;
}
}
}
}
console.log('No valid chart data found');
return false;
}
// Method to force chart update
private forceChartUpdate(): void {
console.log('Forcing chart update');
console.log('Current bubbleChartData:', this.bubbleChartData);
console.log('Current bubbleChartData length:', this.bubbleChartData ? this.bubbleChartData.length : 0);
if (this.bubbleChartData && this.bubbleChartData.length > 0) {
console.log('First dataset data length:', this.bubbleChartData[0].data ? this.bubbleChartData[0].data.length : 0);
}
// Create a new reference to trigger change detection
if (this.bubbleChartData) {
this.bubbleChartData = [...this.bubbleChartData];
}
// Also update noDataAvailable to trigger UI changes
this.noDataAvailable = this.noDataAvailable;
console.log('Chart update forced, noDataAvailable:', this.noDataAvailable);
console.log('Chart update forced, bubbleChartData length:', this.bubbleChartData ? this.bubbleChartData.length : 0);
console.log('Chart update forced, isChartDataValid:', this.isChartDataValid());
}
} }

View File

@@ -284,13 +284,12 @@
<div class="chart-wrapper"> <div class="chart-wrapper">
<div class="chart-content" [class.loading]="isLoading"> <div class="chart-content" [class.loading]="isLoading">
<!-- Show no data message --> <!-- Show no data message -->
<div class="no-data-message" *ngIf="noDataAvailable"> <div class="no-data-message" *ngIf="noDataAvailable && doughnutChartLabels.length === 0">
<p>No chart data available</p> <p>No chart data available</p>
</div> </div>
<!-- Show chart when data is available --> <!-- Show chart when data is available -->
<canvas baseChart <canvas baseChart
*ngIf="!noDataAvailable && doughnutChartLabels.length > 0 && doughnutChartData.length > 0"
[datasets]="doughnutChartData" [datasets]="doughnutChartData"
[labels]="doughnutChartLabels" [labels]="doughnutChartLabels"
[type]="doughnutChartType" [type]="doughnutChartType"
@@ -306,7 +305,7 @@
</div> </div>
</div> </div>
<div class="chart-legend" *ngIf="!noDataAvailable && showlabel && doughnutChartLabels && doughnutChartLabels.length > 0"> <div class="chart-legend" *ngIf="showlabel && doughnutChartLabels && doughnutChartLabels.length > 0">
<div class="legend-item" *ngFor="let label of doughnutChartLabels; let i = index"> <div class="legend-item" *ngFor="let label of doughnutChartLabels; let i = index">
<span class="legend-color" [style.background-color]="getLegendColor(i)"></span> <span class="legend-color" [style.background-color]="getLegendColor(i)"></span>
<span class="legend-label">{{ label }}</span> <span class="legend-label">{{ label }}</span>

View File

@@ -148,8 +148,11 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// Validate initial data // Validate initial data
this.validateChartData(); this.validateChartData();
// Only fetch data if we have the required inputs, otherwise show default data
if (this.table && this.xAxis && this.yAxis) {
this.fetchChartData(); this.fetchChartData();
} }
}
/** /**
* Validate and sanitize chart data * Validate and sanitize chart data
@@ -237,6 +240,12 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
console.log('Chart configuration changed, fetching new data'); console.log('Chart configuration changed, fetching new data');
this.fetchChartData(); this.fetchChartData();
} }
// If we have the required inputs and haven't fetched data yet, fetch it
if ((xAxisChanged || yAxisChanged || tableChanged) && this.table && this.xAxis && this.yAxis && !this.isFetchingData) {
console.log('Required inputs available, fetching data');
this.fetchChartData();
}
} }
ngAfterViewChecked() { ngAfterViewChecked() {
@@ -674,11 +683,31 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.doughnutChartLabels = data.chartLabels; this.doughnutChartLabels = data.chartLabels;
// Handle different data structures
let chartDataValues;
if (Array.isArray(data.chartData)) {
// If chartData is already an array of values
if (data.chartData.length > 0 && typeof data.chartData[0] !== 'object') {
chartDataValues = data.chartData;
}
// If chartData is an array with one object containing the data
else if (data.chartData.length > 0 && data.chartData[0].data) {
chartDataValues = data.chartData[0].data;
}
// Default case
else {
chartDataValues = data.chartData;
}
} else {
chartDataValues = [data.chartData];
}
this.doughnutChartData = [ this.doughnutChartData = [
{ {
data: data.chartData, data: chartDataValues,
backgroundColor: this.chartColors.slice(0, data.chartData.length), backgroundColor: this.chartColors.slice(0, chartDataValues.length),
hoverBackgroundColor: this.chartColors.slice(0, data.chartData.length) hoverBackgroundColor: this.chartColors.slice(0, chartDataValues.length)
} }
]; ];
console.log('Updated doughnut chart with data:', { labels: this.doughnutChartLabels, data: this.doughnutChartData }); console.log('Updated doughnut chart with data:', { labels: this.doughnutChartLabels, data: this.doughnutChartData });
@@ -691,12 +720,21 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
} else { } else {
console.warn('Received data does not have expected structure', data); console.warn('Received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.doughnutChartLabels = []; // Keep default data instead of empty arrays
this.doughnutChartLabels = ["Category A", "Category B", "Category C"];
this.doughnutChartData = [ this.doughnutChartData = [
{ {
data: [], data: [30, 50, 20],
backgroundColor: [], backgroundColor: [
hoverBackgroundColor: [] '#FF6384',
'#36A2EB',
'#FFCE56'
],
hoverBackgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
]
} }
]; ];
} }
@@ -707,12 +745,26 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
(error) => { (error) => {
console.error('Error fetching doughnut chart data:', error); console.error('Error fetching doughnut chart data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.doughnutChartLabels = []; // Keep default data in case of error
this.doughnutChartData = []; this.doughnutChartLabels = ["Category A", "Category B", "Category C"];
this.doughnutChartData = [
{
data: [30, 50, 20],
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
],
hoverBackgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56'
]
}
];
// Reset flags after fetching // Reset flags after fetching
this.isFetchingData = false; this.isFetchingData = false;
this.isLoading = false; this.isLoading = false;
// Keep default data in case of error
} }
); );
} else { } else {
@@ -869,11 +921,31 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.doughnutChartLabels = data.chartLabels; this.doughnutChartLabels = data.chartLabels;
// Handle different data structures
let chartDataValues;
if (Array.isArray(data.chartData)) {
// If chartData is already an array of values
if (data.chartData.length > 0 && typeof data.chartData[0] !== 'object') {
chartDataValues = data.chartData;
}
// If chartData is an array with one object containing the data
else if (data.chartData.length > 0 && data.chartData[0].data) {
chartDataValues = data.chartData[0].data;
}
// Default case
else {
chartDataValues = data.chartData;
}
} else {
chartDataValues = [data.chartData];
}
this.doughnutChartData = [ this.doughnutChartData = [
{ {
data: data.chartData, data: chartDataValues,
backgroundColor: this.chartColors.slice(0, data.chartData.length), backgroundColor: this.chartColors.slice(0, chartDataValues.length),
hoverBackgroundColor: this.chartColors.slice(0, data.chartData.length) hoverBackgroundColor: this.chartColors.slice(0, chartDataValues.length)
} }
]; ];
console.log('Updated doughnut chart with drilldown data:', { labels: this.doughnutChartLabels, data: this.doughnutChartData }); console.log('Updated doughnut chart with drilldown data:', { labels: this.doughnutChartLabels, data: this.doughnutChartData });
@@ -890,14 +962,7 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
} else { } else {
console.warn('Drilldown received data does not have expected structure', data); console.warn('Drilldown received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.doughnutChartLabels = []; // Keep current data instead of empty arrays
this.doughnutChartData = [
{
data: [],
backgroundColor: [],
hoverBackgroundColor: []
}
];
// Set loading state to false // Set loading state to false
this.isLoading = false; this.isLoading = false;
} }
@@ -905,11 +970,9 @@ export class DoughnutChartComponent implements OnInit, OnChanges, AfterViewCheck
(error) => { (error) => {
console.error('Error fetching drilldown data:', error); console.error('Error fetching drilldown data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.doughnutChartLabels = []; // Keep current data in case of error
this.doughnutChartData = [];
// Set loading state to false // Set loading state to false
this.isLoading = false; this.isLoading = false;
// Keep current data in case of error
} }
); );

View File

@@ -281,7 +281,7 @@
<div class="chart-wrapper"> <div class="chart-wrapper">
<!-- Show loading indicator --> <!-- Show loading indicator -->
<div class="loading-indicator" *ngIf="pieChartLabels.length === 0 && pieChartData.length === 0 && !noDataAvailable"> <div class="loading-indicator" *ngIf="pieChartLabels.length === 0 && pieChartData.length === 0 && !noDataAvailable && !isFetchingData">
<div class="spinner"></div> <div class="spinner"></div>
<p>Loading chart data...</p> <p>Loading chart data...</p>
</div> </div>
@@ -291,15 +291,15 @@
<p>No chart data available</p> <p>No chart data available</p>
</div> </div>
<!-- Show chart when data is available --> <!-- Show chart when data is available or show default data -->
<canvas baseChart <canvas baseChart
*ngIf="pieChartLabels.length > 0 && pieChartData.length > 0" [datasets]="pieChartDatasets"
[data]="pieChartData"
[labels]="pieChartLabels" [labels]="pieChartLabels"
[type]="pieChartType" [type]="pieChartType"
[options]="pieChartOptions" [options]="pieChartOptions"
(chartHover)="chartHovered($event)" (chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"> (chartClick)="chartClicked($event)"
[style.display]="shouldShowChart() ? 'block' : 'none'">
</canvas> </canvas>
</div> </div>
<div class="chart-legend" *ngIf="showlabel && pieChartLabels && pieChartLabels.length > 0"> <div class="chart-legend" *ngIf="showlabel && pieChartLabels && pieChartLabels.length > 0">

View File

@@ -37,6 +37,12 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
public pieChartLabels: string[] = ['Category A', 'Category B', 'Category C']; public pieChartLabels: string[] = ['Category A', 'Category B', 'Category C'];
public pieChartData: number[] = [30, 50, 20]; public pieChartData: number[] = [30, 50, 20];
public pieChartDatasets: any[] = [
{
data: [30, 50, 20],
label: 'Dataset 1'
}
];
public pieChartType: string = 'pie'; public pieChartType: string = 'pie';
public pieChartOptions: any = { public pieChartOptions: any = {
responsive: true, responsive: true,
@@ -96,7 +102,7 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
noDataAvailable: boolean = false; noDataAvailable: boolean = false;
// Flag to prevent infinite loops // Flag to prevent infinite loops
private isFetchingData: boolean = false; isFetchingData: boolean = false;
// Subscriptions to unsubscribe on destroy // Subscriptions to unsubscribe on destroy
private subscriptions: Subscription[] = []; private subscriptions: Subscription[] = [];
@@ -132,8 +138,18 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
console.log('PieChartComponent initialized with default data:', { labels: this.pieChartLabels, data: this.pieChartData }); console.log('PieChartComponent initialized with default data:', { labels: this.pieChartLabels, data: this.pieChartData });
// Validate initial data // Validate initial data
this.validateChartData(); this.validateChartData();
// Initialize datasets with default data
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
// Only fetch data if we have the required inputs, otherwise show default data
if (this.table && this.xAxis && this.yAxis) {
this.fetchChartData(); this.fetchChartData();
} }
}
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
console.log('PieChartComponent input changes:', changes); console.log('PieChartComponent input changes:', changes);
@@ -165,6 +181,12 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
console.log('Chart configuration changed, fetching new data'); console.log('Chart configuration changed, fetching new data');
this.fetchChartData(); this.fetchChartData();
} }
// If we have the required inputs and haven't fetched data yet, fetch it
if ((xAxisChanged || yAxisChanged || tableChanged) && this.table && this.xAxis && this.yAxis && !this.isFetchingData) {
console.log('Required inputs available, fetching data');
this.fetchChartData();
}
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@@ -576,8 +598,6 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
if (data === null) { if (data === null) {
console.warn('API returned null data. Check if the API endpoint is working correctly.'); console.warn('API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
return; return;
@@ -588,9 +608,24 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.pieChartLabels = data.chartLabels; this.pieChartLabels = data.chartLabels;
this.pieChartData = data.chartData;
// Extract the actual data values from the chartData array
// chartData is an array with one object containing the data
if (data.chartData.length > 0 && data.chartData[0].data) {
this.pieChartData = data.chartData[0].data;
} else {
this.pieChartData = [];
}
// Trigger change detection // Trigger change detection
this.pieChartLabels = [...this.pieChartLabels];
this.pieChartData = [...this.pieChartData]; this.pieChartData = [...this.pieChartData];
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
console.log('Updated pie chart with data:', { labels: this.pieChartLabels, data: this.pieChartData }); console.log('Updated pie chart with data:', { labels: this.pieChartLabels, data: this.pieChartData });
} else if (data && data.labels && data.datasets) { } else if (data && data.labels && data.datasets) {
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
@@ -598,13 +633,29 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
this.pieChartLabels = data.labels; this.pieChartLabels = data.labels;
this.pieChartData = data.datasets[0]?.data || []; this.pieChartData = data.datasets[0]?.data || [];
// Trigger change detection // Trigger change detection
this.pieChartLabels = [...this.pieChartLabels];
this.pieChartData = [...this.pieChartData]; this.pieChartData = [...this.pieChartData];
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
console.log('Updated pie chart with legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData }); console.log('Updated pie chart with legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData });
} else { } else {
console.warn('Received data does not have expected structure', data); console.warn('Received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = []; // Keep default data if no data is available
this.pieChartData = []; if (this.pieChartLabels.length === 0 && this.pieChartData.length === 0) {
this.pieChartLabels = ['Category A', 'Category B', 'Category C'];
this.pieChartData = [30, 50, 20];
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
}
} }
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
@@ -612,18 +663,13 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
(error) => { (error) => {
console.error('Error fetching pie chart data:', error); console.error('Error fetching pie chart data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
// Keep default data in case of error
} }
); );
} else { } else {
console.log('Missing required data for chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); console.log('Missing required data for chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
} }
@@ -652,8 +698,6 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
} else { } else {
console.warn('Invalid drilldown layer index:', layerIndex); console.warn('Invalid drilldown layer index:', layerIndex);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
return; return;
} }
} }
@@ -664,8 +708,6 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
if (!drilldownConfig || !drilldownConfig.apiUrl || !drilldownConfig.xAxis || !drilldownConfig.yAxis) { if (!drilldownConfig || !drilldownConfig.apiUrl || !drilldownConfig.xAxis || !drilldownConfig.yAxis) {
console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel); console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
return; return;
} }
@@ -762,8 +804,6 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
if (data === null) { if (data === null) {
console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.'); console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
return; return;
} }
@@ -772,9 +812,24 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.pieChartLabels = data.chartLabels; this.pieChartLabels = data.chartLabels;
this.pieChartData = data.chartData;
// Extract the actual data values from the chartData array
// chartData is an array with one object containing the data
if (data.chartData.length > 0 && data.chartData[0].data) {
this.pieChartData = data.chartData[0].data;
} else {
this.pieChartData = [];
}
// Trigger change detection // Trigger change detection
this.pieChartLabels = [...this.pieChartLabels];
this.pieChartData = [...this.pieChartData]; this.pieChartData = [...this.pieChartData];
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
console.log('Updated pie chart with drilldown data:', { labels: this.pieChartLabels, data: this.pieChartData }); console.log('Updated pie chart with drilldown data:', { labels: this.pieChartLabels, data: this.pieChartData });
} else if (data && data.labels && data.datasets) { } else if (data && data.labels && data.datasets) {
// Backend has already filtered the data, just display it // Backend has already filtered the data, just display it
@@ -782,21 +837,24 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
this.pieChartLabels = data.labels; this.pieChartLabels = data.labels;
this.pieChartData = data.datasets[0]?.data || []; this.pieChartData = data.datasets[0]?.data || [];
// Trigger change detection // Trigger change detection
this.pieChartLabels = [...this.pieChartLabels];
this.pieChartData = [...this.pieChartData]; this.pieChartData = [...this.pieChartData];
this.pieChartDatasets = [
{
data: this.pieChartData,
label: 'Dataset 1'
}
];
console.log('Updated pie chart with drilldown legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData }); console.log('Updated pie chart with drilldown legacy data format:', { labels: this.pieChartLabels, data: this.pieChartData });
} else { } else {
console.warn('Drilldown received data does not have expected structure', data); console.warn('Drilldown received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = []; // Keep current data if no data is available
this.pieChartData = [];
} }
}, },
(error) => { (error) => {
console.error('Error fetching drilldown data:', error); console.error('Error fetching drilldown data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.pieChartLabels = [];
this.pieChartData = [];
// Keep current data in case of error
} }
); );
} }
@@ -885,6 +943,26 @@ export class PieChartComponent implements OnInit, OnChanges, AfterViewChecked, O
return this.chartColors[index % this.chartColors.length]; return this.chartColors[index % this.chartColors.length];
} }
// Method to determine if chart should be displayed
shouldShowChart(): boolean {
// Show chart if we have data
if (this.pieChartLabels.length > 0 && this.pieChartData.length > 0) {
return true;
}
// Show chart if we're still fetching data
if (this.isFetchingData) {
return true;
}
// Show chart if we have default data
if (this.pieChartLabels.length > 0 && this.originalPieChartLabels.length > 0) {
return true;
}
return false;
}
// events // events
public chartClicked(e: any): void { public chartClicked(e: any): void {
console.log('Pie chart clicked:', e); console.log('Pie chart clicked:', e);

View File

@@ -279,10 +279,11 @@
</div> </div>
</div> </div>
<div style="position: relative; height: calc(100% - 50px);"> <div style="position: relative; height: calc(100% - 80px); padding: 0 10px 30px 10px;">
<canvas baseChart <canvas baseChart
[datasets]="polarAreaChartData" [datasets]="polarAreaChartData"
[labels]="polarAreaChartLabels" [labels]="polarAreaChartLabels"
[options]="polarAreaChartOptions"
[type]="polarAreaChartType" [type]="polarAreaChartType"
(chartHover)="chartHovered($event)" (chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"> (chartClick)="chartClicked($event)">

View File

@@ -90,6 +90,32 @@ export class PolarChartComponent implements OnInit, OnChanges {
{ data: [ 300, 500, 100, 40, 120 ], label: 'Series 1'} { data: [ 300, 500, 100, 40, 120 ], label: 'Series 1'}
]; ];
public polarAreaChartOptions: any = {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
left: 10,
right: 10,
top: 10,
bottom: 30
}
},
plugins: {
legend: {
display: true,
position: 'top'
}
},
scales: {
r: {
ticks: {
backdropColor: 'rgba(0, 0, 0, 0)'
}
}
}
};
public polarAreaChartType: string = 'polarArea'; public polarAreaChartType: string = 'polarArea';
// Multi-layer drilldown state tracking // Multi-layer drilldown state tracking
@@ -511,7 +537,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.warn('Polar chart API returned null data. Check if the API endpoint is working correctly.'); console.warn('Polar chart API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
return; return;
@@ -524,32 +555,54 @@ export class PolarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.polarAreaChartLabels = data.chartLabels; this.polarAreaChartLabels = data.chartLabels;
if (data.chartData && data.chartData.length > 0) { if (data.chartData && data.chartData.length > 0) {
this.polarAreaChartData = data.chartData[0].data.map(value => { // Convert the data to the expected format for polar area charts
const chartValues = data.chartData[0].data.map(value => {
// Convert to number if it's not already // Convert to number if it's not already
return isNaN(Number(value)) ? 0 : Number(value); return isNaN(Number(value)) ? 0 : Number(value);
}); });
} else { // Assign data in the correct format (array of objects with data property)
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: chartValues,
label: data.chartData[0].label || 'Dataset 1'
}
];
} else {
this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
} }
// Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with data:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData }); console.log('Updated polar chart with data:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
} else if (data && data.labels && data.data) { } else if (data && data.labels && data.data) {
// Handle the original expected format as fallback // Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0; this.noDataAvailable = data.labels.length === 0;
this.polarAreaChartLabels = data.labels; this.polarAreaChartLabels = data.labels;
this.polarAreaChartData = data.data.map(value => { // Convert the data to the expected format for polar area charts
const chartValues = data.data.map(value => {
// Convert to number if it's not already // Convert to number if it's not already
return isNaN(Number(value)) ? 0 : Number(value); return isNaN(Number(value)) ? 0 : Number(value);
}); });
// Trigger change detection // Assign data in the correct format (array of objects with data property)
this.polarAreaChartData = [...this.polarAreaChartData]; this.polarAreaChartData = [
{
data: chartValues,
label: 'Dataset 1'
}
];
console.log('Updated polar chart with legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData }); console.log('Updated polar chart with legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
} else { } else {
console.warn('Polar chart received data does not have expected structure', data); console.warn('Polar chart received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
} }
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
@@ -558,7 +611,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.error('Error fetching polar chart data:', error); console.error('Error fetching polar chart data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
// Keep default data in case of error // Keep default data in case of error
@@ -568,7 +626,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.log('Missing required data for polar chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection }); console.log('Missing required data for polar chart:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
// Reset flag after fetching // Reset flag after fetching
this.isFetchingData = false; this.isFetchingData = false;
} }
@@ -598,7 +661,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.warn('Invalid drilldown layer index:', layerIndex); console.warn('Invalid drilldown layer index:', layerIndex);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
return; return;
} }
} }
@@ -610,7 +678,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel); console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
return; return;
} }
@@ -708,7 +781,12 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.'); console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.');
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
return; return;
} }
@@ -718,12 +796,25 @@ export class PolarChartComponent implements OnInit, OnChanges {
this.noDataAvailable = data.chartLabels.length === 0; this.noDataAvailable = data.chartLabels.length === 0;
this.polarAreaChartLabels = data.chartLabels; this.polarAreaChartLabels = data.chartLabels;
if (data.chartData && data.chartData.length > 0) { if (data.chartData && data.chartData.length > 0) {
this.polarAreaChartData = data.chartData[0].data.map(value => { // Convert the data to the expected format for polar area charts
const chartValues = data.chartData[0].data.map(value => {
// Convert to number if it's not already // Convert to number if it's not already
return isNaN(Number(value)) ? 0 : Number(value); return isNaN(Number(value)) ? 0 : Number(value);
}); });
// Assign data in the correct format (array of objects with data property)
this.polarAreaChartData = [
{
data: chartValues,
label: data.chartData[0].label || 'Dataset 1'
}
];
} else { } else {
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
} }
// Trigger change detection // Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData]; this.polarAreaChartData = [...this.polarAreaChartData];
@@ -732,10 +823,18 @@ export class PolarChartComponent implements OnInit, OnChanges {
// Handle the original expected format as fallback // Handle the original expected format as fallback
this.noDataAvailable = data.labels.length === 0; this.noDataAvailable = data.labels.length === 0;
this.polarAreaChartLabels = data.labels; this.polarAreaChartLabels = data.labels;
this.polarAreaChartData = data.data.map(value => { // Convert the data to the expected format for polar area charts
const chartValues = data.data.map(value => {
// Convert to number if it's not already // Convert to number if it's not already
return isNaN(Number(value)) ? 0 : Number(value); return isNaN(Number(value)) ? 0 : Number(value);
}); });
// Assign data in the correct format (array of objects with data property)
this.polarAreaChartData = [
{
data: chartValues,
label: 'Dataset 1'
}
];
// Trigger change detection // Trigger change detection
this.polarAreaChartData = [...this.polarAreaChartData]; this.polarAreaChartData = [...this.polarAreaChartData];
console.log('Updated polar chart with drilldown legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData }); console.log('Updated polar chart with drilldown legacy data format:', { labels: this.polarAreaChartLabels, data: this.polarAreaChartData });
@@ -743,14 +842,24 @@ export class PolarChartComponent implements OnInit, OnChanges {
console.warn('Drilldown received data does not have expected structure', data); console.warn('Drilldown received data does not have expected structure', data);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
} }
}, },
(error) => { (error) => {
console.error('Error fetching drilldown data:', error); console.error('Error fetching drilldown data:', error);
this.noDataAvailable = true; this.noDataAvailable = true;
this.polarAreaChartLabels = []; this.polarAreaChartLabels = [];
this.polarAreaChartData = []; this.polarAreaChartData = [
{
data: [],
label: 'Dataset 1'
}
];
// Keep current data in case of error // Keep current data in case of error
} }
); );

View File

@@ -0,0 +1 @@
export * from './unified-chart.component';

View File

@@ -0,0 +1,396 @@
<div class="chart-container" *ngIf="!noDataAvailable && !isLoading">
<!-- Back button for drilldown navigation -->
<div class="drilldown-back" *ngIf="currentDrilldownLevel > 0">
<button class="btn btn-sm btn-secondary" (click)="navigateBack()">
<clr-icon shape="arrow" dir="left"></clr-icon>
Back
</button>
<span class="drilldown-level">Level: {{ currentDrilldownLevel }}</span>
</div>
<!-- Chart title -->
<div class="chart-title" *ngIf="charttitle">
<h4>{{ charttitle }}</h4>
</div>
<!-- Filter toggle icon -->
<div class="filter-toggle-icon" *ngIf="baseFilters && baseFilters.length > 0"
(click)="toggleFilters()"
style="cursor: pointer; text-align: right; padding: 5px;">
<clr-icon shape="filter" size="24"
[style.color]="showFilters ? '#007cba' : '#666'"
title="Toggle Filters">
</clr-icon>
<span style="margin-left: 5px; font-size: 12px; color: #666;">
{{ showFilters ? 'Hide Filters' : 'Show Filters' }}
</span>
</div>
<!-- Render different chart types based on chartType input -->
<div class="chart-wrapper">
<!-- Bar Chart -->
<div *ngIf="chartType === 'bar'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'bar'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Line Chart -->
<div *ngIf="chartType === 'line'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'line'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Pie Chart -->
<div *ngIf="chartType === 'pie'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'pie'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Doughnut Chart -->
<div *ngIf="chartType === 'doughnut'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'doughnut'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Bubble Chart -->
<div *ngIf="chartType === 'bubble'" class="chart-canvas-container">
<canvas baseChart
[datasets]="bubbleChartData"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'bubble'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Radar Chart -->
<div *ngIf="chartType === 'radar'" class="chart-canvas-container">
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'radar'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Polar Area Chart -->
<div *ngIf="chartType === 'polar'" class="chart-canvas-container">
<div style="position: absolute; top: 0; left: 0; background: magenta; color: white; padding: 5px; z-index: 1000; font-size: 12px;">
POLAR CHART RENDERED (chartType: {{chartType}})
</div>
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'polarArea'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Scatter Chart -->
<div *ngIf="chartType === 'scatter'" class="chart-canvas-container">
<div style="position: absolute; top: 0; left: 0; background: brown; color: white; padding: 5px; z-index: 1000; font-size: 12px;">
SCATTER CHART RENDERED (chartType: {{chartType}})
</div>
<canvas baseChart
[datasets]="chartData"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'scatter'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
<!-- Default/Unknown Chart Type -->
<div *ngIf="!['bar', 'line', 'pie', 'doughnut', 'bubble', 'radar', 'polar', 'scatter'].includes(chartType)" class="chart-canvas-container">
<div style="position: absolute; top: 0; left: 0; background: gray; color: white; padding: 5px; z-index: 1000; font-size: 12px;">
DEFAULT CHART RENDERED (chartType: {{chartType}})
</div>
<canvas baseChart
[datasets]="chartData"
[labels]="chartLabels"
[options]="chartOptions"
[legend]="chartLegend"
[type]="'bar'"
(chartClick)="chartClicked($event)"
(chartHover)="chartHovered($event)">
</canvas>
</div>
</div>
<!-- Collapsible Base Filters -->
<div class="filters-section" *ngIf="baseFilters && baseFilters.length > 0 && showFilters">
<h5>Filters</h5>
<div class="filters-container">
<div class="filter-item" *ngFor="let filter of baseFilters; let i = index">
<!-- Text Filter -->
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)"
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
</div>
<!-- Dropdown Filter -->
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<select [(ngModel)]="filter.value" (ngModelChange)="onBaseFilterChange(filter)" class="form-control">
<option value="">Select {{ filter.field || 'value' }}</option>
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
{{ option }}
</option>
</select>
</div>
<!-- Multiselect Filter -->
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="multiselect-container">
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'base')">
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
<span *ngIf="filter.value && !Array.isArray(filter.value)">
{{ filter.value }}
</span>
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
{{ filter.value.length }} selected
</span>
</div>
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'base')">
<div class="multiselect-option" *ngFor="let option of getFilterOptions(filter)">
<input type="checkbox"
[checked]="isOptionSelected(filter, option)"
(change)="onMultiSelectChange(filter, option, $event)"
id="base-{{ filter.field }}-{{ option }}">
<label [for]="'base-' + filter.field + '-' + option">{{ option }}</label>
</div>
</div>
</div>
</div>
<!-- Date Range Filter -->
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="date-range-inputs">
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
class="form-control" placeholder="Start Date">
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
class="form-control" placeholder="End Date">
</div>
</div>
<!-- Toggle Filter -->
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="toggle-switch">
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
id="toggle-{{ filter.field }}">
<label [for]="'toggle-' + filter.field" class="toggle-label">
<span class="toggle-slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- Drilldown Filters -->
<div class="filters-section" *ngIf="drilldownFilters && drilldownFilters.length > 0 && currentDrilldownLevel > 0 && showFilters">
<h5>Drilldown Filters</h5>
<div class="filters-container">
<div class="filter-item" *ngFor="let filter of drilldownFilters; let i = index">
<!-- Text Filter -->
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)"
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
</div>
<!-- Dropdown Filter -->
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<select [(ngModel)]="filter.value" (ngModelChange)="onDrilldownFilterChange(filter)" class="form-control">
<option value="">Select {{ filter.field || 'value' }}</option>
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
{{ option }}
</option>
</select>
</div>
<!-- Multiselect Filter -->
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="multiselect-container">
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'drilldown')">
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
<span *ngIf="filter.value && !Array.isArray(filter.value)">
{{ filter.value }}
</span>
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
{{ filter.value.length }} selected
</span>
</div>
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'drilldown')">
<div class="multiselect-option" *ngFor="let option of getFilterOptions(filter)">
<input type="checkbox"
[checked]="isOptionSelected(filter, option)"
(change)="onMultiSelectChange(filter, option, $event)"
id="drilldown-{{ filter.field }}-{{ option }}">
<label [for]="'drilldown-' + filter.field + '-' + option">{{ option }}</label>
</div>
</div>
</div>
</div>
<!-- Date Range Filter -->
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="date-range-inputs">
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
class="form-control" placeholder="Start Date">
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
class="form-control" placeholder="End Date">
</div>
</div>
<!-- Toggle Filter -->
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="toggle-switch">
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
id="drilldown-toggle-{{ filter.field }}">
<label [for]="'drilldown-toggle-' + filter.field" class="toggle-label">
<span class="toggle-slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- Layer Filters -->
<div class="filters-section" *ngIf="hasActiveLayerFilters() && showFilters">
<h5>Layer Filters</h5>
<div class="filters-container">
<div class="filter-item" *ngFor="let filter of getActiveLayerFilters(); let i = index">
<!-- Text Filter -->
<div *ngIf="!filter.type || filter.type === 'text'" class="filter-text">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<input type="text" [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)"
class="form-control" placeholder="Enter {{ filter.field || 'value' }}">
</div>
<!-- Dropdown Filter -->
<div *ngIf="filter.type === 'dropdown'" class="filter-dropdown">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<select [(ngModel)]="filter.value" (ngModelChange)="onLayerFilterChange(filter)" class="form-control">
<option value="">Select {{ filter.field || 'value' }}</option>
<option *ngFor="let option of getFilterOptions(filter)" [value]="option">
{{ option }}
</option>
</select>
</div>
<!-- Multiselect Filter -->
<div *ngIf="filter.type === 'multiselect'" class="filter-multiselect">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="multiselect-container">
<div class="multiselect-display" (click)="toggleMultiselect(filter, 'layer')">
<span *ngIf="!filter.value || (Array.isArray(filter.value) && filter.value.length === 0)">Select {{ filter.field || 'options' }}</span>
<span *ngIf="filter.value && !Array.isArray(filter.value)">
{{ filter.value }}
</span>
<span *ngIf="filter.value && Array.isArray(filter.value) && filter.value.length > 0">
{{ filter.value.length }} selected
</span>
</div>
<div class="multiselect-dropdown" *ngIf="isMultiselectOpen(filter, 'layer')">
<div class="multiselect-option" *ngFor="let option of getFilterOptions(filter)">
<input type="checkbox"
[checked]="isOptionSelected(filter, option)"
(change)="onMultiSelectChange(filter, option, $event)"
id="layer-{{ filter.field }}-{{ option }}">
<label [for]="'layer-' + filter.field + '-' + option">{{ option }}</label>
</div>
</div>
</div>
</div>
<!-- Date Range Filter -->
<div *ngIf="filter.type === 'date-range'" class="filter-date-range">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="date-range-inputs">
<input type="date" [(ngModel)]="filter.value.start" (ngModelChange)="onDateRangeInputChange(filter, 'start', $event)"
class="form-control" placeholder="Start Date">
<input type="date" [(ngModel)]="filter.value.end" (ngModelChange)="onDateRangeInputChange(filter, 'end', $event)"
class="form-control" placeholder="End Date">
</div>
</div>
<!-- Toggle Filter -->
<div *ngIf="filter.type === 'toggle'" class="filter-toggle">
<label>{{ filter.field || 'Filter ' + (i + 1) }}</label>
<div class="toggle-switch">
<input type="checkbox" [(ngModel)]="filter.value" (ngModelChange)="onToggleChange(filter, $event.target.checked)"
id="layer-toggle-{{ filter.field }}">
<label [for]="'layer-toggle-' + filter.field" class="toggle-label">
<span class="toggle-slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
<!-- Clear Filters Button -->
<div class="clear-filters" *ngIf="hasActiveFilters() && showFilters">
<button class="btn btn-sm btn-outline" (click)="clearAllFilters()">
Clear All Filters
</button>
</div>
</div>
<!-- No Data Available Message -->
<div class="no-data-message" *ngIf="noDataAvailable && !isLoading">
<p>No data available for the selected filters.</p>
<button class="btn btn-sm btn-primary" (click)="fetchChartData()">Retry</button>
</div>
<!-- Loading Indicator -->
<div class="loading-indicator" *ngIf="isLoading">
<div class="spinner"></div>
<p>Loading chart data...</p>
</div>

View File

@@ -0,0 +1,307 @@
.chart-container {
position: relative;
height: 100%;
width: 100%;
padding: 10px;
}
.drilldown-back {
display: flex;
align-items: center;
margin-bottom: 10px;
.drilldown-level {
margin-left: 10px;
font-size: 14px;
color: #666;
}
}
.chart-title {
text-align: center;
margin-bottom: 15px;
h4 {
margin: 0;
color: #333;
}
}
.chart-wrapper {
position: relative;
height: calc(100% - 100px);
min-height: 400px;
padding: 10px;
}
.chart-canvas-container {
position: relative;
height: 100%;
width: 100%;
padding: 15px;
box-sizing: border-box;
canvas {
display: block;
max-width: 100%;
max-height: 100%;
}
}
.filter-toggle-icon {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 5px;
cursor: pointer;
clr-icon {
transition: color 0.3s ease;
&:hover {
color: #007cba !important;
}
}
span {
margin-left: 5px;
font-size: 12px;
color: #666;
transition: color 0.3s ease;
}
&:hover span {
color: #007cba;
}
}
.filters-section {
margin-top: 20px;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 4px;
background-color: #f9f9f9;
h5 {
margin-top: 0;
margin-bottom: 10px;
color: #333;
}
}
.filters-container {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.filter-item {
flex: 1 1 200px;
min-width: 150px;
label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #555;
}
.form-control {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
}
}
.filter-text,
.filter-dropdown,
.filter-date-range {
.form-control {
height: 36px;
}
}
.date-range-inputs {
display: flex;
gap: 10px;
.form-control {
flex: 1;
}
}
.filter-multiselect {
position: relative;
.multiselect-container {
position: relative;
}
.multiselect-display {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
background-color: white;
cursor: pointer;
min-height: 36px;
display: flex;
align-items: center;
}
.multiselect-dropdown {
position: absolute;
top: 100%;
left: 0;
right: 0;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 1000;
max-height: 200px;
overflow-y: auto;
}
.multiselect-option {
padding: 8px 12px;
border-bottom: 1px solid #eee;
&:last-child {
border-bottom: none;
}
&:hover {
background-color: #f5f5f5;
}
input[type="checkbox"] {
margin-right: 8px;
}
label {
margin: 0;
font-weight: normal;
cursor: pointer;
}
}
}
.filter-toggle {
display: flex;
align-items: center;
gap: 10px;
.toggle-switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.toggle-switch input {
opacity: 0;
width: 0;
height: 0;
}
.toggle-label {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 24px;
}
.toggle-slider {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .toggle-label {
background-color: #2196F3;
}
input:checked + .toggle-label .toggle-slider {
transform: translateX(26px);
}
}
.clear-filters {
margin-top: 15px;
text-align: center;
}
.no-data-message {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
text-align: center;
color: #666;
p {
margin-bottom: 15px;
font-size: 16px;
}
}
.loading-indicator {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 300px;
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
p {
margin: 0;
color: #666;
}
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@media (max-width: 768px) {
.filters-container {
flex-direction: column;
}
.filter-item {
min-width: 100%;
}
.chart-wrapper {
min-height: 250px;
}
.chart-canvas-container {
padding: 10px;
}
}

View File

@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UnifiedChartComponent } from './unified-chart.component';
describe('UnifiedChartComponent', () => {
let component: UnifiedChartComponent;
let fixture: ComponentFixture<UnifiedChartComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [UnifiedChartComponent]
});
fixture = TestBed.createComponent(UnifiedChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -12,23 +12,23 @@ import { ModulesetupService } from 'src/app/services/builder/modulesetup.service
styleUrls: ['./dashrunnerall.component.scss'] styleUrls: ['./dashrunnerall.component.scss']
}) })
export class DashrunnerallComponent implements OnInit { export class DashrunnerallComponent implements OnInit {
addModall:boolean = false; addModall: boolean = false;
selected:any[] = []; selected: any[] = [];
loading = false; loading = false;
data:any; data: any;
id:any; id: any;
moduleId:any; moduleId: any;
modalDelete = false; modalDelete = false;
rowSelected :any= {}; rowSelected: any = {};
rows: any[]; rows: any[];
projectname; projectname;
projectId; projectId;
error; error;
constructor( constructor(
private router : Router, private router: Router,
private route: ActivatedRoute,private dashboardService : Dashboard3Service, private route: ActivatedRoute, private dashboardService: Dashboard3Service,
// private wireframeservice : WireframeService, // private wireframeservice : WireframeService,
private excel: ExcelService,private mainService: ModulesetupService, private excel: ExcelService, private mainService: ModulesetupService,
private toastr: ToastrService,) { } private toastr: ToastrService,) { }
ngOnInit(): void { ngOnInit(): void {
@@ -42,41 +42,46 @@ export class DashrunnerallComponent implements OnInit {
// this.getprojectName(this.projectId); // this.getprojectName(this.projectId);
} }
getprojectName(id){ getprojectName(id) {
this.mainService.getProjectModules(id).subscribe((data) => { this.mainService.getProjectModules(id).subscribe((data) => {
console.log(data); console.log(data);
this.projectname=data.items[0]['projectName']; this.projectname = data.items[0]['projectName'];
console.log(this.projectname); console.log(this.projectname);
}); });
} }
getdashboard() getdashboard() {
{ this.dashboardService.getAllDash().subscribe((data) => {
this.dashboardService.getAllDash().subscribe((data) =>{
this.data = data; this.data = data;
this.rows = this.data; this.rows = this.data;
console.log(data); console.log(data);
this.error="No data Available"; this.error = "No data Available";
console.log(this.error); console.log(this.error);
}); });
} }
openModal() openModal() {
{
this.addModall = true; this.addModall = true;
} }
gotoadd() gotoadd() {
{ this.router.navigate(['../../dashboardbuilder'], { relativeTo: this.route });
this.router.navigate(['../../dashboardbuilder'],{relativeTo:this.route});
} }
goToEdit(id:number) // for runner line navigation
{ // goToEditData(id: number){
this.router.navigate(['../dashrunner/'+id],{relativeTo:this.route}); // this.router.navigate(['../editdata/'+id],{relativeTo:this.route});
// }
goToEdit(id: number) {
// Navigate to editnewdash component instead of dashrunnerline
// Pass a query parameter to indicate this is from dashboard runner
this.router.navigate(['../../dashboardbuilder/editdashn/' + id], {
relativeTo: this.route,
queryParams: { fromRunner: true }
});
} }
goToEditData(id: number){ goToEditData(id: number) {
this.router.navigate(['../editdata/'+id],{relativeTo:this.route}); this.router.navigate(['../editdata/' + id], { relativeTo: this.route });
} }
onExport() { onExport() {
@@ -84,23 +89,22 @@ export class DashrunnerallComponent implements OnInit {
moment().format('YYYYMMDD_HHmmss')) moment().format('YYYYMMDD_HHmmss'))
} }
gotoAction(){ gotoAction() {
this.router.navigate(["../../actions"], { relativeTo: this.route, queryParams: { m_id: this.moduleId,pname:this.projectname } }); this.router.navigate(["../../actions"], { relativeTo: this.route, queryParams: { m_id: this.moduleId, pname: this.projectname } });
} }
gotoRepo(){ gotoRepo() {
this.router.navigate(["../../modulecard"], { relativeTo: this.route, queryParams: { p_id: this.projectId } }); this.router.navigate(["../../modulecard"], { relativeTo: this.route, queryParams: { p_id: this.projectId } });
} }
onDelete(row){ onDelete(row) {
this.rowSelected = row; this.rowSelected = row;
console.log(this.rowSelected); console.log(this.rowSelected);
this.modalDelete = true; this.modalDelete = true;
} }
delete(id) delete(id) {
{
this.modalDelete = false; this.modalDelete = false;
console.log("in delete "+id); console.log("in delete " + id);
this.dashboardService.deleteField(id).subscribe((data)=>{ this.dashboardService.deleteField(id).subscribe((data) => {
console.log(data); console.log(data);
this.ngOnInit(); this.ngOnInit();
}); });

View File

@@ -254,7 +254,7 @@ export class ReportbuildqueryComponent implements OnInit {
name; name;
databaseName; databaseName;
databasename(val) { databasename(val) {
console.log(val); console.log('connection ', val);
this.databaseName = val.name; this.databaseName = val.name;
this.selecteddatabase = val.conn_string; this.selecteddatabase = val.conn_string;
console.log(this.selecteddatabase); console.log(this.selecteddatabase);

View File

@@ -23,6 +23,18 @@
<label for="workflow_name">{{'ACTIVE'| translate}}</label> <label for="workflow_name">{{'ACTIVE'| translate}}</label>
<input type="checkbox" formControlName="active" clrToggle value="billable" name="billable" /> <input type="checkbox" formControlName="active" clrToggle value="billable" name="billable" />
</div> </div>
<!-- SureConnect Dropdown -->
<div class="clr-col-md-4 clr-col-sm-12">
<label for="sureConnectId">SureConnect Connection</label>
<select formControlName="sureConnectId" class="clr-select">
<option value="">-- Select SureConnect --</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.connection_name || conn.id}}
</option>
</select>
</div>
<!-- <!--
<div class="clr-col-md-4 clr-col-sm-12"> <div class="clr-col-md-4 clr-col-sm-12">
<label for="url">Get URL</label> <label for="url">Get URL</label>

View File

@@ -4,6 +4,8 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr'; import { ToastrService } from 'ngx-toastr';
import { ReportBuilderService } from 'src/app/services/api/report-builder.service'; import { ReportBuilderService } from 'src/app/services/api/report-builder.service';
import { SureconnectService } from '../../dashboardnew/sureconnect/sureconnect.service';
@Component({ @Component({
selector: 'app-report-build2add', selector: 'app-report-build2add',
templateUrl: './report-build2add.component.html', templateUrl: './report-build2add.component.html',
@@ -11,8 +13,12 @@ import { ReportBuilderService } from 'src/app/services/api/report-builder.servic
}) })
export class ReportBuild2addComponent implements OnInit { export class ReportBuild2addComponent implements OnInit {
public entryForm: FormGroup; public entryForm: FormGroup;
// Add sureconnect data property
sureconnectData: any[] = [];
constructor(private _fb: FormBuilder, private router: Router,private toastr: ToastrService, constructor(private _fb: FormBuilder, private router: Router,private toastr: ToastrService,
private route: ActivatedRoute,private reportBuilderService: ReportBuilderService) { } private route: ActivatedRoute,private reportBuilderService: ReportBuilderService,
private sureconnectService: SureconnectService) { }
ngOnInit(): void { ngOnInit(): void {
this.entryForm = this._fb.group({ this.entryForm = this._fb.group({
@@ -20,9 +26,23 @@ export class ReportBuild2addComponent implements OnInit {
description:[null], description:[null],
active:[null], active:[null],
isSql:[false], isSql:[false],
// Add sureConnectId field to the form
sureConnectId: [null],
Rpt_builder2_lines: this._fb.array([this.initLinesFormReport()]), Rpt_builder2_lines: this._fb.array([this.initLinesFormReport()]),
}); });
// Load sureconnect data
this.loadSureconnectData();
}
// Add method to load sureconnect data
loadSureconnectData() {
this.sureconnectService.getAll().subscribe((data: any[]) => {
this.sureconnectData = data;
console.log('Sureconnect data loaded:', this.sureconnectData);
}, (error) => {
console.log('Error loading sureconnect data:', error);
});
} }
initLinesFormReport() { initLinesFormReport() {

View File

@@ -18,41 +18,58 @@
<clr-icon shape="plus"></clr-icon>{{'ADD' | translate}} <clr-icon shape="plus"></clr-icon>{{'ADD' | translate}}
</button> </button>
</div> </div>
</div> </div>
<clr-datagrid [clrDgLoading]="loading"> <clr-datagrid [clrDgLoading]="loading">
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{'LOADING' | translate}}</clr-spinner></ng-template> <clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{'LOADING' | translate}}</clr-spinner></ng-template>
<div *ngIf="error;else loadingSpinner">{{error}}</div></clr-dg-placeholder> <div *ngIf="error;else loadingSpinner">{{error}}</div>
</clr-dg-placeholder>
<clr-dg-column [clrDgField]="''"><ng-container *clrDgHideableColumn="{hidden: false}"> <clr-dg-column [clrDgField]="''"><ng-container *clrDgHideableColumn="{hidden: false}">
{{'GO_TO' | translate}} {{'GO_TO' | translate}}
</ng-container></clr-dg-column> </ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="'name'"><ng-container *clrDgHideableColumn="{hidden: false}"> <clr-dg-column [clrDgField]="'name'"><ng-container *clrDgHideableColumn="{hidden: false}">
{{'REPORT_NAME' | translate}} {{'REPORT_NAME' | translate}}
</ng-container></clr-dg-column> </ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="'description'"><ng-container *clrDgHideableColumn="{hidden: false}"> <clr-dg-column [clrDgField]="'description'"><ng-container *clrDgHideableColumn="{hidden: false}">
{{'REPORT_DESCRIPTION' | translate}} {{'REPORT_DESCRIPTION' | translate}}
</ng-container></clr-dg-column> </ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="''"><ng-container *clrDgHideableColumn="{hidden: false}">
Sureconnect
</ng-container></clr-dg-column>
<clr-dg-column [clrDgField]="'active'"><ng-container *clrDgHideableColumn="{hidden: false}"> <clr-dg-column [clrDgField]="'active'"><ng-container *clrDgHideableColumn="{hidden: false}">
{{'ACTIVE' | translate}} {{'ACTIVE' | translate}}
</ng-container></clr-dg-column> </ng-container></clr-dg-column>
<clr-dg-column><ng-container *clrDgHideableColumn="{hidden: false}"> <clr-dg-column><ng-container *clrDgHideableColumn="{hidden: false}">
<clr-icon shape="bars"></clr-icon>{{'ACTION' | translate}} <clr-icon shape="bars"></clr-icon>{{'ACTION' | translate}}
</ng-container></clr-dg-column> </ng-container></clr-dg-column>
<clr-dg-row *clrDgItems="let user of gridData?.slice()?.reverse();" [clrDgItem]="user"> <clr-dg-row *clrDgItems="let user of gridData?.slice()?.reverse();" [clrDgItem]="user">
<clr-dg-cell><span class="label label-light-blue" style="display: inline;margin-left: 10px; cursor: pointer;" (click)="goToLines(user)"> {{'SET_UP' | translate}}</span></clr-dg-cell> <clr-dg-cell><span class="label label-light-blue" style="display: inline;margin-left: 10px; cursor: pointer;"
(click)="goToLines(user)"> {{'SET_UP' | translate}}</span></clr-dg-cell>
<clr-dg-cell id="word">{{user.reportName}}</clr-dg-cell> <clr-dg-cell id="word">{{user.reportName}}</clr-dg-cell>
<clr-dg-cell id="word">{{user.description}}</clr-dg-cell> <clr-dg-cell id="word">{{user.description}}</clr-dg-cell>
<clr-dg-cell id="word">{{user.sureconnect_name}}</clr-dg-cell>
<clr-dg-cell id="word">{{user.active}}</clr-dg-cell> <clr-dg-cell id="word">{{user.active}}</clr-dg-cell>
<clr-dg-cell> <clr-dg-cell>
<a href="javascript:void(0)" style="padding-right: 10px;" role="tooltip" aria-haspopup="true" class="tooltip tooltip-sm tooltip-top-left"> <a href="javascript:void(0)" style="padding-right: 10px;" role="tooltip" aria-haspopup="true"
<span style="cursor: pointer;"><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error" style="color: red;"></clr-icon></span> class="tooltip tooltip-sm tooltip-top-left">
<span style="cursor: pointer;"><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error"
style="color: red;"></clr-icon></span>
<span class="tooltip-content"> {{'DELETE' | translate}}</span> <span class="tooltip-content"> {{'DELETE' | translate}}</span>
</a> </a>
<clr-signpost> <clr-signpost>
<span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span> <span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success"
style="color: rgb(0, 130, 236);"></clr-icon></span>
<clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen> <clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen>
<h5 style="margin-top: 0">{{'WHO_COLUMN' | translate}}</h5> <h5 style="margin-top: 0">{{'WHO_COLUMN' | translate}}</h5>
<div>{{'ACCOUNT_ID' | translate}}: <code class="clr-code">{{user.accountId}}</code></div> <div>{{'ACCOUNT_ID' | translate}}: <code class="clr-code">{{user.accountId}}</code></div>
@@ -87,16 +104,16 @@
</clr-dg-pagination> </clr-dg-pagination>
</clr-dg-footer> </clr-dg-footer>
</clr-datagrid> </clr-datagrid>
</div> </div>
<clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true"> <clr-modal [(clrModalOpen)]="modaldelete" [clrModalSize]="'lg'" [clrModalStaticBackdrop]="true">
<div class="modal-body" *ngIf="rowSelected.id"> <div class="modal-body" *ngIf="rowSelected.id">
<h1 class="delete">{{'DELETE_CONFIRMATION' | translate}}</h1> <h1 class="delete">{{'DELETE_CONFIRMATION' | translate}}</h1>
<h2 class="heading">{{rowSelected.id}}</h2> <h2 class="heading">{{rowSelected.id}}</h2>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="modaldelete = false">{{'CANCEL' | translate}}</button> <button type="button" class="btn btn-outline" (click)="modaldelete = false">{{'CANCEL' | translate}}</button>
<button type="submit" (click)="delete(rowSelected.id)" class="btn btn-primary" >{{'DELETE' | translate}}</button> <button type="submit" (click)="delete(rowSelected.id)" class="btn btn-primary">{{'DELETE' | translate}}</button>
</div> </div>
</div> </div>
</clr-modal> </clr-modal>

View File

@@ -26,20 +26,35 @@
</div> --> </div> -->
<div class="clr-col-md-4 clr-col-sm-12"> <div class="clr-col-md-4 clr-col-sm-12">
<label for="url">Get URL</label> <label for="url">Get URL</label>
<div> <input type="text" class="clr-input" formControlName="url" name="url" [(ngModel)]="nodeEditProperties.url" placeholder="Enter Url" style="width: 76%">&nbsp;<span><button class="btn btn-icon btn-primary" (click)="getkeys()"> <div> <input type="text" class="clr-input" formControlName="url" name="url"
[(ngModel)]="nodeEditProperties.url" placeholder="Enter Url" style="width: 76%">&nbsp;<span><button
class="btn btn-icon btn-primary" (click)="getkeys()">
<clr-icon shape="view-list"></clr-icon> <clr-icon shape="view-list"></clr-icon>
</button></span></div> </button></span></div>
</div> </div>
<div class="clr-col-md-4 clr-col-sm-12"> <div class="clr-col-md-4 clr-col-sm-12">
<label for="workflow_name">Include Date filter</label> <label for="workflow_name">Include Date filter</label>
<input type="checkbox" formControlName="date_param_req" name="date_param_req" [(ngModel)]="nodeEditProperties.date_param_req" clrToggle /> <input type="checkbox" formControlName="date_param_req" name="date_param_req"
[(ngModel)]="nodeEditProperties.date_param_req" clrToggle />
</div> </div>
<!-- SureConnect Dropdown -->
<div class="clr-col-md-4 clr-col-sm-12">
<label for="sureConnectId">SureConnect Connection</label>
<select formControlName="sureConnectId" class="clr-select">
<option value="">-- Select SureConnect --</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.name || conn.id}}
</option>
</select>
</div>
<div class="clr-col-md-4 clr-col-sm-12"> <div class="clr-col-md-4 clr-col-sm-12">
<label>Standard Parameters</label> <label>Standard Parameters</label>
<clr-combobox-container style="margin-top: 0; padding-top: 0;"> <clr-combobox-container style="margin-top: 0; padding-top: 0;">
<!-- <label style="padding-bottom: 5px; padding-top:0px; font-weight: lighter;" class="p1">Select Left Side Filter</label> --> <!-- <label style="padding-bottom: 5px; padding-top:0px; font-weight: lighter;" class="p1">Select Left Side Filter</label> -->
<clr-combobox formControlName="std_param_html" name="std_param_html" [(ngModel)]="nodeEditProperties.std_param_html" clrMulti="true" <clr-combobox formControlName="std_param_html" name="std_param_html"
required> [(ngModel)]="nodeEditProperties.std_param_html" clrMulti="true" required>
<ng-container *clrOptionSelected="let selected"> <ng-container *clrOptionSelected="let selected">
{{selected}} {{selected}}
</ng-container> </ng-container>
@@ -91,5 +106,4 @@
<button type="submit" form-control class="btn btn-primary" (click)="onSubmit()">UPDATE</button> <button type="submit" form-control class="btn btn-primary" (click)="onSubmit()">UPDATE</button>
</div> </div>
</form> </form>
</div> </div>

View File

@@ -3,6 +3,7 @@ import { FormBuilder, FormGroup } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr'; import { ToastrService } from 'ngx-toastr';
import { ReportBuilderService } from 'src/app/services/api/report-builder.service'; import { ReportBuilderService } from 'src/app/services/api/report-builder.service';
import { SureconnectService } from '../../dashboardnew/sureconnect/sureconnect.service';
@Component({ @Component({
@@ -13,54 +14,75 @@ import { ReportBuilderService } from 'src/app/services/api/report-builder.servic
export class ReportBuild2editComponent implements OnInit { export class ReportBuild2editComponent implements OnInit {
public entryForm: FormGroup; public entryForm: FormGroup;
updated = false; updated = false;
ReportData:any = {}; ReportData: any = {};
id: number; id: number;
nodeEditProperties = { nodeEditProperties = {
std_param_html:'', std_param_html: '',
adhoc_param_html:'', adhoc_param_html: '',
// column_str:'', // column_str:'',
// conn_name:'', // conn_name:'',
date_param_req:'', date_param_req: '',
// folderName:'', // folderName:'',
url:'', url: '',
// Add sureConnectId property
sureConnectId: null,
};
// Add sureconnect data property
sureconnectData: any[] = [];
};
constructor(private router: Router, constructor(private router: Router,
private route: ActivatedRoute,private reportBuilderService: ReportBuilderService, private route: ActivatedRoute, private reportBuilderService: ReportBuilderService,
private toastr: ToastrService, private _fb: FormBuilder) { } private toastr: ToastrService, private _fb: FormBuilder,
private sureconnectService: SureconnectService) { }
ngOnInit(): void { ngOnInit(): void {
this.id = this.route.snapshot.params["id"]; this.id = this.route.snapshot.params["id"];
console.log("update with id = ", this.id); console.log("update with id = ", this.id);
this.entryForm = this._fb.group({ this.entryForm = this._fb.group({
std_param_html : [null], std_param_html: [null],
adhoc_param_html:[null], adhoc_param_html: [null],
// column_str:[null], // column_str:[null],
// conn_name:[null], // conn_name:[null],
date_param_req:[null], date_param_req: [null],
// folderName:[null], // folderName:[null],
url:[null], url: [null],
// Add sureConnectId to form
sureConnectId: [null],
}); });
// Load sureconnect data first, then load report data
this.loadSureconnectData();
this.getById(this.id); this.getById(this.id);
this.listoddatabase(); this.listoddatabase();
} }
// Add method to load sureconnect data
loadSureconnectData() {
this.sureconnectService.getAll().subscribe((data: any[]) => {
this.sureconnectData = data;
console.log('Sureconnect data loaded:', this.sureconnectData);
}, (error) => {
console.log('Error loading sureconnect data:', error);
});
}
databaselist; databaselist;
listoddatabase(){ listoddatabase() {
this.reportBuilderService.getdatabse().subscribe((data)=>{ this.reportBuilderService.getdatabse().subscribe((data) => {
this.databaselist=data; this.databaselist = data;
console.log(this.databaselist) console.log(this.databaselist)
},(error) => { }, (error) => {
console.log(error); console.log(error);
if(error){ if (error) {
} }
}); });
} }
builderLine; builderLine;
lineId; lineId;
builderLineData:any[] = []; builderLineData: any[] = [];
getById(id: number) { getById(id: number) {
this.reportBuilderService.getrbDetailsById(id).subscribe( this.reportBuilderService.getrbDetailsById(id).subscribe(
(data) => { (data) => {
@@ -70,10 +92,9 @@ export class ReportBuild2editComponent implements OnInit {
this.builderLine = this.ReportData.rpt_builder2_lines; this.builderLine = this.ReportData.rpt_builder2_lines;
this.lineId = this.builderLine[0].id this.lineId = this.builderLine[0].id
console.log("line data ",this.lineId, this.builderLine); console.log("line data ", this.lineId, this.builderLine);
if(this.builderLine[0].model != '') if (this.builderLine[0].model != '') {
{ this.builderLineData = JSON.parse(this.builderLine[0].model);
this.builderLineData = JSON.parse(this.builderLine[0].model) ;
console.log(this.builderLineData); console.log(this.builderLineData);
this.nodeEditProperties.std_param_html = this.builderLineData[0].std_param_html; this.nodeEditProperties.std_param_html = this.builderLineData[0].std_param_html;
@@ -82,6 +103,11 @@ export class ReportBuild2editComponent implements OnInit {
// this.nodeEditProperties.conn_name = this.builderLineData.conn_name; // this.nodeEditProperties.conn_name = this.builderLineData.conn_name;
this.nodeEditProperties.date_param_req = this.builderLineData[0].date_param_req; this.nodeEditProperties.date_param_req = this.builderLineData[0].date_param_req;
this.nodeEditProperties.url = this.builderLineData[0].url; this.nodeEditProperties.url = this.builderLineData[0].url;
// Set sureConnectId if it exists in the data
this.nodeEditProperties.sureConnectId = this.builderLineData[0].sureConnectId || null;
// Update form with loaded data
this.entryForm.patchValue(this.nodeEditProperties);
} }
}, },
(err) => { (err) => {
@@ -92,21 +118,21 @@ export class ReportBuild2editComponent implements OnInit {
stdparams; stdparams;
keysfromurl; keysfromurl;
getkeys(){ getkeys() {
if(this.nodeEditProperties.url !== null){ if (this.nodeEditProperties.url !== null) {
this.reportBuilderService.getcolumnDetailsByurl(this.nodeEditProperties.url).subscribe(data =>{ this.reportBuilderService.getcolumnDetailsByurl(this.nodeEditProperties.url).subscribe(data => {
console.log(data); console.log('coloum list data ', data);
this.keysfromurl = data; this.keysfromurl = data;
this.nodeEditProperties.adhoc_param_html = this.keysfromurl; this.nodeEditProperties.adhoc_param_html = this.keysfromurl;
}) })
}else{ } else {
this.toastr.error("URL is required"); this.toastr.error("URL is required");
} }
} }
listBuilder_Lines = { listBuilder_Lines = {
model:{} model: {}
} }
update() { update() {
@@ -116,6 +142,8 @@ export class ReportBuild2editComponent implements OnInit {
adhoc_param_html: this.nodeEditProperties.adhoc_param_html, adhoc_param_html: this.nodeEditProperties.adhoc_param_html,
date_param_req: this.nodeEditProperties.date_param_req, date_param_req: this.nodeEditProperties.date_param_req,
url: this.nodeEditProperties.url, url: this.nodeEditProperties.url,
// Add sureConnectId to the data
sureConnectId: this.nodeEditProperties.sureConnectId,
}; };
this.builderLineData[0].std_param_html = this.nodeEditProperties.std_param_html; this.builderLineData[0].std_param_html = this.nodeEditProperties.std_param_html;
@@ -124,12 +152,15 @@ export class ReportBuild2editComponent implements OnInit {
// this.builderLineData.conn_name = this.nodeEditProperties.conn_name ; // this.builderLineData.conn_name = this.nodeEditProperties.conn_name ;
this.builderLineData[0].date_param_req = this.nodeEditProperties.date_param_req; this.builderLineData[0].date_param_req = this.nodeEditProperties.date_param_req;
this.builderLineData[0].url = this.nodeEditProperties.url; this.builderLineData[0].url = this.nodeEditProperties.url;
// Add sureConnectId to the data
this.builderLineData[0].sureConnectId = this.nodeEditProperties.sureConnectId;
console.log(this.builderLineData); console.log(this.builderLineData);
// this.builderLineData.splice(1); // this.builderLineData.splice(1);
console.log(this.builderLineData); console.log(this.builderLineData);
let tmp = JSON.stringify(this.builderLineData); //.replace(/\\/g, '') let tmp = JSON.stringify(this.builderLineData); //.replace(/\\/g, '')
this.listBuilder_Lines.model = tmp; this.listBuilder_Lines.model = tmp;
console.log(this.listBuilder_Lines); console.log(this.listBuilder_Lines);
this.reportBuilderService.updaterbLineData(this.listBuilder_Lines, this.lineId).subscribe( this.reportBuilderService.updaterbLineData(this.listBuilder_Lines, this.lineId).subscribe(
(data) => { (data) => {
@@ -149,6 +180,8 @@ console.log(this.listBuilder_Lines);
onSubmit() { onSubmit() {
this.updated = true; this.updated = true;
// Update nodeEditProperties with form values including sureConnectId
Object.assign(this.nodeEditProperties, this.entryForm.value);
this.update(); this.update();
} }

View File

@@ -104,8 +104,11 @@ todayDate;
adhocList:any[]; adhocList:any[];
SQLQuery; SQLQuery;
getUrl; getUrl;
// Add sureConnectId property
sureConnectId: number | null = null;
stdParamfields; stdParamfields;
DateParam; DateParam;
getById(id: number) { getById(id: number) {
this.reportBuilderService.getrbDetailsById(id).subscribe( this.reportBuilderService.getrbDetailsById(id).subscribe(
(data) => { (data) => {
@@ -120,6 +123,8 @@ todayDate;
// this.adhocList = JSON.parse(adhocList); // this.adhocList = JSON.parse(adhocList);
this.DateParam = this.builderLineData.date_param_req; this.DateParam = this.builderLineData.date_param_req;
this.getUrl = this.builderLineData.url; this.getUrl = this.builderLineData.url;
// Get sureConnectId if it exists
this.sureConnectId = this.builderLineData.sureConnectId || null;
console.log(this.adhocList,this.DateParam,this.getUrl) console.log(this.adhocList,this.DateParam,this.getUrl)
this.getStdParam(this.header_id); this.getStdParam(this.header_id);
this.featchData(); this.featchData();
@@ -127,22 +132,58 @@ todayDate;
} }
/**
* Fetch data using the URL and SureConnect connection if available
*/
featchData(){ featchData(){
// If sureConnectId is available, we might want to modify the request
// For now, we'll use the existing implementation but with better error handling
this.reportBuilderService.getAllDetailsByurl(this.getUrl).subscribe(data =>{ this.reportBuilderService.getAllDetailsByurl(this.getUrl).subscribe(data =>{
console.log(data); console.log(data);
if(data.body){ if(data.body){
// Check if the response is XML (starts with <) or JSON
if (typeof data.body === 'string' && data.body.trim().startsWith('<')) {
// Handle XML response
console.log('Received XML response, parsing to JSON');
try {
this.rows = this.parseXMLToJSON(data.body);
this.filterRows = [...this.rows]; // Create a copy
console.log('Parsed XML data:', this.rows);
} catch (error) {
console.error('Error parsing XML:', error);
this.rows = [];
this.filterRows = [];
}
} else {
// Handle JSON response
try {
console.log(JSON.parse(data.body)); console.log(JSON.parse(data.body));
this.rows = JSON.parse(data.body); this.rows = JSON.parse(data.body);
this.filterRows = JSON.parse(data.body); this.filterRows = JSON.parse(data.body);
} catch (error) {
console.error('Error parsing JSON:', error);
this.rows = [];
this.filterRows = [];
} }
}
} else {
// If no body, initialize with empty arrays
this.rows = [];
this.filterRows = [];
}
}, error => {
// Handle HTTP errors
console.error('Error fetching data:', error);
this.rows = [];
this.filterRows = [];
}); });
} }
dynamicHtml:any = []; dynamicHtml: any = [];
dynamicHtmlFlag = false; dynamicHtmlFlag = false;
stdParmas; stdParmas;
stdParamFlag = false; stdParamFlag = false;
getStdParam(id: any){ getStdParam(id: any) {
console.log(this.builderLineData.std_param_html); console.log(this.builderLineData.std_param_html);
this.dynamicHtml = this.builderLineData.std_param_html; this.dynamicHtml = this.builderLineData.std_param_html;
// this.dynamicHtml = ['a.abc','b.abcde'] // this.dynamicHtml = ['a.abc','b.abcde']
@@ -154,9 +195,9 @@ todayDate;
} }
console.log(this.dynamicForm.value); console.log(this.dynamicForm.value);
} }
if(this.dynamicHtml == undefined || this.dynamicHtml == ''){ if (this.dynamicHtml == undefined || this.dynamicHtml == '') {
this.dynamicHtmlFlag = false; this.dynamicHtmlFlag = false;
}else{ } else {
this.dynamicHtmlFlag = true; this.dynamicHtmlFlag = true;
} }
@@ -174,37 +215,37 @@ todayDate;
// } // }
// }); // });
} }
modo2(val){ modo2(val) {
console.log(val); console.log(val);
this.selectedfrom=val; this.selectedfrom = val;
} }
modo3(val){ modo3(val) {
console.log(val); console.log(val);
this.selectedto=val; this.selectedto = val;
} }
duplicateArray=[]; duplicateArray = [];
myDateValue: Date; myDateValue: Date;
toDate:Date; toDate: Date;
reverseAndTimeStamp(dateString) { reverseAndTimeStamp(dateString) {
const reverse = new Date(dateString.split("-").reverse().join("-")); const reverse = new Date(dateString.split("-").reverse().join("-"));
return reverse.getTime(); return reverse.getTime();
} }
filterDate() { filterDate() {
let fromdate=moment(this.myDateValue).format('DD-MM-YYYY'); let fromdate = moment(this.myDateValue).format('DD-MM-YYYY');
console.log(fromdate) console.log(fromdate)
let todate=moment(this.toDate).format('DD-MM-YYYY'); let todate = moment(this.toDate).format('DD-MM-YYYY');
if(this.myDateValue && this.toDate){ if (this.myDateValue && this.toDate) {
const selectedMembers = this.array.filter(m => { const selectedMembers = this.array.filter(m => {
return this.reverseAndTimeStamp(m.fromDate) >= this.reverseAndTimeStamp(fromdate) && this.reverseAndTimeStamp(m.fromDate) <= this.reverseAndTimeStamp(todate) return this.reverseAndTimeStamp(m.fromDate) >= this.reverseAndTimeStamp(fromdate) && this.reverseAndTimeStamp(m.fromDate) <= this.reverseAndTimeStamp(todate)
} }
); );
this.duplicateArray=selectedMembers this.duplicateArray = selectedMembers
}else{ } else {
this.duplicateArray=this.array this.duplicateArray = this.array
} }
console.log(this.duplicateArray); // the result objects console.log(this.duplicateArray); // the result objects
this.modalselect=false; this.modalselect = false;
} }
dateParameter: string; dateParameter: string;
from_date: Date; from_date: Date;
@@ -228,10 +269,10 @@ this.duplicateArray=this.array
this.to_date = new Date(this.from_date); this.to_date = new Date(this.from_date);
this.to_date.setDate(this.from_date.getDate() + 6); this.to_date.setDate(this.from_date.getDate() + 6);
console.log(this.from_date); console.log(this.from_date);
this.myDateValue=this.from_date; this.myDateValue = this.from_date;
console.log(this.to_date); console.log(this.to_date);
console.log(this.myDateValue); console.log(this.myDateValue);
this.toDate=this.to_date; this.toDate = this.to_date;
this.FromDatequery = this.from_date.toISOString().substring(0, 10); this.FromDatequery = this.from_date.toISOString().substring(0, 10);
this.ToDatequery = this.to_date.toISOString().substring(0, 10); this.ToDatequery = this.to_date.toISOString().substring(0, 10);
@@ -254,10 +295,10 @@ this.duplicateArray=this.array
// Calculate the date of Sunday of the previous week // Calculate the date of Sunday of the previous week
this.to_date = new Date(this.from_date); this.to_date = new Date(this.from_date);
this.to_date.setDate(this.from_date.getDate() + 6); this.to_date.setDate(this.from_date.getDate() + 6);
this.myDateValue=this.from_date; this.myDateValue = this.from_date;
console.log(this.to_date); console.log(this.to_date);
console.log(this.myDateValue); console.log(this.myDateValue);
this.toDate=this.to_date; this.toDate = this.to_date;
this.FromDatequery = this.from_date.toISOString().substring(0, 10); this.FromDatequery = this.from_date.toISOString().substring(0, 10);
@@ -328,10 +369,10 @@ this.duplicateArray=this.array
// Calculate the date of the last day of the current year // Calculate the date of the last day of the current year
this.to_date = new Date(currentDate.getFullYear(), 11, 31); this.to_date = new Date(currentDate.getFullYear(), 11, 31);
this.myDateValue=this.from_date; this.myDateValue = this.from_date;
console.log(this.to_date); console.log(this.to_date);
console.log(this.myDateValue); console.log(this.myDateValue);
this.toDate=this.to_date; this.toDate = this.to_date;
this.FromDatequery = this.from_date.toISOString().substring(0, 10); this.FromDatequery = this.from_date.toISOString().substring(0, 10);
@@ -349,48 +390,48 @@ this.duplicateArray=this.array
// Calculate the date of the last day of the previous year // Calculate the date of the last day of the previous year
this.to_date = new Date(currentDate.getFullYear() - 1, 11, 31); this.to_date = new Date(currentDate.getFullYear() - 1, 11, 31);
this.myDateValue=this.from_date; this.myDateValue = this.from_date;
console.log(this.to_date); console.log(this.to_date);
console.log(this.myDateValue); console.log(this.myDateValue);
this.toDate=this.to_date; this.toDate = this.to_date;
this.FromDatequery = this.from_date.toISOString().substring(0, 10); this.FromDatequery = this.from_date.toISOString().substring(0, 10);
this.ToDatequery = this.to_date.toISOString().substring(0, 10); this.ToDatequery = this.to_date.toISOString().substring(0, 10);
// this.filterDate(); // this.filterDate();
} }
SelectdateType; SelectdateType;
select(val:any){ select(val: any) {
console.log(val); console.log(val);
this.SelectdateType = val; this.SelectdateType = val;
if(val === 'This Week'){ if (val === 'This Week') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateThisWeek() this.calculateThisWeek()
}else if(val === 'Last Week'){ } else if (val === 'Last Week') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateLastWeek() this.calculateLastWeek()
}else if(val === 'This Month'){ } else if (val === 'This Month') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateThisMonth() this.calculateThisMonth()
}else if(val === 'Last Month'){ } else if (val === 'Last Month') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateLastMonth() this.calculateLastMonth()
// }else if(val === 'To Specific FromDate To To Date'){ // }else if(val === 'To Specific FromDate To To Date'){
// this.openmodel() // this.openmodel()
} }
else if(val === 'This Year'){ else if (val === 'This Year') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateThisYear() this.calculateThisYear()
}else if(val === 'Last Year'){ } else if (val === 'Last Year') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.calculateLastYear() this.calculateLastYear()
} }
else if(val === 'Today'){ else if (val === 'Today') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.myDateValue = this.todayDate; this.myDateValue = this.todayDate;
@@ -399,7 +440,7 @@ this.duplicateArray=this.array
this.FromDatequery = this.myDateValue; this.FromDatequery = this.myDateValue;
this.ToDatequery = this.toDate; this.ToDatequery = this.toDate;
} }
else if(val === '--Select Particular--'){ else if (val === '--Select Particular--') {
this.FromDatequery = null; this.FromDatequery = null;
this.ToDatequery = null; this.ToDatequery = null;
this.newfrom = null; this.newfrom = null;
@@ -410,8 +451,8 @@ this.duplicateArray=this.array
} }
openmodel(){ openmodel() {
this.modalselect=true; this.modalselect = true;
} }
onExport() { onExport() {
@@ -423,15 +464,15 @@ this.duplicateArray=this.array
downloadFile(format: string) { downloadFile(format: string) {
const date = moment().format('YYYYMMDD_HHmmss') const date = moment().format('YYYYMMDD_HHmmss')
const reportNameWithUnderscore = this.reportName + '_' + date; const reportNameWithUnderscore = this.reportName + '_' + date;
this.reportBuilderService.downloadFile(format, this.filterRows,reportNameWithUnderscore) this.reportBuilderService.downloadFile(format, this.filterRows, reportNameWithUnderscore)
} }
back(){ back() {
this.router.navigate(["../../all"], { relativeTo: this.route }); this.router.navigate(["../../all"], { relativeTo: this.route });
} }
FormattedAdhocparameters; FormattedAdhocparameters;
adocdata; adocdata;
// showPlusIconRow: number | null = 0; // showPlusIconRow: number | null = 0;
onAddLines(){ onAddLines() {
console.log(this.serverData); console.log(this.serverData);
const lastRow = this.serverData[this.serverData.length - 1]; const lastRow = this.serverData[this.serverData.length - 1];
if (lastRow && lastRow.fields_name !== '') { if (lastRow && lastRow.fields_name !== '') {
@@ -494,8 +535,8 @@ adocdata;
} }
rows:any[]; rows: any[];
filterRows:any[]; filterRows: any[];
columns: any[]; columns: any[];
rowdata; rowdata;
FromDatequery; FromDatequery;
@@ -505,11 +546,11 @@ adocdata;
newto; newto;
dateKey; dateKey;
runtheQuery(){ runtheQuery() {
console.log(this.myDateValue , this.toDate); console.log(this.myDateValue, this.toDate);
let query = this.SQLQuery; let query = this.SQLQuery;
// let query // let query
if(this.dynamicForm.value){ if (this.dynamicForm.value) {
// for(let i = 0; i < this.dynamicForm.value.length; i++){ // for(let i = 0; i < this.dynamicForm.value.length; i++){
// // const query = this.SQLQuery + " AND " + this.dynamicForm.controls[i] + " = " + this.dynamicForm.value[i] // // const query = this.SQLQuery + " AND " + this.dynamicForm.controls[i] + " = " + this.dynamicForm.value[i]
@@ -519,7 +560,7 @@ runtheQuery(){
// Iterate over the keys in dynamicForm.value // Iterate over the keys in dynamicForm.value
Object.keys(this.dynamicForm.value).forEach((key) => { Object.keys(this.dynamicForm.value).forEach((key) => {
// Append the condition for each key to the query // Append the condition for each key to the query
if (this.dynamicForm.value[key] !== null ) { if (this.dynamicForm.value[key] !== null) {
this.selectcolumn(this.dynamicForm.value); this.selectcolumn(this.dynamicForm.value);
// query += ` AND ${key} = '${this.dynamicForm.value[key]}'`; // query += ` AND ${key} = '${this.dynamicForm.value[key]}'`;
} }
@@ -539,27 +580,27 @@ runtheQuery(){
// query += ` AND cretaedat BETWEEN '${this.FromDatequery}' AND '${this.ToDatequery}'`; // query += ` AND cretaedat BETWEEN '${this.FromDatequery}' AND '${this.ToDatequery}'`;
// }else // }else
if(this.DateParam == true){ if (this.DateParam == true) {
this.dateKey = 'createdat'; this.dateKey = 'createdat';
this.adhocList.forEach(key => { this.adhocList.forEach(key => {
if (key.includes("created_at")) { if (key.includes("created_at")) {
this.dateKey ="created_at" ; this.dateKey = "created_at";
} }
}); });
this.adhocList.forEach(key => { this.adhocList.forEach(key => {
if (key.includes("createdAt")) { if (key.includes("createdAt")) {
this.dateKey ="createdAt" ; this.dateKey = "createdAt";
} }
}); });
if(this.myDateValue && this.toDate){ if (this.myDateValue && this.toDate) {
if(this.myDateValue){ if (this.myDateValue) {
this.newfrom = new Date(this.myDateValue); this.newfrom = new Date(this.myDateValue);
// const year = inputDate.getFullYear(); // const year = inputDate.getFullYear();
// const month = String(inputDate.getMonth() + 1).padStart(2, "0"); // Months are zero-based, so add 1 // const month = String(inputDate.getMonth() + 1).padStart(2, "0"); // Months are zero-based, so add 1
// const day = String(inputDate.getDate()).padStart(2, "0"); // const day = String(inputDate.getDate()).padStart(2, "0");
// this.newfrom = `${year}-${month}-${day}`; // this.newfrom = `${year}-${month}-${day}`;
} }
if(this.toDate){ if (this.toDate) {
this.newto = new Date(this.toDate); this.newto = new Date(this.toDate);
// const year = inputDate.getFullYear(); // const year = inputDate.getFullYear();
// const month = String(inputDate.getMonth() + 1).padStart(2, "0"); // Months are zero-based, so add 1 // const month = String(inputDate.getMonth() + 1).padStart(2, "0"); // Months are zero-based, so add 1
@@ -569,40 +610,37 @@ runtheQuery(){
} }
query += ` AND ${this.dateKey} BETWEEN '${this.newfrom}' AND '${this.newto}'`; query += ` AND ${this.dateKey} BETWEEN '${this.newfrom}' AND '${this.newto}'`;
} }
} }
// if(this.myDateValue && this.toDate){ // if(this.myDateValue && this.toDate){
// query += ` AND from_date = NVL(${this.myDateValue}from_date, 'from_date') AND to_date = NVL(${this.toDate}to_date, 'to_date')`; // query += ` AND from_date = NVL(${this.myDateValue}from_date, 'from_date') AND to_date = NVL(${this.toDate}to_date, 'to_date')`;
// } // }
console.log(query); console.log(query);
} }
// if(this.FormattedAdhocparameters){ // if(this.FormattedAdhocparameters){
// query += this.FormattedAdhocparameters // query += this.FormattedAdhocparameters
// } // }
this.selectcolumn(this.serverData); this.selectcolumn(this.serverData);
// query = `SELECT a.name AS name, b.dob AS dob FROM abc a, abcde b WHERE a.name = 'gaurav' AND a.abc = NVL(b.abc, 'name') AND a.abcde = NVL(b.abcde, 'test');` // query = `SELECT a.name AS name, b.dob AS dob FROM abc a, abcde b WHERE a.name = 'gaurav' AND a.abc = NVL(b.abc, 'name') AND a.abcde = NVL(b.abcde, 'test');`
console.log(query); console.log(query);
this.reportBuilderService.getMasterData(query).subscribe((data) => { this.reportBuilderService.getMasterData(query).subscribe((data) => {
// this.rows = data; // this.rows = data;
console.log(this.rows); console.log(this.rows);
this.rowdata= [this.rows]; this.rowdata = [this.rows];
console.log(typeof this.rows); console.log(typeof this.rows);
if(data){ if (data) {
this.toastr.success("Run Successfully") this.toastr.success("Run Successfully")
} }
var j; var j;
var cart = []; var cart = [];
for(var i = 0; i < data.length; i++) for (var i = 0; i < data.length; i++) {
{
var columnsIn = data[i]; var columnsIn = data[i];
if(i==1) if (i == 1) {
{ for (var key in columnsIn) {
for(var key in columnsIn) j = { prop: key, name: key };
{
j={prop:key , name: key};
cart.push(j) cart.push(j)
} }
@@ -610,30 +648,30 @@ this.rowdata= [this.rows];
} }
this.columns = cart; this.columns = cart;
}); });
} }
getHeaders() { getHeaders() {
let headers: string[] = []; let headers: string[] = [];
if(this.rows) { if (this.rows) {
this.rows.forEach((value) => { this.rows.forEach((value) => {
Object.keys(value).forEach((key) => { Object.keys(value).forEach((key) => {
if(!headers.find((header) => header == key)){ if (!headers.find((header) => header == key)) {
headers.push(key) headers.push(key)
} }
}) })
}) })
} }
return headers; return headers;
} }
getFilterHeaders() { getFilterHeaders() {
let headers: string[] = []; let headers: string[] = [];
if(this.filterRows) { if (this.filterRows) {
this.filterRows.forEach((value) => { this.filterRows.forEach((value) => {
Object.keys(value).forEach((key) => { Object.keys(value).forEach((key) => {
if(!headers.find((header) => header == key)){ if (!headers.find((header) => header == key)) {
headers.push(key) headers.push(key)
} }
}) })
@@ -644,8 +682,8 @@ getFilterHeaders() {
selectedValues: { [key: string]: any[] } = {}; selectedValues: { [key: string]: any[] } = {};
selectcolumn(data: any) { selectcolumn(data: any) {
if (Array.isArray(data)) { if (Array.isArray(data)) {
for (const item of data) { for (const item of data) {
const columnName = item.fields_name; const columnName = item.fields_name;
@@ -695,13 +733,21 @@ selectcolumn(data: any) {
console.log(this.selectedValues); console.log(this.selectedValues);
this.filterRowsBySelectedValues(); this.filterRowsBySelectedValues();
} }
filtered = false; filtered = false;
filterRowsBySelectedValues() { filterRowsBySelectedValues() {
// Check if rows is defined and iterable
if (!this.rows || !Array.isArray(this.rows)) {
console.warn('Rows is not defined or not an array');
this.filterRows = [];
this.filtered = false;
return;
}
// Create a filteredRows array to store the filtered data // Create a filteredRows array to store the filtered data
const filteredRows = []; const filteredRows = [];
@@ -750,7 +796,7 @@ filterRowsBySelectedValues() {
} }
} }
} }
if(this.FromDatequery !== null && this.ToDatequery !== null){ if (this.FromDatequery !== null && this.ToDatequery !== null) {
this.newfrom = this.FromDatequery this.newfrom = this.FromDatequery
this.newto = this.ToDatequery this.newto = this.ToDatequery
} }
@@ -803,11 +849,11 @@ filterRowsBySelectedValues() {
// Set this.filtered based on allArraysEmpty and dateRangeNotSelected // Set this.filtered based on allArraysEmpty and dateRangeNotSelected
this.filtered = !allArraysEmpty || !dateRangeNotSelected; this.filtered = !allArraysEmpty || !dateRangeNotSelected;
} }
formatDate(dateObj: any): string { formatDate(dateObj: any): string {
// Extract individual date properties // Extract individual date properties
const { year, monthValue, dayOfMonth, hour, minute, second } = dateObj; const { year, monthValue, dayOfMonth, hour, minute, second } = dateObj;
@@ -816,9 +862,9 @@ formatDate(dateObj: any): string {
// Format the date as needed (e.g., using built-in JavaScript date formatting) // Format the date as needed (e.g., using built-in JavaScript date formatting)
return formattedDate.toLocaleString(); // Or any other desired formatting return formattedDate.toLocaleString(); // Or any other desired formatting
} }
isDate(value: any): boolean { isDate(value: any): boolean {
return ( return (
value instanceof Date || value instanceof Date ||
(value && (value &&
@@ -826,6 +872,83 @@ isDate(value: any): boolean {
value.monthValue !== undefined && value.monthValue !== undefined &&
value.dayOfMonth !== undefined) value.dayOfMonth !== undefined)
); );
} }
/**
* Simple XML parser to convert XML to JSON array
* Handles the specific format: <User><id>101</id><name>John Doe</name><email>john.doe@example.com</email></User>
* @param xmlString The XML string to parse
* @returns Array of objects representing the XML data
*/
private parseXMLToJSON(xmlString: string): any[] {
// Remove any XML declaration
xmlString = xmlString.replace(/<\?xml[^>]*\?>/g, '');
// Extract the root element name (e.g., "User" from <User>...</User>)
const rootMatch = xmlString.match(/<(\w+)(?:\s[^>]*)?>/);
if (!rootMatch) {
console.warn('Could not identify root element in XML');
return [];
}
const rootElement = rootMatch[1];
const results: any[] = [];
// Create a regex to match all instances of the root element
const regex = new RegExp(`<${rootElement}(?:\\s[^>]*)?>([\\s\\S]*?)<\\/${rootElement}>`, 'g');
let match;
while ((match = regex.exec(xmlString)) !== null) {
const elementContent = match[1];
const item: any = {};
// Extract all tags and their values
const tagRegex = /<(\w+)>(.*?)<\/\1>/g;
let tagMatch;
while ((tagMatch = tagRegex.exec(elementContent)) !== null) {
const tagName = tagMatch[1];
const tagValue = tagMatch[2];
// Try to convert to appropriate type
item[tagName] = this.convertValueType(tagValue);
}
results.push(item);
}
return results;
}
/**
* Convert string values to appropriate types (number, boolean, etc.)
* @param value The string value to convert
* @returns The value converted to the appropriate type
*/
private convertValueType(value: string): any {
// Check for empty value
if (value === '') {
return value;
}
// Check for boolean values
if (value.toLowerCase() === 'true') {
return true;
}
if (value.toLowerCase() === 'false') {
return false;
}
// Check for numeric values
if (!isNaN(Number(value)) && !isNaN(parseFloat(value))) {
// Check if it's an integer or float
if (Number.isInteger(parseFloat(value))) {
return parseInt(value, 10);
} else {
return parseFloat(value);
}
}
// Return as string if no other type matches
return value;
}
} }

View File

@@ -39,6 +39,14 @@
</div> </div>
</a> </a>
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
routerLink="/cns-portal/shield-dashboard">
<div class="nav-icon-wrapper">
<clr-icon shape="shield" solid></clr-icon>
<span class="nav-tooltip">Shield Dashboard</span>
</div>
</a>
<a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active" <a href="javascript://" class="nav-link nav-icon modern-nav-icon" routerLinkActive="active"
routerLink="/cns-portal/rerunner/all" (click)="getName()"> routerLink="/cns-portal/rerunner/all" (click)="getName()">
<div class="nav-icon-wrapper"> <div class="nav-icon-wrapper">
@@ -122,27 +130,27 @@
<a href="javascript://" clrDropdownItem (click)="switchLanguage('en')" class="modern-lang-item"> <a href="javascript://" clrDropdownItem (click)="switchLanguage('en')" class="modern-lang-item">
<clr-icon shape="globe" class="lang-icon"></clr-icon> <clr-icon shape="globe" class="lang-icon"></clr-icon>
<span>English</span> <span>English</span>
<div class="lang-flag">🇺🇸</div> <div class="lang-flag">🇺🇸</div>
</a> </a>
<a href="javascript://" clrDropdownItem (click)="switchLanguage('hi')" class="modern-lang-item"> <a href="javascript://" clrDropdownItem (click)="switchLanguage('hi')" class="modern-lang-item">
<clr-icon shape="globe" class="lang-icon"></clr-icon> <clr-icon shape="globe" class="lang-icon"></clr-icon>
<span>हिन्दी</span> <span>हिन्दी</span>
<div class="lang-flag">🇮🇳</div> <div class="lang-flag">🇮🇳</div>
</a> </a>
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ta')" class="modern-lang-item"> <a href="javascript://" clrDropdownItem (click)="switchLanguage('ta')" class="modern-lang-item">
<clr-icon shape="globe" class="lang-icon"></clr-icon> <clr-icon shape="globe" class="lang-icon"></clr-icon>
<span>தமிழ்</span> <span>தமிழ்</span>
<div class="lang-flag">🇮🇳</div> <div class="lang-flag">🇮🇳</div>
</a> </a>
<a href="javascript://" clrDropdownItem (click)="switchLanguage('pa')" class="modern-lang-item"> <a href="javascript://" clrDropdownItem (click)="switchLanguage('pa')" class="modern-lang-item">
<clr-icon shape="globe" class="lang-icon"></clr-icon> <clr-icon shape="globe" class="lang-icon"></clr-icon>
<span>ਪੰਜਾਬੀ</span> <span>ਪੰਜਾਬੀ</span>
<div class="lang-flag">🇮🇳</div> <div class="lang-flag">🇮🇳</div>
</a> </a>
<a href="javascript://" clrDropdownItem (click)="switchLanguage('ml')" class="modern-lang-item"> <a href="javascript://" clrDropdownItem (click)="switchLanguage('ml')" class="modern-lang-item">
<clr-icon shape="globe" class="lang-icon"></clr-icon> <clr-icon shape="globe" class="lang-icon"></clr-icon>
<span>മലയാളം</span> <span>മലയാളം</span>
<div class="lang-flag">🇮🇳</div> <div class="lang-flag">🇮🇳</div>
</a> </a>
</clr-dropdown-menu> </clr-dropdown-menu>
</clr-dropdown> </clr-dropdown>

View File

@@ -1,3 +1,26 @@
import { Ad10Component } from './BuilderComponents/angulardatatype/Ad10/Ad10.component';
import { DefatestComponent } from './BuilderComponents/defu/Defatest/Defatest.component';
import { ChildformComponent } from './BuilderComponents/stpkg/Childform/Childform.component';
import { DistrictComponent } from './BuilderComponents/testdata/District/District.component';
import { StateComponent } from './BuilderComponents/testdata/State/State.component';
import { CountryComponent } from './BuilderComponents/testdata/Country/Country.component';
import { Ad9Component } from './BuilderComponents/angulardatatype/Ad9/Ad9.component';
import { Ad8Component } from './BuilderComponents/angulardatatype/Ad8/Ad8.component';
import { Ad7Component } from './BuilderComponents/angulardatatype/Ad7/Ad7.component';
import { Ad6Component } from './BuilderComponents/angulardatatype/Ad6/Ad6.component';
import { Adv5Component } from './BuilderComponents/angulardatatype/Adv5/Adv5.component';
import { Adv4Component } from './BuilderComponents/angulardatatype/Adv4/Adv4.component';
import { SupportComponent } from './BuilderComponents/angulardatatype/Support/Support.component';
import { Adv3Component } from './BuilderComponents/angulardatatype/Adv3/Adv3.component';
import { Dv2Component } from './BuilderComponents/angulardatatype/Dv2/Dv2.component';
import { Adv1Component } from './BuilderComponents/angulardatatype/Adv1/Adv1.component';
import { Basicp3Component } from './BuilderComponents/angulardatatype/Basicp3/Basicp3.component';
import { Basicp2Component } from './BuilderComponents/angulardatatype/Basicp2/Basicp2.component';
import { Basicp1Component } from './BuilderComponents/angulardatatype/Basicp1/Basicp1.component';
import { SequencegenaratorComponent } from './fnd/sequencegenarator/sequencegenarator.component'; import { SequencegenaratorComponent } from './fnd/sequencegenarator/sequencegenarator.component';
import { Component, NgModule } from '@angular/core'; import { Component, NgModule } from '@angular/core';
@@ -82,6 +105,17 @@ import { MappingruleallComponent } from './datamanagement/mappingrule/mappingrul
import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingruleadd/mappingruleadd.component'; import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingruleadd/mappingruleadd.component';
import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component'; import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component';
import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component'; import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component';
import { AllapiregisteryComponent } from './fnd/apiregistery/allapiregistery/allapiregistery.component';
import { AddapiregisteryComponent } from './fnd/apiregistery/addapiregistery/addapiregistery.component';
import { EditapiregisteryComponent } from './fnd/apiregistery/editapiregistery/editapiregistery.component';
import { ApiregisterylineComponent } from './fnd/apiregistery/Apiregisteryline/Apiregisteryline.component';
import { Customer_informationComponent } from './BuilderComponents/angulardatatype/Customer_information/Customer_information.component';
import { Deployment_typeComponent } from './BuilderComponents/angulardatatype/Deployment_type/Deployment_type.component';
import { ManufacturerComponent } from './BuilderComponents/angulardatatype/Manufacturer/Manufacturer.component';
import { Order_summaryComponent } from './BuilderComponents/angulardatatype/Order_summary/Order_summary.component';
import { ProductComponent } from './BuilderComponents/angulardatatype/Product/Product.component';
import { TypesComponent } from './BuilderComponents/angulardatatype/Types/Types.component';
import { Test2Component } from './BuilderComponents/testdata/Test2/Test2.component';
import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component'; import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component';
import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component'; import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component';
import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component'; import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component';
@@ -89,9 +123,9 @@ import { Data_lakeComponent } from './builder/dashboardnew/Data_lake/Data_lake.c
import { SureconnectComponent } from './builder/dashboardnew/sureconnect/sureconnect.component'; import { SureconnectComponent } from './builder/dashboardnew/sureconnect/sureconnect.component';
import { EditsureconnectComponent } from './builder/dashboardnew/sureconnect/editsureconnect/editsureconnect.component'; import { EditsureconnectComponent } from './builder/dashboardnew/sureconnect/editsureconnect/editsureconnect.component';
import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.component'; import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.component';
// import { QueryComponent } from './superadmin/query/query.component'; import { QueryComponent } from './superadmin/query/query.component';
// import { QueryaddComponent } from './superadmin/queryadd/queryadd.component'; import { QueryaddComponent } from './superadmin/queryadd/queryadd.component';
// import { QueryeditComponent } from './superadmin/queryedit/queryedit.component'; import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
@@ -132,6 +166,8 @@ const routes: Routes = [
{ path: 'editconnect/:id', component: EditsureconnectComponent }, { path: 'editconnect/:id', component: EditsureconnectComponent },
{ {
path: 'reportbuild', component: ReportBuildComponent, path: 'reportbuild', component: ReportBuildComponent,
children: [ children: [
@@ -143,9 +179,9 @@ const routes: Routes = [
//SUPER ADMIN //SUPER ADMIN
// { path: 'query', component: QueryComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } }, { path: 'query', component: QueryComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } },
// { path: 'reportQuery/:id/queryadd', component: QueryaddComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } }, { path: 'reportQuery/:id/queryadd', component: QueryaddComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } },
// { path: 'reportQuery/queryedit/:id', component: QueryeditComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } }, { path: 'reportQuery/queryedit/:id', component: QueryeditComponent, canActivate: [AuthGuard], data: { roles: [Role.Admin] } },
@@ -189,6 +225,12 @@ const routes: Routes = [
] ]
}, },
// Shield Dashboard
{
path: 'shield-dashboard',
loadChildren: () => import('./builder/dashboardnew/gadgets/shield-dashboard/shield-dashboard-routing.module').then(m => m.ShieldDashboardRoutingModule)
},
{ {
path: 'dashboardrunner', component: DashboardrunnerComponent, path: 'dashboardrunner', component: DashboardrunnerComponent,
children: [ children: [
@@ -236,8 +278,20 @@ const routes: Routes = [
], ],
}, },
{ path: 'SequenceGenerator', component: SequencegenaratorComponent }, { path: 'SequenceGenerator', component: SequencegenaratorComponent },
{ path: 'apiregistery', component: ApiregisteryComponent },
// Api registery
{
path: 'apiregistery', component: ApiregisteryComponent,
children: [
{ path: '', redirectTo: 'all', pathMatch: 'full' },
{ path: 'all', component: AllapiregisteryComponent },
{ path: 'add', component: AddapiregisteryComponent },
{ path: 'edit/:id', component: EditapiregisteryComponent },
{ path: 'line/:id', component: ApiregisterylineComponent },
],
},
// DATA MANAGEMENT // DATA MANAGEMENT
@@ -270,18 +324,186 @@ const routes: Routes = [
// buildercomponents // buildercomponents
{ path: 'Country', component: CountryComponent },
{ path: 'Adv3', component: Adv3Component },
{ path: 'Ad10', component: Ad10Component },
{ path: 'Childform', component: ChildformComponent },
{ path: 'District', component: DistrictComponent },
{ path: 'State', component: StateComponent },
{ path: 'Country', component: CountryComponent },
{ path: 'Ad9', component: Ad9Component },
{ path: 'Ad8', component: Ad8Component },
{ path: 'Ad7', component: Ad7Component },
{ path: 'Ad6', component: Ad6Component },
{ path: 'Adv5', component: Adv5Component },
{ path: 'Support', component: SupportComponent },
{ path: 'Adv3', component: Adv3Component },
{ path: 'tokenregistery', component: Token_registeryComponent }, { path: 'tokenregistery', component: Token_registeryComponent },
{ path: 'Defatest', component: DefatestComponent },
{ path: 'Country', component: CountryComponent },
{ path: 'Defatest', component: DefatestComponent },
{ path: 'Test2', component: Test2Component },
{ path: 'Country', component: CountryComponent },
{ path: 'Test2', component: Test2Component },
{ path: 'Childform', component: ChildformComponent },
{ path: 'District', component: DistrictComponent },
{ path: 'State', component: StateComponent },
{ path: 'Country', component: CountryComponent },
{ path: 'Ad9', component: Ad9Component },
{ path: 'Ad8', component: Ad8Component },
{ path: 'Ad7', component: Ad7Component },
{ path: 'Ad6', component: Ad6Component },
{ path: 'Adv5', component: Adv5Component },
{ path: 'Adv4', component: Adv4Component },
{ path: 'Support', component: SupportComponent },
{ path: 'Adv3', component: Adv3Component },
{ path: 'Dv2', component: Dv2Component },
{ path: 'Adv1', component: Adv1Component },
{ path: 'Basicp3', component: Basicp3Component },
{ path: 'Basicp2', component: Basicp2Component },
{ path: 'Basicp1', component: Basicp1Component },
{ path: 'cust', component: Customer_informationComponent },
{ path: 'Order_summary', component: Order_summaryComponent },
{ path: 'Types', component: TypesComponent },
{ path: 'Product', component: ProductComponent },
{ path: 'Manufacturer', component: ManufacturerComponent },
{ path: 'Deployment_type', component: Deployment_typeComponent },
{ path: 'Stepper_workflow', component: Stepper_workflowComponent }, { path: 'Stepper_workflow', component: Stepper_workflowComponent },
{ path: '**', component: PageNotFoundComponent }, { path: '**', component: PageNotFoundComponent },
] ]

View File

@@ -1,3 +1,25 @@
import { Ad10Component } from './BuilderComponents/angulardatatype/Ad10/Ad10.component';
import { DefatestComponent } from './BuilderComponents/defu/Defatest/Defatest.component';
import { ChildformComponent } from './BuilderComponents/stpkg/Childform/Childform.component';
import { DistrictComponent } from './BuilderComponents/testdata/District/District.component';
import { StateComponent } from './BuilderComponents/testdata/State/State.component';
import { CountryComponent } from './BuilderComponents/testdata/Country/Country.component';
import { Ad9Component } from './BuilderComponents/angulardatatype/Ad9/Ad9.component';
import { Ad8Component } from './BuilderComponents/angulardatatype/Ad8/Ad8.component';
import { Ad7Component } from './BuilderComponents/angulardatatype/Ad7/Ad7.component';
import { Ad6Component } from './BuilderComponents/angulardatatype/Ad6/Ad6.component';
import { Adv5Component } from './BuilderComponents/angulardatatype/Adv5/Adv5.component';
import { Adv4Component } from './BuilderComponents/angulardatatype/Adv4/Adv4.component';
import { SupportComponent } from './BuilderComponents/angulardatatype/Support/Support.component';
import { Adv3Component } from './BuilderComponents/angulardatatype/Adv3/Adv3.component';
import { Dv2Component } from './BuilderComponents/angulardatatype/Dv2/Dv2.component';
import { Adv1Component } from './BuilderComponents/angulardatatype/Adv1/Adv1.component';
import { Basicp3Component } from './BuilderComponents/angulardatatype/Basicp3/Basicp3.component';
import { Basicp2Component } from './BuilderComponents/angulardatatype/Basicp2/Basicp2.component';
import { Basicp1Component } from './BuilderComponents/angulardatatype/Basicp1/Basicp1.component';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
@@ -74,6 +96,9 @@ import { RadarChartComponent } from './builder/dashboardnew/gadgets/radar-chart/
import { ScatterChartComponent } from './builder/dashboardnew/gadgets/scatter-chart/scatter-chart.component'; import { ScatterChartComponent } from './builder/dashboardnew/gadgets/scatter-chart/scatter-chart.component';
import { ToDoChartComponent } from './builder/dashboardnew/gadgets/to-do-chart/to-do-chart.component'; import { ToDoChartComponent } from './builder/dashboardnew/gadgets/to-do-chart/to-do-chart.component';
import { ScheduleComponent } from './builder/dashboardnew/schedule/schedule.component'; import { ScheduleComponent } from './builder/dashboardnew/schedule/schedule.component';
import { CommonFilterComponent } from './builder/dashboardnew/common-filter/common-filter.component';
import { ChartWrapperComponent } from './builder/dashboardnew/common-filter/chart-wrapper.component';
import { CompactFilterComponent } from './builder/dashboardnew/common-filter/compact-filter.component';
import { AddextensionComponent } from './fnd/extension/addextension/addextension.component'; import { AddextensionComponent } from './fnd/extension/addextension/addextension.component';
import { AllextensionComponent } from './fnd/extension/allextension/allextension.component'; import { AllextensionComponent } from './fnd/extension/allextension/allextension.component';
import { EditextensionComponent } from './fnd/extension/editextension/editextension.component'; import { EditextensionComponent } from './fnd/extension/editextension/editextension.component';
@@ -91,6 +116,9 @@ import { RadarRunnerComponent } from './builder/dashboardrunner/dashrunnerline/r
import { ScatterRunnerComponent } from './builder/dashboardrunner/dashrunnerline/scatter-runner/scatter-runner.component'; import { ScatterRunnerComponent } from './builder/dashboardrunner/dashrunnerline/scatter-runner/scatter-runner.component';
import { TodoRunnerComponent } from './builder/dashboardrunner/dashrunnerline/todo-runner/todo-runner.component'; import { TodoRunnerComponent } from './builder/dashboardrunner/dashrunnerline/todo-runner/todo-runner.component';
// Import CompactFilterRunnerComponent
import { CompactFilterRunnerComponent } from './builder/dashboardrunner/dashrunnerline/compact-filter-runner/compact-filter-runner.component';
import { ApiregisteryComponent } from './fnd/apiregistery/apiregistery.component'; import { ApiregisteryComponent } from './fnd/apiregistery/apiregistery.component';
import { BulkimportComponent } from './datamanagement/bulkimport/bulkimport.component'; import { BulkimportComponent } from './datamanagement/bulkimport/bulkimport.component';
@@ -106,18 +134,34 @@ import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingrul
import { MappingruleallComponent } from './datamanagement/mappingrule/mappingruleall/mappingruleall.component'; import { MappingruleallComponent } from './datamanagement/mappingrule/mappingruleall/mappingruleall.component';
import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component'; import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component';
import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component'; import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component';
import { AllapiregisteryComponent } from './fnd/apiregistery/allapiregistery/allapiregistery.component';
import { AddapiregisteryComponent } from './fnd/apiregistery/addapiregistery/addapiregistery.component';
import { EditapiregisteryComponent } from './fnd/apiregistery/editapiregistery/editapiregistery.component';
import { ApiregisterylineComponent } from './fnd/apiregistery/Apiregisteryline/Apiregisteryline.component';
import { Customer_informationComponent } from './BuilderComponents/angulardatatype/Customer_information/Customer_information.component';
import { Deployment_typeComponent } from './BuilderComponents/angulardatatype/Deployment_type/Deployment_type.component';
import { ManufacturerComponent } from './BuilderComponents/angulardatatype/Manufacturer/Manufacturer.component';
import { Order_summaryComponent } from './BuilderComponents/angulardatatype/Order_summary/Order_summary.component';
import { ProductComponent } from './BuilderComponents/angulardatatype/Product/Product.component';
import { TypesComponent } from './BuilderComponents/angulardatatype/Types/Types.component';
import { Test2Component } from './BuilderComponents/testdata/Test2/Test2.component';
import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component'; import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component';
import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component'; import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component';
import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component'; import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component';
import { QueryComponent } from './superadmin/query/query.component';
import { QueryaddComponent } from './superadmin/queryadd/queryadd.component';
import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
import { FieldTypesModule } from '../../shared/components/field-types/field-types.module';
import { SharedModule } from '../../shared/shared.module';
import { Data_lakeComponent } from './builder/dashboardnew/Data_lake/Data_lake.component'; import { Data_lakeComponent } from './builder/dashboardnew/Data_lake/Data_lake.component';
import { CronJobBuilderComponent } from './builder/dashboardnew/Data_lake/cron-job-builder/cron-job-builder.component'; import { CronJobBuilderComponent } from './builder/dashboardnew/Data_lake/cron-job-builder/cron-job-builder.component';
import { SureconnectComponent } from './builder/dashboardnew/sureconnect/sureconnect.component'; import { SureconnectComponent } from './builder/dashboardnew/sureconnect/sureconnect.component';
import { EditsureconnectComponent } from './builder/dashboardnew/sureconnect/editsureconnect/editsureconnect.component'; import { EditsureconnectComponent } from './builder/dashboardnew/sureconnect/editsureconnect/editsureconnect.component';
import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.component'; import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.component';
// import { QueryComponent } from './superadmin/query/query.component'; // Import Shield Dashboard Module
// import { QueryaddComponent } from './superadmin/queryadd/queryadd.component'; import { ShieldDashboardModule } from './builder/dashboardnew/gadgets/shield-dashboard/shield-dashboard.module';
// import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -128,71 +172,58 @@ import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.c
UsermaintanceaddComponent, UsermaintanceeditComponent, UsermaintanceaddComponent, UsermaintanceeditComponent,
SubmenuComponent, ModulesComponent, SessionloggerComponent, SubmenuComponent, ModulesComponent, SessionloggerComponent,
DashboardnewComponent, EditformnewdashComponent, EditnewdashComponent, ScheduleComponent, DashboardnewComponent, EditformnewdashComponent, EditnewdashComponent, ScheduleComponent,
DoughnutChartComponent, LineChartComponent, RadarChartComponent, BarChartComponent, BubbleChartComponent, DynamicChartComponent, ScatterChartComponent, PolarChartComponent, PieChartComponent, FinancialChartComponent, ToDoChartComponent, GridViewComponent, CommonFilterComponent, ChartWrapperComponent, CompactFilterComponent, DoughnutChartComponent, LineChartComponent, RadarChartComponent, BarChartComponent, BubbleChartComponent, DynamicChartComponent, ScatterChartComponent, PolarChartComponent, PieChartComponent, FinancialChartComponent, ToDoChartComponent, GridViewComponent,
DashrunnerlineComponent, BarRunnerComponent, LineRunnerComponent, DoughnutRunnerComponent, GridRunnerComponent, PieRunnerComponent, PolarRunnerComponent, RadarRunnerComponent, ScatterRunnerComponent, TodoRunnerComponent, BubbleRunnerComponent, DashrunnerlineComponent, BarRunnerComponent, LineRunnerComponent, DoughnutRunnerComponent, GridRunnerComponent, PieRunnerComponent, PolarRunnerComponent, RadarRunnerComponent, ScatterRunnerComponent, TodoRunnerComponent, BubbleRunnerComponent,
// Add CompactFilterRunnerComponent to declarations
CompactFilterRunnerComponent,
ReportBuildComponent, ReportbuildeditComponent, ReportbuildqueryComponent, ReportBuild2Component, ReportBuild2editComponent, ReportBuildComponent, ReportbuildeditComponent, ReportbuildqueryComponent, ReportBuild2Component, ReportBuild2editComponent,
// QueryComponent, QueryaddComponent, QueryeditComponent, QueryComponent, QueryaddComponent, QueryeditComponent,
ExtensionComponent, ExtensionComponent,
AllextensionComponent, AllextensionComponent,
AddextensionComponent, EditextensionComponent, ApiregisteryComponent, AddextensionComponent, EditextensionComponent, ApiregisteryComponent, AllapiregisteryComponent, AddapiregisteryComponent, EditapiregisteryComponent,
DatamanagementComponent, DatamananementworkflowComponent, BulkimportComponent, BulkimportallComponent, BulkimportaddComponent, BulkimporteditComponent, BulkimportlineComponent, BulkimporteditlineComponent, MappingruleComponent,
MappingruleallComponent, MappingruleaddComponent, MappingruleeditComponent, ApiregisterylineComponent,
ThemeCustomizationComponent, DatamanagementComponent, DatamananementworkflowComponent, BulkimportComponent, BulkimportallComponent, BulkimportaddComponent, BulkimporteditComponent, BulkimportlineComponent, BulkimporteditlineComponent, MappingruleComponent, MappingruleallComponent,
MappingruleaddComponent,
MappingruleeditComponent, Stepper_workflowComponent, Customer_informationComponent,
Data_lakeComponent, Data_lakeComponent,
SureconnectComponent, SureconnectComponent,
EditsureconnectComponent, EditsureconnectComponent,
OauthComponent, OauthComponent,
CronJobBuilderComponent, CronJobBuilderComponent,
// FileUploadListComponent,
// buildercomponents // buildercomponents
ThemeCustomizationComponent,
Ad10Component,
Token_registeryComponent, Token_registeryComponent,
DefatestComponent,
Test2Component,
Order_summaryComponent,
TypesComponent,
ProductComponent,
ManufacturerComponent,
Deployment_typeComponent,
ChildformComponent,
DistrictComponent,
StateComponent,
CountryComponent,
Ad9Component,
Ad8Component,
Ad7Component,
Ad6Component,
Adv5Component,
Adv4Component,
SupportComponent,
Adv3Component,
Dv2Component,
Adv1Component,
Basicp3Component,
Basicp2Component,
Basicp1Component,
Stepper_workflowComponent,
], ],
imports: [ imports: [
QRCodeModule, QRCodeModule,
@@ -212,6 +243,9 @@ import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.c
NgChartsModule, NgChartsModule,
NgxChartsModule, NgxChartsModule,
DynamicModule, DynamicModule,
FieldTypesModule,
SharedModule,
ShieldDashboardModule,
], ],
providers: [ providers: [
CookieService, CookieService,

View File

@@ -0,0 +1,252 @@
import { Ad10Component } from './BuilderComponents/angulardatatype/Ad10/Ad10.component';
import { DefatestComponent } from './BuilderComponents/defu/Defatest/Defatest.component';
import { ChildformComponent } from './BuilderComponents/stpkg/Childform/Childform.component';
import { DistrictComponent } from './BuilderComponents/testdata/District/District.component';
import { StateComponent } from './BuilderComponents/testdata/State/State.component';
import { CountryComponent } from './BuilderComponents/testdata/Country/Country.component';
import { Ad9Component } from './BuilderComponents/angulardatatype/Ad9/Ad9.component';
import { Ad8Component } from './BuilderComponents/angulardatatype/Ad8/Ad8.component';
import { Ad7Component } from './BuilderComponents/angulardatatype/Ad7/Ad7.component';
import { Ad6Component } from './BuilderComponents/angulardatatype/Ad6/Ad6.component';
import { Adv5Component } from './BuilderComponents/angulardatatype/Adv5/Adv5.component';
import { Adv4Component } from './BuilderComponents/angulardatatype/Adv4/Adv4.component';
import { SupportComponent } from './BuilderComponents/angulardatatype/Support/Support.component';
import { Adv3Component } from './BuilderComponents/angulardatatype/Adv3/Adv3.component';
import { Dv2Component } from './BuilderComponents/angulardatatype/Dv2/Dv2.component';
import { Adv1Component } from './BuilderComponents/angulardatatype/Adv1/Adv1.component';
import { Basicp3Component } from './BuilderComponents/angulardatatype/Basicp3/Basicp3.component';
import { Basicp2Component } from './BuilderComponents/angulardatatype/Basicp2/Basicp2.component';
import { Basicp1Component } from './BuilderComponents/angulardatatype/Basicp1/Basicp1.component';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ClarityModule } from '@clr/angular';
import { MainPageComponent } from '../main/fnd/main-page/main-page.component';
import { MainRoutingModule } from './main-routing.module';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
// import { AboutComponent } from '../main/admin/about/about.component';
// import { LayoutComponent } from './layout/layout.component';
import { HelperModule } from 'src/app/pipes/helpers.module';
import { PasswordResetComponent } from '../main/admin/password-reset/password-reset.component';
import { UserComponent } from '../main/admin/user/user.component';
import { AllMenuGroupComponent } from '../main/admin/menu-group/all/all-menu-group.component';
import { EditMenuGroupComponent } from '../main/admin/menu-group/edit/edit-menu-group.component';
import { MenuGroupComponent } from '../main/admin/menu-group/menu-group.component';
import { ReadOnlyMenuGroupComponent } from '../main/admin/menu-group/read-only/readonly-menu-group.component';
import { AddMenurComponent } from '../main/admin/menu-register/add-menur/add-menur.component';
import { AllMenurComponent } from '../main/admin/menu-register/all-menur/all-menur.component';
import { EditMenurComponent } from '../main/admin/menu-register/edit-menur/edit-menur.component';
import { MenuRegisterComponent } from '../main/admin/menu-register/menu-register.component';
import { ReadonlyMenurComponent } from '../main/admin/menu-register/readonly-menur/readonly-menur.component';
import { ProfileSettingComponent } from '../main/admin/profile-setting/profile-setting.component';
import { UsermaintanceaddComponent } from '../main/admin/usermaintanceadd/usermaintanceadd.component';
import { UsermaintanceeditComponent } from '../main/admin/usermaintanceedit/usermaintanceedit.component';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { HttpClientModule } from '@angular/common/http';
import { CodemirrorModule } from "@ctrl/ngx-codemirror";
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { GridsterModule } from 'angular-gridster2';
import { DynamicModule } from 'ng-dynamic-component';
import { NgChartsModule } from 'ng2-charts';
import { CKEditorModule } from 'ng2-ckeditor';
import { UserRegistrationComponent } from '../main/admin/user-registration/user-registration.component';
import { QRCodeModule } from 'angularx-qrcode';
import { TagInputModule } from 'ngx-chips';
import { CookieService } from 'ngx-cookie-service';
import { ImageCropperModule } from 'ngx-image-cropper';
import { ModulesComponent } from './admin/modules/modules.component';
import { SessionloggerComponent } from './admin/sessionlogger/sessionlogger.component';
import { SubmenuComponent } from './admin/submenu/submenu.component';
import { WireframeService } from 'src/app/services/builder/wireframe.service';
import { ReportBuildComponent } from './builder/report-build/report-build.component';
import { ReportbuildeditComponent } from './builder/report-build/reportbuildedit/reportbuildedit.component';
import { ReportbuildqueryComponent } from './builder/report-build/reportbuildquery/reportbuildquery.component';
import { ReportBuild2Component } from './builder/report-build2/report-build2.component';
import { ReportBuild2editComponent } from './builder/report-build2/report-build2edit/report-build2edit.component';
import { ReportRunnerComponent } from './builder/report-runner/report-runner.component';
import { ReportrunnereditComponent } from './builder/report-runner/reportrunneredit/reportrunneredit.component';
import { Reportrunneredit2Component } from './builder/report-runner/reportrunneredit2/reportrunneredit2.component';
import { DashboardnewComponent } from './builder/dashboardnew/dashboardnew.component';
import { EditformnewdashComponent } from './builder/dashboardnew/editformnewdash/editformnewdash.component';
import { EditnewdashComponent } from './builder/dashboardnew/editnewdash/editnewdash.component';
import { BarChartComponent } from './builder/dashboardnew/gadgets/bar-chart/bar-chart.component';
import { BubbleChartComponent } from './builder/dashboardnew/gadgets/bubble-chart/bubble-chart.component';
import { DoughnutChartComponent } from './builder/dashboardnew/gadgets/doughnut-chart/doughnut-chart.component';
import { DynamicChartComponent } from './builder/dashboardnew/gadgets/dynamic-chart/dynamic-chart.component';
import { FinancialChartComponent } from './builder/dashboardnew/gadgets/financial-chart/financial-chart.component';
import { GridViewComponent } from './builder/dashboardnew/gadgets/grid-view/grid-view.component';
import { LineChartComponent } from './builder/dashboardnew/gadgets/line-chart/line-chart.component';
import { PieChartComponent } from './builder/dashboardnew/gadgets/pie-chart/pie-chart.component';
import { PolarChartComponent } from './builder/dashboardnew/gadgets/polar-chart/polar-chart.component';
import { RadarChartComponent } from './builder/dashboardnew/gadgets/radar-chart/radar-chart.component';
import { ScatterChartComponent } from './builder/dashboardnew/gadgets/scatter-chart/scatter-chart.component';
import { ToDoChartComponent } from './builder/dashboardnew/gadgets/to-do-chart/to-do-chart.component';
import { ScheduleComponent } from './builder/dashboardnew/schedule/schedule.component';
import { CommonFilterComponent } from './builder/dashboardnew/common-filter/common-filter.component';
import { ChartWrapperComponent } from './builder/dashboardnew/common-filter/chart-wrapper.component';
import { AddextensionComponent } from './fnd/extension/addextension/addextension.component';
import { AllextensionComponent } from './fnd/extension/allextension/allextension.component';
import { EditextensionComponent } from './fnd/extension/editextension/editextension.component';
import { ExtensionComponent } from './fnd/extension/extension.component';
import { BarRunnerComponent } from './builder/dashboardrunner/dashrunnerline/bar-runner/bar-runner.component';
import { BubbleRunnerComponent } from './builder/dashboardrunner/dashrunnerline/bubble-runner/bubble-runner.component';
import { DashrunnerlineComponent } from './builder/dashboardrunner/dashrunnerline/dashrunnerline.component';
import { DoughnutRunnerComponent } from './builder/dashboardrunner/dashrunnerline/doughnut-runner/doughnut-runner.component';
import { GridRunnerComponent } from './builder/dashboardrunner/dashrunnerline/grid-runner/grid-runner.component';
import { LineRunnerComponent } from './builder/dashboardrunner/dashrunnerline/line-runner/line-runner.component';
import { PieRunnerComponent } from './builder/dashboardrunner/dashrunnerline/pie-runner/pie-runner.component';
import { PolarRunnerComponent } from './builder/dashboardrunner/dashrunnerline/polar-runner/polar-runner.component';
import { RadarRunnerComponent } from './builder/dashboardrunner/dashrunnerline/radar-runner/radar-runner.component';
import { ScatterRunnerComponent } from './builder/dashboardrunner/dashrunnerline/scatter-runner/scatter-runner.component';
import { TodoRunnerComponent } from './builder/dashboardrunner/dashrunnerline/todo-runner/todo-runner.component';
import { ApiregisteryComponent } from './fnd/apiregistery/apiregistery.component';
import { BulkimportComponent } from './datamanagement/bulkimport/bulkimport.component';
import { BulkimportaddComponent } from './datamanagement/bulkimport/bulkimportadd/bulkimportadd.component';
import { BulkimportallComponent } from './datamanagement/bulkimport/bulkimportall/bulkimportall.component';
import { BulkimporteditComponent } from './datamanagement/bulkimport/bulkimportedit/bulkimportedit.component';
import { BulkimporteditlineComponent } from './datamanagement/bulkimport/bulkimporteditline/bulkimporteditline.component';
import { BulkimportlineComponent } from './datamanagement/bulkimport/bulkimportline/bulkimportline.component';
import { DatamanagementComponent } from './datamanagement/datamanagement/datamanagement.component';
import { DatamananementworkflowComponent } from './datamanagement/datamananementworkflow/datamananementworkflow.component';
import { MappingruleComponent } from './datamanagement/mappingrule/mappingrule.component';
import { MappingruleaddComponent } from './datamanagement/mappingrule/mappingruleadd/mappingruleadd.component';
import { MappingruleallComponent } from './datamanagement/mappingrule/mappingruleall/mappingruleall.component';
import { MappingruleeditComponent } from './datamanagement/mappingrule/mappingruleedit/mappingruleedit.component';
import { Stepper_workflowComponent } from './BuilderComponents/stepperworkflow/Stepper_workflow/Stepper_workflow.component';
import { AllapiregisteryComponent } from './fnd/apiregistery/allapiregistery/allapiregistery.component';
import { AddapiregisteryComponent } from './fnd/apiregistery/addapiregistery/addapiregistery.component';
import { EditapiregisteryComponent } from './fnd/apiregistery/editapiregistery/editapiregistery.component';
import { ApiregisterylineComponent } from './fnd/apiregistery/Apiregisteryline/Apiregisteryline.component';
import { Customer_informationComponent } from './BuilderComponents/angulardatatype/Customer_information/Customer_information.component';
import { Deployment_typeComponent } from './BuilderComponents/angulardatatype/Deployment_type/Deployment_type.component';
import { ManufacturerComponent } from './BuilderComponents/angulardatatype/Manufacturer/Manufacturer.component';
import { Order_summaryComponent } from './BuilderComponents/angulardatatype/Order_summary/Order_summary.component';
import { ProductComponent } from './BuilderComponents/angulardatatype/Product/Product.component';
import { TypesComponent } from './BuilderComponents/angulardatatype/Types/Types.component';
import { Test2Component } from './BuilderComponents/testdata/Test2/Test2.component';
import { Token_registeryComponent } from './fnd/Token_registery/Token_registery.component';
import { MyworkspaceComponent } from './admin/myworkspace/myworkspace.component';
import { ThemeCustomizationComponent } from './theme-customization/theme-customization.component';
// import { QueryComponent } from './superadmin/query/query.component';
// import { QueryaddComponent } from './superadmin/queryadd/queryadd.component';
// import { QueryeditComponent } from './superadmin/queryedit/queryedit.component';
import { FieldTypesModule } from '../../shared/components/field-types/field-types.module';
import { SharedModule } from '../../shared/shared.module';
import { Data_lakeComponent } from './builder/dashboardnew/Data_lake/Data_lake.component';
import { CronJobBuilderComponent } from './builder/dashboardnew/Data_lake/cron-job-builder/cron-job-builder.component';
import { SureconnectComponent } from './builder/dashboardnew/sureconnect/sureconnect.component';
import { EditsureconnectComponent } from './builder/dashboardnew/sureconnect/editsureconnect/editsureconnect.component';
import { OauthComponent } from './builder/dashboardnew/sureconnect/oauth/oauth.component';
// Import Shield Dashboard Module
import { ShieldDashboardModule } from './builder/dashboardnew/gadgets/shield-dashboard/shield-dashboard.module';
@NgModule({
declarations: [
MainPageComponent, PageNotFoundComponent, UserComponent, PasswordResetComponent,
MyworkspaceComponent,
ReportRunnerComponent, ReportrunnereditComponent, Reportrunneredit2Component, MenuGroupComponent, AllMenuGroupComponent, EditMenuGroupComponent, ReadOnlyMenuGroupComponent, UserRegistrationComponent,
MenuRegisterComponent, AddMenurComponent, EditMenurComponent, AllMenurComponent, ReadonlyMenurComponent, ProfileSettingComponent,
UsermaintanceaddComponent, UsermaintanceeditComponent,
SubmenuComponent, ModulesComponent, SessionloggerComponent,
DashboardnewComponent, EditformnewdashComponent, EditnewdashComponent, ScheduleComponent,
CommonFilterComponent, ChartWrapperComponent, DoughnutChartComponent, LineChartComponent, RadarChartComponent, BarChartComponent, BubbleChartComponent, DynamicChartComponent, ScatterChartComponent, PolarChartComponent, PieChartComponent, FinancialChartComponent, ToDoChartComponent, GridViewComponent,
DashrunnerlineComponent, BarRunnerComponent, LineRunnerComponent, DoughnutRunnerComponent, GridRunnerComponent, PieRunnerComponent, PolarRunnerComponent, RadarRunnerComponent, ScatterRunnerComponent, TodoRunnerComponent, BubbleRunnerComponent,
ReportBuildComponent, ReportbuildeditComponent, ReportbuildqueryComponent, ReportBuild2Component, ReportBuild2editComponent,
// QueryComponent, QueryaddComponent, QueryeditComponent,
ExtensionComponent,
AllextensionComponent,
AddextensionComponent, EditextensionComponent, ApiregisteryComponent, AllapiregisteryComponent, AddapiregisteryComponent, EditapiregisteryComponent,
ApiregisterylineComponent,
DatamanagementComponent, DatamananementworkflowComponent, BulkimportComponent, BulkimportallComponent, BulkimportaddComponent, BulkimporteditComponent, BulkimportlineComponent, BulkimporteditlineComponent, MappingruleComponent, MappingruleallComponent,
MappingruleaddComponent,
MappingruleeditComponent, Stepper_workflowComponent, Customer_informationComponent,
Data_lakeComponent,
SureconnectComponent,
EditsureconnectComponent,
OauthComponent,
CronJobBuilderComponent,
// FileUploadListComponent,
// buildercomponents
ThemeCustomizationComponent,
Ad10Component,
Token_registeryComponent,
DefatestComponent,
Test2Component,
Order_summaryComponent,
TypesComponent,
ProductComponent,
ManufacturerComponent,
Deployment_typeComponent,
ChildformComponent,
DistrictComponent,
StateComponent,
CountryComponent,
Ad9Component,
Ad8Component,
Ad7Component,
Ad6Component,
Adv5Component,
Adv4Component,
SupportComponent,
Adv3Component,
Dv2Component,
Adv1Component,
Basicp3Component,
Basicp2Component,
Basicp1Component,
],
imports: [
QRCodeModule,
CommonModule,
FormsModule,
ReactiveFormsModule,
ClarityModule,
HelperModule,
MainRoutingModule,
DragDropModule,
HttpClientModule,
ImageCropperModule,
TagInputModule,
CodemirrorModule,
CKEditorModule,
GridsterModule,
NgChartsModule,
NgxChartsModule,
DynamicModule,
FieldTypesModule,
SharedModule,
ShieldDashboardModule,
],
providers: [
CookieService,
WireframeService,
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class MainModule { }

View File

@@ -69,4 +69,13 @@ export class AlertsService {
} }
return this.apiRequest.get(apiUrl); return this.apiRequest.get(apiUrl);
} }
// Get values for a specific key from API
public getValuesFromUrl(url: string, sureId: number | undefined, key: string): Observable<any> {
let apiUrl = `chart/getValue?apiUrl=${url}&key=${key}`;
if (sureId) {
apiUrl += `&sureId=${sureId}`;
}
return this.apiRequest.get(apiUrl);
}
} }