builder
This commit is contained in:
parent
cdcf1e07c7
commit
cdd752469c
@ -70,6 +70,41 @@
|
|||||||
min-height: 24px;
|
min-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.multiselect-container {
|
||||||
|
max-height: 150px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 5px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-label {
|
||||||
|
font-size: 12px;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-checkbox {
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-label {
|
.toggle-label {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@ -38,19 +38,6 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Subscribe to filter definitions to get available filters
|
|
||||||
this.filterService.filters$.subscribe(filters => {
|
|
||||||
this.availableFilters = filters;
|
|
||||||
this.updateSelectedFilter();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Subscribe to filter state changes
|
|
||||||
this.filterService.filterState$.subscribe(state => {
|
|
||||||
if (this.selectedFilter && state.hasOwnProperty(this.selectedFilter.id)) {
|
|
||||||
this.filterValue = state[this.selectedFilter.id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize configuration from inputs
|
// Initialize configuration from inputs
|
||||||
this.configFilterKey = this.filterKey;
|
this.configFilterKey = this.filterKey;
|
||||||
this.configFilterType = this.filterType;
|
this.configFilterType = this.filterType;
|
||||||
@ -70,26 +57,53 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
|
|
||||||
// Register this filter with the filter service
|
// Register this filter with the filter service
|
||||||
this.registerFilter();
|
this.registerFilter();
|
||||||
|
|
||||||
|
// Subscribe to filter definitions to get available filters
|
||||||
|
this.filterService.filters$.subscribe(filters => {
|
||||||
|
this.availableFilters = filters;
|
||||||
|
this.updateSelectedFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Subscribe to filter state changes
|
||||||
|
this.filterService.filterState$.subscribe(state => {
|
||||||
|
if (this.selectedFilter && state.hasOwnProperty(this.selectedFilter.id)) {
|
||||||
|
this.filterValue = state[this.selectedFilter.id];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
// 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
|
||||||
|
if ((this.filterType === 'dropdown' || this.filterType === 'multiselect') && this.filterKey) {
|
||||||
|
this.loadAvailableValues(this.filterKey);
|
||||||
|
}
|
||||||
this.registerFilter();
|
this.registerFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle API URL changes
|
||||||
|
if (changes.apiUrl && !changes.apiUrl.firstChange) {
|
||||||
|
if (this.apiUrl) {
|
||||||
|
this.loadAvailableKeys();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register this filter with the filter service
|
// Register this filter with the filter service
|
||||||
registerFilter(): void {
|
registerFilter(): void {
|
||||||
if (this.filterKey) {
|
if (this.filterKey) {
|
||||||
|
// Get current filter values from the service
|
||||||
|
const currentFilterValues = this.filterService.getFilterValues();
|
||||||
|
|
||||||
// Create a filter definition for this compact filter
|
// Create a filter definition for this compact filter
|
||||||
const filterDef: Filter = {
|
const filterDef: Filter = {
|
||||||
id: `compact-filter-${this.filterKey}`,
|
id: `${this.filterKey}`,
|
||||||
field: this.filterKey,
|
field: this.filterKey,
|
||||||
label: this.filterLabel || this.filterKey,
|
label: this.filterLabel || this.filterKey,
|
||||||
type: this.filterType as any,
|
type: this.filterType as any,
|
||||||
options: this.filterOptions,
|
options: this.filterOptions,
|
||||||
value: this.filterValue
|
value: this.filterValue // Use the current filter value
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current filters
|
// Get current filters
|
||||||
@ -99,9 +113,32 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
const existingFilterIndex = currentFilters.findIndex(f => f.id === filterDef.id);
|
const existingFilterIndex = currentFilters.findIndex(f => f.id === filterDef.id);
|
||||||
|
|
||||||
if (existingFilterIndex >= 0) {
|
if (existingFilterIndex >= 0) {
|
||||||
|
// Preserve the existing filter configuration
|
||||||
|
const existingFilter = currentFilters[existingFilterIndex];
|
||||||
|
|
||||||
|
// Preserve the existing filter value if it exists in the service
|
||||||
|
if (currentFilterValues.hasOwnProperty(existingFilter.id)) {
|
||||||
|
filterDef.value = currentFilterValues[existingFilter.id];
|
||||||
|
this.filterValue = filterDef.value; // Update local value
|
||||||
|
} else if (existingFilter.value !== undefined) {
|
||||||
|
// Fallback to existing filter's value if no service value
|
||||||
|
filterDef.value = existingFilter.value;
|
||||||
|
this.filterValue = filterDef.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve other configuration properties
|
||||||
|
filterDef.label = existingFilter.label;
|
||||||
|
filterDef.options = existingFilter.options || this.filterOptions;
|
||||||
|
|
||||||
// Update existing filter
|
// Update existing filter
|
||||||
currentFilters[existingFilterIndex] = filterDef;
|
currentFilters[existingFilterIndex] = filterDef;
|
||||||
} else {
|
} else {
|
||||||
|
// For new filters, check if there's already a value in the service
|
||||||
|
if (currentFilterValues.hasOwnProperty(filterDef.id)) {
|
||||||
|
filterDef.value = currentFilterValues[filterDef.id];
|
||||||
|
this.filterValue = filterDef.value; // Update local value
|
||||||
|
}
|
||||||
|
|
||||||
// Add new filter
|
// Add new filter
|
||||||
currentFilters.push(filterDef);
|
currentFilters.push(filterDef);
|
||||||
}
|
}
|
||||||
@ -118,9 +155,24 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
if (this.filterKey && this.availableFilters.length > 0) {
|
if (this.filterKey && this.availableFilters.length > 0) {
|
||||||
this.selectedFilter = this.availableFilters.find(f => f.field === this.filterKey) || null;
|
this.selectedFilter = this.availableFilters.find(f => f.field === this.filterKey) || null;
|
||||||
if (this.selectedFilter) {
|
if (this.selectedFilter) {
|
||||||
// Get current value for this filter
|
// Get current value for this filter from the service
|
||||||
const currentState = this.filterService.getFilterValues();
|
const currentState = this.filterService.getFilterValues();
|
||||||
this.filterValue = currentState[this.selectedFilter.id] || '';
|
const filterValue = currentState[this.selectedFilter.id];
|
||||||
|
if (filterValue !== undefined) {
|
||||||
|
this.filterValue = filterValue;
|
||||||
|
} else if (this.selectedFilter.value !== undefined) {
|
||||||
|
// Use the filter's default value if no service value
|
||||||
|
this.filterValue = this.selectedFilter.value;
|
||||||
|
} else {
|
||||||
|
// Use the current filter value as fallback
|
||||||
|
this.filterValue = this.filterValue || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also update configuration properties from the selected filter
|
||||||
|
this.configFilterKey = this.selectedFilter.field;
|
||||||
|
this.configFilterType = this.selectedFilter.type;
|
||||||
|
this.configFilterLabel = this.selectedFilter.label;
|
||||||
|
this.configFilterOptions = (this.selectedFilter.options || []).join(',');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +182,14 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
this.filterValue = value;
|
this.filterValue = value;
|
||||||
this.filterService.updateFilterValue(this.selectedFilter.id, value);
|
this.filterService.updateFilterValue(this.selectedFilter.id, value);
|
||||||
this.filterChange.emit({ filterId: this.selectedFilter.id, value: value });
|
this.filterChange.emit({ filterId: this.selectedFilter.id, value: value });
|
||||||
|
|
||||||
|
// Update the filter definition in the service to reflect the new value
|
||||||
|
const currentFilters = this.filterService.getFilters();
|
||||||
|
const filterIndex = currentFilters.findIndex(f => f.id === this.selectedFilter.id);
|
||||||
|
if (filterIndex >= 0) {
|
||||||
|
currentFilters[filterIndex].value = value;
|
||||||
|
this.filterService.setFilters(currentFilters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,11 +239,19 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
toggleConfigMode(): void {
|
toggleConfigMode(): void {
|
||||||
this.isConfigMode = !this.isConfigMode;
|
this.isConfigMode = !this.isConfigMode;
|
||||||
if (this.isConfigMode) {
|
if (this.isConfigMode) {
|
||||||
// Initialize config values
|
// Initialize config values from current filter if available
|
||||||
|
if (this.selectedFilter) {
|
||||||
|
this.configFilterKey = this.selectedFilter.field;
|
||||||
|
this.configFilterType = this.selectedFilter.type;
|
||||||
|
this.configFilterLabel = this.selectedFilter.label;
|
||||||
|
this.configFilterOptions = (this.selectedFilter.options || []).join(',');
|
||||||
|
} else {
|
||||||
|
// Fallback to current properties
|
||||||
this.configFilterKey = this.filterKey;
|
this.configFilterKey = this.filterKey;
|
||||||
this.configFilterType = this.filterType;
|
this.configFilterType = this.filterType;
|
||||||
this.configFilterLabel = this.filterLabel;
|
this.configFilterLabel = this.filterLabel;
|
||||||
this.configFilterOptions = this.filterOptions.join(',');
|
this.configFilterOptions = this.filterOptions.join(',');
|
||||||
|
}
|
||||||
this.configApiUrl = this.apiUrl;
|
this.configApiUrl = this.apiUrl;
|
||||||
this.configConnectionId = this.connectionId;
|
this.configConnectionId = this.connectionId;
|
||||||
}
|
}
|
||||||
@ -216,8 +284,8 @@ export class CompactFilterComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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.filterType === 'dropdown' || this.filterType === 'multiselect') && this.filterKey) {
|
if ((this.configFilterType === 'dropdown' || this.configFilterType === 'multiselect') && this.configFilterKey) {
|
||||||
this.loadAvailableValues(this.filterKey);
|
this.loadAvailableValues(this.configFilterKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the updated filter with the filter service
|
// Register the updated filter with the filter service
|
||||||
|
|||||||
@ -550,6 +550,95 @@
|
|||||||
<input id="chartparameter" type="text" formControlName="chartparameter" class="clr-input" [(ngModel)]="gadgetsEditdata.chartparameter">
|
<input id="chartparameter" type="text" formControlName="chartparameter" class="clr-input" [(ngModel)]="gadgetsEditdata.chartparameter">
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
|
<!-- Compact Filter Configuration (shown only for Compact Filter components) -->
|
||||||
|
<div class="clr-row" *ngIf="gadgetsEditdata?.fieldName === 'Compact Filter'" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h4>Compact Filter Configuration</h4>
|
||||||
|
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="compactFilterConnection">Connection</label>
|
||||||
|
<select id="compactFilterConnection" class="clr-select" [(ngModel)]="gadgetsEditdata.connection"
|
||||||
|
(ngModelChange)="onCompactFilterConnectionChange($event)" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Connection</option>
|
||||||
|
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
|
||||||
|
{{conn.connection_name || conn.id}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<div class="clr-subtext">Select a connection for this compact filter</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 10px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="compactFilterApiUrl">API URL</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="compactFilterApiUrl" class="clr-input" [(ngModel)]="gadgetsEditdata.table"
|
||||||
|
(ngModelChange)="onCompactFilterApiUrlChange($event)" [ngModelOptions]="{standalone: true}"
|
||||||
|
placeholder="Enter API URL">
|
||||||
|
<span>
|
||||||
|
<button class="btn btn-icon btn-primary" style="margin: 0px;"
|
||||||
|
(click)="loadAvailableKeys(gadgetsEditdata.table, gadgetsEditdata.connection)"
|
||||||
|
[disabled]="!gadgetsEditdata.table">
|
||||||
|
<clr-icon shape="redo"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="clr-subtext">Enter the API URL to fetch data for this filter</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 10px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="filterKey">Filter Key</label>
|
||||||
|
<select id="filterKey" class="clr-select" [(ngModel)]="gadgetsEditdata.filterKey"
|
||||||
|
(ngModelChange)="onFilterKeyChange($event)" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Filter Key</option>
|
||||||
|
<option *ngFor="let key of availableKeys" [value]="key">{{ key }}</option>
|
||||||
|
</select>
|
||||||
|
<div class="clr-subtext">Select the field name to filter on</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 10px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="filterType">Filter Type</label>
|
||||||
|
<select id="filterType" class="clr-select" [(ngModel)]="gadgetsEditdata.filterType"
|
||||||
|
(ngModelChange)="onFilterTypeChange($event)" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="text">Text</option>
|
||||||
|
<option value="dropdown">Dropdown</option>
|
||||||
|
<option value="multiselect">Multi-Select</option>
|
||||||
|
<option value="date-range">Date Range</option>
|
||||||
|
<option value="toggle">Toggle</option>
|
||||||
|
</select>
|
||||||
|
<div class="clr-subtext">Select the type of filter control to display</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 10px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="filterLabel">Filter Label (Optional)</label>
|
||||||
|
<input type="text" id="filterLabel" class="clr-input" [(ngModel)]="gadgetsEditdata.filterLabel"
|
||||||
|
[ngModelOptions]="{standalone: true}" placeholder="Enter filter label">
|
||||||
|
<div class="clr-subtext">Label to display for this filter in the UI (if not provided, filter key will be used)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 10px;" *ngIf="gadgetsEditdata.filterType === 'dropdown' || gadgetsEditdata.filterType === 'multiselect'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="filterOptions">Filter Options (comma separated)</label>
|
||||||
|
<input type="text" id="filterOptions" class="clr-input" [(ngModel)]="filterOptionsString"
|
||||||
|
[ngModelOptions]="{standalone: true}" placeholder="Option1,Option2,Option3">
|
||||||
|
<div class="clr-subtext">Comma-separated list of options for dropdown/multiselect filters</div>
|
||||||
|
<div class="clr-subtext" *ngIf="gadgetsEditdata.filterKey">
|
||||||
|
<strong>Available values for "{{ gadgetsEditdata.filterKey }}":</strong> {{ filterOptionsString }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-outline" (click)="modeledit = false">Cancel</button>
|
<button type="button" class="btn btn-outline" (click)="modeledit = false">Cancel</button>
|
||||||
<button type="button" class="btn btn-primary" (click)="applyChanges(modelid)">Apply</button>
|
<button type="button" class="btn btn-primary" (click)="applyChanges(modelid)">Apply</button>
|
||||||
|
|||||||
@ -48,6 +48,12 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
public entryForm: FormGroup;
|
public entryForm: FormGroup;
|
||||||
public commonFilterForm: FormGroup; // Add common filter form
|
public commonFilterForm: FormGroup; // Add common filter form
|
||||||
|
|
||||||
|
// Add filterOptionsString property for compact filter
|
||||||
|
filterOptionsString: string = '';
|
||||||
|
|
||||||
|
// Add availableKeys property for compact filter
|
||||||
|
availableKeys: string[] = [];
|
||||||
|
|
||||||
WidgetsMock: WidgetModel[] = [
|
WidgetsMock: WidgetModel[] = [
|
||||||
{
|
{
|
||||||
name: 'Common Filter',
|
name: 'Common Filter',
|
||||||
@ -360,6 +366,16 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
dashboard.component = component.componentInstance;
|
dashboard.component = component.componentInstance;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ensure compact filter configuration properties are properly initialized
|
||||||
|
if (dashboard.component === 'Compact Filter' || dashboard.name === 'Compact Filter') {
|
||||||
|
// Make sure all compact filter properties exist
|
||||||
|
if (dashboard.filterKey === undefined) dashboard.filterKey = '';
|
||||||
|
if (dashboard.filterType === undefined) dashboard.filterType = 'text';
|
||||||
|
if (dashboard.filterLabel === undefined) dashboard.filterLabel = '';
|
||||||
|
if (dashboard.filterOptions === undefined) dashboard.filterOptions = [];
|
||||||
|
// table and connection properties should already exist for all components
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -374,6 +390,16 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
dashboard.component = component.name;
|
dashboard.component = component.name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Ensure compact filter configuration properties are preserved
|
||||||
|
if (dashboard.name === 'Compact Filter') {
|
||||||
|
// Make sure all compact filter properties exist
|
||||||
|
if (dashboard.filterKey === undefined) dashboard.filterKey = '';
|
||||||
|
if (dashboard.filterType === undefined) dashboard.filterType = 'text';
|
||||||
|
if (dashboard.filterLabel === undefined) dashboard.filterLabel = '';
|
||||||
|
if (dashboard.filterOptions === undefined) dashboard.filterOptions = [];
|
||||||
|
// table and connection properties should already exist for all components
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 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)
|
||||||
@ -601,6 +627,18 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
if (item['filterOptions'] === undefined) {
|
if (item['filterOptions'] === undefined) {
|
||||||
this.gadgetsEditdata['filterOptions'] = [];
|
this.gadgetsEditdata['filterOptions'] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize filterOptionsString for compact filter
|
||||||
|
if (item.name === 'Compact Filter') {
|
||||||
|
this.filterOptionsString = this.gadgetsEditdata['filterOptions'].join(', ');
|
||||||
|
// Load available keys when editing a compact filter
|
||||||
|
if (this.gadgetsEditdata['table']) {
|
||||||
|
this.loadAvailableKeys(this.gadgetsEditdata['table'], this.gadgetsEditdata['connection']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.filterOptionsString = '';
|
||||||
|
}
|
||||||
|
|
||||||
this.getStores();
|
this.getStores();
|
||||||
|
|
||||||
// Set default connection if none is set and we have connections
|
// Set default connection if none is set and we have connections
|
||||||
@ -699,6 +737,9 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
|
|
||||||
//https://www.w3schools.com/js/tryit.asp?filename=tryjson_stringify_function_tostring
|
//https://www.w3schools.com/js/tryit.asp?filename=tryjson_stringify_function_tostring
|
||||||
|
|
||||||
|
// First serialize the dashboard collection to ensure component names are properly set
|
||||||
|
this.serialize(this.dashboardCollection.dashboard);
|
||||||
|
|
||||||
let cmp = this.dashboardCollection.dashboard.forEach(dashboard => {
|
let cmp = this.dashboardCollection.dashboard.forEach(dashboard => {
|
||||||
this.componentCollection.forEach(component => {
|
this.componentCollection.forEach(component => {
|
||||||
if (dashboard.name === component.name) {
|
if (dashboard.name === component.name) {
|
||||||
@ -719,8 +760,6 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
//console.log(merged);
|
//console.log(merged);
|
||||||
console.log("temp data", typeof tmp);
|
console.log("temp data", typeof tmp);
|
||||||
console.log(tmp);
|
console.log(tmp);
|
||||||
let parsed = JSON.parse(tmp);
|
|
||||||
this.serialize(parsed.dashboard);
|
|
||||||
this.dashbord1_Line.model = tmp;
|
this.dashbord1_Line.model = tmp;
|
||||||
|
|
||||||
// let obj = this.dashboardCollection;
|
// let obj = this.dashboardCollection;
|
||||||
@ -777,12 +816,19 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
xyz.commonFilterEnabled = this.gadgetsEditdata.commonFilterEnabled; // Add common filter property
|
xyz.commonFilterEnabled = this.gadgetsEditdata.commonFilterEnabled; // Add common filter property
|
||||||
|
|
||||||
// For compact filter, preserve filter configuration properties
|
// For compact filter, preserve filter configuration properties
|
||||||
if (item.component && item.component.name === 'CompactFilterComponent') {
|
if (item.name === 'Compact Filter') {
|
||||||
xyz.filterKey = this.gadgetsEditdata.filterKey || '';
|
xyz.filterKey = this.gadgetsEditdata.filterKey || '';
|
||||||
xyz.filterType = this.gadgetsEditdata.filterType || 'text';
|
xyz.filterType = this.gadgetsEditdata.filterType || 'text';
|
||||||
xyz.filterLabel = this.gadgetsEditdata.filterLabel || '';
|
xyz.filterLabel = this.gadgetsEditdata.filterLabel || '';
|
||||||
|
// Convert filterOptionsString to array
|
||||||
|
if (this.gadgetsEditdata.fieldName === 'Compact Filter') {
|
||||||
|
xyz.filterOptions = this.filterOptionsString.split(',').map(opt => opt.trim()).filter(opt => opt);
|
||||||
|
} else {
|
||||||
xyz.filterOptions = this.gadgetsEditdata.filterOptions || [];
|
xyz.filterOptions = this.gadgetsEditdata.filterOptions || [];
|
||||||
}
|
}
|
||||||
|
xyz.table = this.gadgetsEditdata.table || '';
|
||||||
|
xyz.connection = this.gadgetsEditdata.connection || undefined;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(xyz);
|
console.log(xyz);
|
||||||
return xyz;
|
return xyz;
|
||||||
@ -818,8 +864,58 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
* This prevents errors when trying to set properties that don't exist on the components
|
* This prevents errors when trying to set properties that don't exist on the components
|
||||||
*/
|
*/
|
||||||
getChartInputs(item: any): any {
|
getChartInputs(item: any): any {
|
||||||
// Only pass properties that are relevant to chart components
|
// For CompactFilterComponent, pass only filter configuration properties
|
||||||
const chartInputs = {
|
if (item.name === 'Compact Filter') {
|
||||||
|
const filterInputs = {
|
||||||
|
filterKey: item['filterKey'] || '',
|
||||||
|
filterType: item['filterType'] || 'text',
|
||||||
|
filterLabel: item['filterLabel'] || '',
|
||||||
|
filterOptions: item['filterOptions'] || [],
|
||||||
|
apiUrl: item['table'] || '', // Use table as API URL
|
||||||
|
connectionId: item['connection'] ? parseInt(item['connection'], 10) : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
// Preserve configuration in the item itself
|
||||||
|
item['filterKey'] = filterInputs['filterKey'];
|
||||||
|
item['filterType'] = filterInputs['filterType'];
|
||||||
|
item['filterLabel'] = filterInputs['filterLabel'];
|
||||||
|
item['filterOptions'] = filterInputs['filterOptions'];
|
||||||
|
item['table'] = filterInputs['apiUrl'];
|
||||||
|
item['connection'] = item['connection'];
|
||||||
|
|
||||||
|
// Remove undefined properties to avoid passing unnecessary data
|
||||||
|
Object.keys(filterInputs).forEach(key => {
|
||||||
|
if (filterInputs[key] === undefined) {
|
||||||
|
delete filterInputs[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return filterInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For CommonFilterComponent, pass only filter-related properties
|
||||||
|
if (item.component && item.component.name === 'CommonFilterComponent') {
|
||||||
|
const commonFilterInputs = {
|
||||||
|
baseFilters: item['baseFilters'] || [],
|
||||||
|
drilldownFilters: item['drilldownFilters'] || [],
|
||||||
|
drilldownLayers: item['drilldownLayers'] || [],
|
||||||
|
fieldName: item['name'] || '',
|
||||||
|
connection: item['connection'] || undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove undefined properties to avoid passing unnecessary data
|
||||||
|
Object.keys(commonFilterInputs).forEach(key => {
|
||||||
|
if (commonFilterInputs[key] === undefined) {
|
||||||
|
delete commonFilterInputs[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return commonFilterInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For GridViewComponent, pass chart properties with drilldown support
|
||||||
|
if (item.component && item.component.name === 'GridViewComponent') {
|
||||||
|
const gridInputs = {
|
||||||
xAxis: item.xAxis,
|
xAxis: item.xAxis,
|
||||||
yAxis: item.yAxis,
|
yAxis: item.yAxis,
|
||||||
table: item.table,
|
table: item.table,
|
||||||
@ -848,24 +944,45 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
drilldownLayers: item['drilldownLayers'] || []
|
drilldownLayers: item['drilldownLayers'] || []
|
||||||
};
|
};
|
||||||
|
|
||||||
// For CommonFilterComponent, also pass baseFilters, drilldownFilters, drilldownLayers, fieldName, and connection
|
// Remove undefined properties to avoid passing unnecessary data
|
||||||
if (item.component && item.component.name === 'CommonFilterComponent') {
|
Object.keys(gridInputs).forEach(key => {
|
||||||
chartInputs['baseFilters'] = item['baseFilters'] || [];
|
if (gridInputs[key] === undefined) {
|
||||||
chartInputs['drilldownFilters'] = item['drilldownFilters'] || [];
|
delete gridInputs[key];
|
||||||
chartInputs['drilldownLayers'] = item['drilldownLayers'] || [];
|
}
|
||||||
chartInputs['fieldName'] = item['name'] || '';
|
});
|
||||||
chartInputs['connection'] = item['connection'] || undefined;
|
|
||||||
|
return gridInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For CompactFilterComponent, pass filter configuration properties
|
// For all other chart components, pass chart-specific properties
|
||||||
if (item.component && item.component.name === 'CompactFilterComponent') {
|
const chartInputs = {
|
||||||
chartInputs['filterKey'] = item['filterKey'] || '';
|
xAxis: item.xAxis,
|
||||||
chartInputs['filterType'] = item['filterType'] || 'text';
|
yAxis: item.yAxis,
|
||||||
chartInputs['filterLabel'] = item['filterLabel'] || '';
|
table: item.table,
|
||||||
chartInputs['filterOptions'] = item['filterOptions'] || [];
|
datastore: item.datastore,
|
||||||
chartInputs['apiUrl'] = item['table'] || ''; // Use table as API URL
|
charttitle: item.charttitle,
|
||||||
chartInputs['connectionId'] = item['connection'] ? parseInt(item['connection'], 10) : undefined;
|
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
|
// Remove undefined properties to avoid passing unnecessary data
|
||||||
Object.keys(chartInputs).forEach(key => {
|
Object.keys(chartInputs).forEach(key => {
|
||||||
@ -922,13 +1039,24 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
updatedItem.commonFilterEnabledDrilldown = this.gadgetsEditdata.commonFilterEnabledDrilldown; // Add drilldown common filter property
|
updatedItem.commonFilterEnabledDrilldown = this.gadgetsEditdata.commonFilterEnabledDrilldown; // Add drilldown common filter property
|
||||||
|
|
||||||
// For compact filter, preserve filter configuration properties
|
// For compact filter, preserve filter configuration properties
|
||||||
if (item.component && item.component.name === 'CompactFilterComponent') {
|
if (item.name === 'Compact Filter') {
|
||||||
updatedItem.filterKey = this.gadgetsEditdata.filterKey || '';
|
updatedItem.filterKey = this.gadgetsEditdata.filterKey || '';
|
||||||
updatedItem.filterType = this.gadgetsEditdata.filterType || 'text';
|
updatedItem.filterType = this.gadgetsEditdata.filterType || 'text';
|
||||||
updatedItem.filterLabel = this.gadgetsEditdata.filterLabel || '';
|
updatedItem.filterLabel = this.gadgetsEditdata.filterLabel || '';
|
||||||
|
// Convert filterOptionsString to array
|
||||||
|
if (this.gadgetsEditdata.fieldName === 'Compact Filter') {
|
||||||
|
updatedItem.filterOptions = this.filterOptionsString.split(',').map(opt => opt.trim()).filter(opt => opt);
|
||||||
|
} else {
|
||||||
updatedItem.filterOptions = this.gadgetsEditdata.filterOptions || [];
|
updatedItem.filterOptions = this.gadgetsEditdata.filterOptions || [];
|
||||||
|
}
|
||||||
updatedItem.table = this.gadgetsEditdata.table || ''; // API URL
|
updatedItem.table = this.gadgetsEditdata.table || ''; // API URL
|
||||||
updatedItem.connection = this.gadgetsEditdata.connection || undefined; // Connection ID
|
updatedItem.connection = this.gadgetsEditdata.connection || undefined; // Connection ID
|
||||||
|
|
||||||
|
// Also preserve these properties in gadgetsEditdata for consistency
|
||||||
|
this.gadgetsEditdata.filterKey = updatedItem.filterKey;
|
||||||
|
this.gadgetsEditdata.filterType = updatedItem.filterType;
|
||||||
|
this.gadgetsEditdata.filterLabel = updatedItem.filterLabel;
|
||||||
|
this.gadgetsEditdata.filterOptions = updatedItem.filterOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Updated item:', updatedItem);
|
console.log('Updated item:', updatedItem);
|
||||||
@ -1356,4 +1484,80 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
// This would require the chart component to have a public resize method
|
// This would require the chart component to have a public resize method
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add method to load available keys for compact filter
|
||||||
|
loadAvailableKeys(apiUrl: string, connectionId: string | undefined) {
|
||||||
|
if (apiUrl) {
|
||||||
|
const connectionIdNum = connectionId ? parseInt(connectionId, 10) : undefined;
|
||||||
|
this.alertService.getColumnfromurl(apiUrl, connectionIdNum).subscribe(
|
||||||
|
(keys: string[]) => {
|
||||||
|
this.availableKeys = keys;
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('Error loading available keys:', error);
|
||||||
|
this.availableKeys = [];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add method to load available values for a specific key
|
||||||
|
loadAvailableValues(key: string) {
|
||||||
|
if (key && this.gadgetsEditdata['table']) {
|
||||||
|
const connectionIdNum = this.gadgetsEditdata['connection'] ?
|
||||||
|
parseInt(this.gadgetsEditdata['connection'], 10) : undefined;
|
||||||
|
this.alertService.getValuesFromUrl(this.gadgetsEditdata['table'], connectionIdNum, key).subscribe(
|
||||||
|
(values: string[]) => {
|
||||||
|
// Update filter options string for dropdown/multiselect
|
||||||
|
if (this.gadgetsEditdata['filterType'] === 'dropdown' ||
|
||||||
|
this.gadgetsEditdata['filterType'] === 'multiselect') {
|
||||||
|
this.filterOptionsString = values.join(', ');
|
||||||
|
// Also update the gadgetsEditdata filterOptions array
|
||||||
|
this.gadgetsEditdata['filterOptions'] = values;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('Error loading available values:', error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add method to handle filter key change
|
||||||
|
onFilterKeyChange(key: string) {
|
||||||
|
this.gadgetsEditdata['filterKey'] = key;
|
||||||
|
// Load available values when filter key changes
|
||||||
|
if (key && (this.gadgetsEditdata['filterType'] === 'dropdown' ||
|
||||||
|
this.gadgetsEditdata['filterType'] === 'multiselect')) {
|
||||||
|
this.loadAvailableValues(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add method to handle filter type change
|
||||||
|
onFilterTypeChange(type: string) {
|
||||||
|
this.gadgetsEditdata['filterType'] = type;
|
||||||
|
// Load available values when filter type changes to dropdown or multiselect
|
||||||
|
if ((type === 'dropdown' || type === 'multiselect') && this.gadgetsEditdata['filterKey']) {
|
||||||
|
this.loadAvailableValues(this.gadgetsEditdata['filterKey']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add method to handle API URL change for compact filter
|
||||||
|
onCompactFilterApiUrlChange(url: string) {
|
||||||
|
this.gadgetsEditdata['table'] = url;
|
||||||
|
// Load available keys when API URL changes
|
||||||
|
if (url) {
|
||||||
|
this.loadAvailableKeys(url, this.gadgetsEditdata['connection']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add method to handle connection change for compact filter
|
||||||
|
onCompactFilterConnectionChange(connectionId: string) {
|
||||||
|
this.gadgetsEditdata['connection'] = connectionId;
|
||||||
|
// Reload available keys when connection changes
|
||||||
|
if (this.gadgetsEditdata['table']) {
|
||||||
|
this.loadAvailableKeys(this.gadgetsEditdata['table'], connectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@ -1,38 +1,26 @@
|
|||||||
<div class="chart-container">
|
<div style="display: block; height: 100%; width: 100%;">
|
||||||
<!-- Compact Filters -->
|
<!-- No filter controls needed with the new simplified approach -->
|
||||||
<div class="compact-filters-container" *ngIf="baseFilters && baseFilters.length > 0">
|
<!-- Filters are now configured at the drilldown level -->
|
||||||
<app-compact-filter
|
|
||||||
*ngFor="let filter of baseFilters"
|
|
||||||
[filterKey]="filter.field"
|
|
||||||
(filterChange)="onFilterChange($event)">
|
|
||||||
</app-compact-filter>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Drilldown mode indicator -->
|
<!-- Drilldown mode indicator -->
|
||||||
<div *ngIf="currentDrilldownLevel > 0" class="drilldown-indicator">
|
<div *ngIf="currentDrilldownLevel > 0" style="background-color: #e0e0e0; padding: 5px; margin-bottom: 10px; border-radius: 4px; text-align: center;">
|
||||||
<span class="drilldown-text">Drilldown Level: {{currentDrilldownLevel}}</span>
|
<span style="font-weight: bold; color: #333;">Drilldown Level: {{currentDrilldownLevel}}</span>
|
||||||
<button class="btn btn-secondary btn-sm" (click)="navigateBack()">
|
<button (click)="navigateBack()" style="margin-left: 10px; padding: 2px 8px; background-color: #007cba; color: white; border: none; border-radius: 3px; cursor: pointer;">
|
||||||
Back to Level {{currentDrilldownLevel - 1}}
|
Back to Level {{currentDrilldownLevel - 1}}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-danger btn-sm" (click)="resetToOriginalData()">
|
<button (click)="resetToOriginalData()" style="margin-left: 10px; padding: 2px 8px; background-color: #dc3545; color: white; border: none; border-radius: 3px; cursor: pointer;">
|
||||||
Back to Main View
|
Back to Main View
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="chart-header">
|
|
||||||
<h3>{{ charttitle || 'Bar Chart' }}</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="chart-wrapper">
|
|
||||||
<div class="chart-content" [class.loading]="barChartData.length === 0 && barChartLabels.length === 0 && !noDataAvailable">
|
|
||||||
<!-- No data message -->
|
<!-- No data message -->
|
||||||
<div class="no-data-message" *ngIf="noDataAvailable">
|
<div *ngIf="noDataAvailable" style="text-align: center; padding: 20px; color: #666; font-style: italic;">
|
||||||
<p>No data available</p>
|
No data available
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Chart display -->
|
<!-- Chart display -->
|
||||||
|
<div *ngIf="!noDataAvailable" style="position: relative; height: calc(100% - 50px);">
|
||||||
<canvas baseChart
|
<canvas baseChart
|
||||||
*ngIf="!noDataAvailable"
|
|
||||||
[datasets]="barChartData"
|
[datasets]="barChartData"
|
||||||
[labels]="barChartLabels"
|
[labels]="barChartLabels"
|
||||||
[type]="barChartType"
|
[type]="barChartType"
|
||||||
@ -40,11 +28,5 @@
|
|||||||
(chartHover)="chartHovered($event)"
|
(chartHover)="chartHovered($event)"
|
||||||
(chartClick)="chartClicked($event)">
|
(chartClick)="chartClicked($event)">
|
||||||
</canvas>
|
</canvas>
|
||||||
|
|
||||||
<!-- Loading overlay -->
|
|
||||||
<div class="loading-overlay" *ngIf="barChartData.length === 0 && barChartLabels.length === 0 && !noDataAvailable">
|
|
||||||
<div class="shimmer-bar"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -5,214 +5,27 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container {
|
.bar-chart-container {
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
||||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
border: 1px solid #eaeaea;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-container:hover {
|
|
||||||
box-shadow: 0 6px 25px rgba(0, 0, 0, 0.2);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.compact-filters-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
padding: 5px;
|
|
||||||
background: #ffffff;
|
|
||||||
border: 1px solid #e9ecef;
|
|
||||||
border-radius: 6px;
|
|
||||||
min-height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drilldown-indicator {
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
padding: 10px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.drilldown-text {
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
padding: 6px 12px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:hover {
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-sm {
|
|
||||||
padding: 4px 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-secondary {
|
|
||||||
background-color: #007cba;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-danger {
|
|
||||||
background-color: #dc3545;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-header {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 22px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #0a192f;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
border-bottom: 2px solid #3498db;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-wrapper {
|
|
||||||
flex: 1;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.chart-content {
|
|
||||||
position: relative;
|
|
||||||
height: 100%;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border: 1px solid #e9ecef;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
opacity: 0.7;
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
filter: blur(2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas {
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 100%;
|
|
||||||
transition: filter 0.3s ease;
|
|
||||||
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas:hover {
|
|
||||||
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.15));
|
|
||||||
transform: scale(1.02);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-data-message {
|
|
||||||
text-align: center;
|
|
||||||
padding: 30px;
|
|
||||||
color: #666;
|
|
||||||
font-size: 18px;
|
|
||||||
font-style: italic;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.no-data-message p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading-overlay {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: rgba(255, 255, 255, 0.8);
|
|
||||||
|
|
||||||
.shimmer-bar {
|
|
||||||
width: 80%;
|
|
||||||
height: 20px;
|
|
||||||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
|
||||||
background-size: 200% 100%;
|
|
||||||
animation: shimmer 1.5s infinite;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes shimmer {
|
canvas {
|
||||||
0% {
|
display: block;
|
||||||
background-position: -200% 0;
|
max-width: 100%;
|
||||||
}
|
max-height: 100%;
|
||||||
100% {
|
|
||||||
background-position: 200% 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Responsive design for chart container
|
// Responsive design for chart container
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.chart-container {
|
.bar-chart-container {
|
||||||
padding: 15px;
|
height: 300px;
|
||||||
}
|
|
||||||
|
|
||||||
.chart-header h3 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drilldown-indicator {
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drilldown-text {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compact-filters-container {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.chart-container {
|
.bar-chart-container {
|
||||||
padding: 10px;
|
height: 250px;
|
||||||
}
|
|
||||||
|
|
||||||
.chart-header h3 {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,12 +141,6 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle filter changes from compact filters
|
|
||||||
onFilterChange(event: { filterId: string, value: any }): void {
|
|
||||||
console.log('Compact filter changed:', event);
|
|
||||||
// The filter service will automatically trigger chart updates through the subscription
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchChartData(): void {
|
fetchChartData(): void {
|
||||||
// Set flag to prevent recursive calls
|
// Set flag to prevent recursive calls
|
||||||
this.isFetchingData = true;
|
this.isFetchingData = true;
|
||||||
@ -179,73 +173,41 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
console.log('Bar chart data URL:', url);
|
console.log('Bar chart data URL:', url);
|
||||||
|
|
||||||
// Convert baseFilters to filter parameters
|
// Convert baseFilters to filter parameters
|
||||||
let filterParams = '';
|
|
||||||
if (this.baseFilters && this.baseFilters.length > 0) {
|
|
||||||
const filterObj = {};
|
const filterObj = {};
|
||||||
|
|
||||||
|
// Add base filters
|
||||||
|
if (this.baseFilters && this.baseFilters.length > 0) {
|
||||||
this.baseFilters.forEach(filter => {
|
this.baseFilters.forEach(filter => {
|
||||||
if (filter.field && filter.value) {
|
if (filter.field && filter.value) {
|
||||||
filterObj[filter.field] = filter.value;
|
filterObj[filter.field] = filter.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Object.keys(filterObj).length > 0) {
|
|
||||||
filterParams = JSON.stringify(filterObj);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
console.log('Base filters:', this.baseFilters);
|
|
||||||
console.log('Base filter params:', filterParams);
|
|
||||||
|
|
||||||
// Add common filters to filter parameters
|
// Add common filters
|
||||||
const commonFilters = this.filterService.getFilterValues();
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
const filterDefinitions = this.filterService.getFilters();
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
console.log('Common filters from service:', commonFilters);
|
|
||||||
console.log('Filter definitions:', filterDefinitions);
|
|
||||||
|
|
||||||
if (Object.keys(commonFilters).length > 0) {
|
|
||||||
// Merge common filters with base filters
|
|
||||||
const mergedFilterObj = {};
|
|
||||||
|
|
||||||
// Add base filters first
|
|
||||||
if (filterParams) {
|
|
||||||
try {
|
|
||||||
const baseFilterObj = JSON.parse(filterParams);
|
|
||||||
Object.assign(mergedFilterObj, baseFilterObj);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Failed to parse base filter parameters:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add common filters using the field name as the key, not the filter id
|
|
||||||
Object.keys(commonFilters).forEach(filterId => {
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
const filterValue = commonFilters[filterId];
|
const filterValue = commonFilters[filterId];
|
||||||
console.log(`Processing filter ID: ${filterId}, Value:`, filterValue);
|
|
||||||
|
|
||||||
// Find the filter definition to get the field name
|
// Find the filter definition to get the field name
|
||||||
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
console.log(`Filter definition for ${filterId}:`, filterDef);
|
|
||||||
|
|
||||||
if (filterDef && filterDef.field) {
|
if (filterDef && filterDef.field) {
|
||||||
const fieldName = filterDef.field;
|
const fieldName = filterDef.field;
|
||||||
console.log(`Mapping filter ID ${filterId} to field name: ${fieldName}`);
|
|
||||||
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
mergedFilterObj[fieldName] = filterValue;
|
filterObj[fieldName] = filterValue;
|
||||||
console.log(`Added to merged filters: ${fieldName} =`, filterValue);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Fallback to using filterId as field name if no field is defined
|
|
||||||
console.log(`No field name found for filter ID ${filterId}, using ID as field name`);
|
|
||||||
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
|
||||||
mergedFilterObj[filterId] = filterValue;
|
|
||||||
console.log(`Added to merged filters: ${filterId} =`, filterValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Object.keys(mergedFilterObj).length > 0) {
|
// Convert to JSON string for API call
|
||||||
filterParams = JSON.stringify(mergedFilterObj);
|
let filterParams = '';
|
||||||
}
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Final merged filter object:', filterParams);
|
console.log('Final filter object:', filterObj);
|
||||||
// Fetch data from the dashboard service with parameter field and value
|
// Fetch data from the dashboard service with parameter field and value
|
||||||
// For base level, we pass empty parameter and value, but now also pass filters
|
// For base level, we pass empty parameter and value, but now also pass filters
|
||||||
const subscription = this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
|
const subscription = this.dashboardService.getChartData(this.table, 'bar', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
|
||||||
@ -400,61 +362,47 @@ export class BarChartComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
console.log('Drilldown data URL:', url);
|
console.log('Drilldown data URL:', url);
|
||||||
|
|
||||||
// Convert drilldown layer filters to filter parameters (if applicable)
|
// Convert drilldown layer filters to filter parameters (if applicable)
|
||||||
let filterParams = '';
|
|
||||||
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
|
|
||||||
const filterObj = {};
|
const filterObj = {};
|
||||||
|
|
||||||
|
// Add drilldown layer filters
|
||||||
|
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
|
||||||
drilldownConfig.filters.forEach((filter: any) => {
|
drilldownConfig.filters.forEach((filter: any) => {
|
||||||
if (filter.field && filter.value) {
|
if (filter.field && filter.value) {
|
||||||
filterObj[filter.field] = filter.value;
|
filterObj[filter.field] = filter.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Object.keys(filterObj).length > 0) {
|
|
||||||
filterParams = JSON.stringify(filterObj);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
console.log('Drilldown layer filter parameters:', filterParams);
|
|
||||||
|
|
||||||
// Convert drilldownFilters to filter parameters for drilldown level
|
// Add drilldownFilters
|
||||||
let drilldownFilterParams = '';
|
|
||||||
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
|
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
|
||||||
const filterObj = {};
|
|
||||||
this.drilldownFilters.forEach(filter => {
|
this.drilldownFilters.forEach(filter => {
|
||||||
if (filter.field && filter.value) {
|
if (filter.field && filter.value) {
|
||||||
filterObj[filter.field] = filter.value;
|
filterObj[filter.field] = filter.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (Object.keys(filterObj).length > 0) {
|
|
||||||
drilldownFilterParams = JSON.stringify(filterObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add common filters to drilldown filter parameters
|
|
||||||
const commonFilters = this.filterService.getFilterValues();
|
|
||||||
if (Object.keys(commonFilters).length > 0) {
|
|
||||||
// Merge common filters with drilldown filters
|
|
||||||
const mergedFilterObj = {};
|
|
||||||
|
|
||||||
// Add drilldown filters first
|
|
||||||
if (drilldownFilterParams) {
|
|
||||||
try {
|
|
||||||
const drilldownFilterObj = JSON.parse(drilldownFilterParams);
|
|
||||||
Object.assign(mergedFilterObj, drilldownFilterObj);
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('Failed to parse drilldown filter parameters:', e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add common filters
|
// Add common filters
|
||||||
Object.keys(commonFilters).forEach(key => {
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
const value = commonFilters[key];
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
if (value !== undefined && value !== null && value !== '') {
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
mergedFilterObj[key] = value;
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Object.keys(mergedFilterObj).length > 0) {
|
// Convert to JSON string for API call
|
||||||
drilldownFilterParams = JSON.stringify(mergedFilterObj);
|
let drilldownFilterParams = '';
|
||||||
}
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
drilldownFilterParams = JSON.stringify(filterObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Drilldown filter parameters:', drilldownFilterParams);
|
console.log('Drilldown filter parameters:', drilldownFilterParams);
|
||||||
|
|||||||
@ -4,9 +4,41 @@
|
|||||||
<div class="clr-col-8">
|
<div class="clr-col-8">
|
||||||
<h3>{{charttitle || 'Data Grid'}}</h3>
|
<h3>{{charttitle || 'Data Grid'}}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Add drilldown navigation controls -->
|
||||||
|
<div class="clr-col-4" *ngIf="drilldownEnabled && drilldownStack.length > 0" style="text-align: right;">
|
||||||
|
<button class="btn btn-sm btn-link" (click)="navigateBack()">
|
||||||
|
<cds-icon shape="arrow" direction="left"></cds-icon>
|
||||||
|
Back to {{drilldownStack.length > 1 ? 'Previous Level' : 'Main Data'}}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Show current drilldown level -->
|
||||||
|
<div class="clr-row" *ngIf="drilldownEnabled && drilldownStack.length > 0">
|
||||||
|
<div class="clr-col-12">
|
||||||
|
<div class="alert alert-info" style="padding: 8px 12px; margin-bottom: 12px;">
|
||||||
|
<div class="alert-items">
|
||||||
|
<div class="alert-item static">
|
||||||
|
<div class="alert-icon-wrapper">
|
||||||
|
<cds-icon class="alert-icon" shape="info-circle"></cds-icon>
|
||||||
|
</div>
|
||||||
|
<span class="alert-text">
|
||||||
|
Drilldown Level: {{currentDrilldownLevel}}
|
||||||
|
<span *ngIf="drilldownStack.length > 0">
|
||||||
|
(Clicked on: {{drilldownStack[drilldownStack.length - 1].clickedKey}} = {{drilldownStack[drilldownStack.length - 1].clickedValue}})
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<clr-datagrid [clrDgLoading]="loading">
|
<clr-datagrid [clrDgLoading]="loading">
|
||||||
<clr-dg-placeholder> <ng-template #loadingSpinner><clr-spinner>Loading ... </clr-spinner></ng-template>
|
<clr-dg-placeholder>
|
||||||
|
<ng-template #loadingSpinner>
|
||||||
|
<clr-spinner>Loading ... </clr-spinner>
|
||||||
|
</ng-template>
|
||||||
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
||||||
</clr-dg-placeholder>
|
</clr-dg-placeholder>
|
||||||
|
|
||||||
@ -19,7 +51,7 @@
|
|||||||
|
|
||||||
<clr-dg-row *clrDgItems="let item of givendata" [clrDgItem]="item">
|
<clr-dg-row *clrDgItems="let item of givendata" [clrDgItem]="item">
|
||||||
<!-- Dynamic cells based on response keys -->
|
<!-- Dynamic cells based on response keys -->
|
||||||
<clr-dg-cell *ngFor="let header of dynamicHeaders">
|
<clr-dg-cell *ngFor="let header of dynamicHeaders" (click)="onRowClick(item, header.key)">
|
||||||
{{item[header.key]}}
|
{{item[header.key]}}
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
|||||||
@ -1,12 +1,28 @@
|
|||||||
@import '../../../../../../../styles1.scss';
|
// Add styles for drilldown navigation
|
||||||
input.ng-invalid.ng-touched {
|
.alert-info {
|
||||||
border-color: red;
|
background-color: #dcedf7;
|
||||||
|
border-color: #a3d4f5;
|
||||||
|
color: #21333b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error_mess {
|
.alert-info .alert-icon {
|
||||||
color: red;
|
color: #0072a3;
|
||||||
}
|
}
|
||||||
clr-datagrid{
|
|
||||||
height: 400px; /* Adjust the height as needed */
|
.btn-link {
|
||||||
overflow-y: auto;
|
color: #0072a3;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link:hover {
|
||||||
|
color: #00567a;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dg-wrapper {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr-row {
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
@ -1,13 +1,17 @@
|
|||||||
import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { Component, OnInit, Input, OnChanges, OnDestroy, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import { UsergrpmaintainceService } from 'src/app/services/admin/usergrpmaintaince.service';
|
import { UsergrpmaintainceService } from 'src/app/services/admin/usergrpmaintaince.service';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-grid-view',
|
selector: 'app-grid-view',
|
||||||
templateUrl: './grid-view.component.html',
|
templateUrl: './grid-view.component.html',
|
||||||
styleUrls: ['./grid-view.component.scss']
|
styleUrls: ['./grid-view.component.scss']
|
||||||
})
|
})
|
||||||
export class GridViewComponent implements OnInit, OnChanges {
|
export class GridViewComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
@Input() xAxis: string;
|
@Input() xAxis: string;
|
||||||
@Input() yAxis: string | string[];
|
@Input() yAxis: string | string[];
|
||||||
@Input() table: string;
|
@Input() table: string;
|
||||||
@ -23,6 +27,16 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
@Input() datasource: string;
|
@Input() datasource: string;
|
||||||
@Input() fieldName: string;
|
@Input() fieldName: string;
|
||||||
@Input() connection: number; // Add connection input
|
@Input() connection: number; // Add connection input
|
||||||
|
// Drilldown configuration inputs
|
||||||
|
@Input() drilldownEnabled: boolean = false;
|
||||||
|
@Input() drilldownApiUrl: string;
|
||||||
|
@Input() drilldownXAxis: string;
|
||||||
|
@Input() drilldownYAxis: string;
|
||||||
|
@Input() drilldownParameter: string; // Add drilldown parameter input
|
||||||
|
@Input() baseFilters: any[] = []; // Add base filters input
|
||||||
|
@Input() drilldownFilters: any[] = []; // Add drilldown filters input
|
||||||
|
// Multi-layer drilldown configuration inputs
|
||||||
|
@Input() drilldownLayers: any[] = []; // Array of drilldown layer configurations
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
givendata: any[] = [];
|
givendata: any[] = [];
|
||||||
@ -38,13 +52,37 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
submitted = false;
|
submitted = false;
|
||||||
dynamicHeaders: any[] = [];
|
dynamicHeaders: any[] = [];
|
||||||
|
|
||||||
constructor(
|
// Multi-layer drilldown state tracking
|
||||||
|
drilldownStack: any[] = []; // Stack to track drilldown navigation history
|
||||||
|
currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
|
||||||
|
originalGridData: any[] = [];
|
||||||
|
|
||||||
|
// No data state
|
||||||
|
noDataAvailable: boolean = false;
|
||||||
|
|
||||||
|
// Flag to prevent infinite loops
|
||||||
|
private isFetchingData: boolean = false;
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
private mainservice: UsergrpmaintainceService,
|
private mainservice: UsergrpmaintainceService,
|
||||||
private dashboardService: Dashboard3Service,
|
private dashboardService: Dashboard3Service,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the grid data
|
||||||
|
console.log('GridView: Filter state changed:', filters);
|
||||||
|
this.fetchGridData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.fetchGridData();
|
this.fetchGridData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,12 +93,21 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
const xAxisChanged = changes.xAxis && !changes.xAxis.firstChange;
|
const xAxisChanged = changes.xAxis && !changes.xAxis.firstChange;
|
||||||
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
|
const yAxisChanged = changes.yAxis && !changes.yAxis.firstChange;
|
||||||
const tableChanged = changes.table && !changes.table.firstChange;
|
const tableChanged = changes.table && !changes.table.firstChange;
|
||||||
const connectionChanged = changes.connection && !changes.connection.firstChange; // Add connection change detection
|
const connectionChanged = changes.connection && !changes.connection.firstChange;
|
||||||
|
const baseFiltersChanged = changes.baseFilters && !changes.baseFilters.firstChange;
|
||||||
|
// Drilldown configuration changes
|
||||||
|
const drilldownEnabledChanged = changes.drilldownEnabled && !changes.drilldownEnabled.firstChange;
|
||||||
|
const drilldownApiUrlChanged = changes.drilldownApiUrl && !changes.drilldownApiUrl.firstChange;
|
||||||
|
const drilldownXAxisChanged = changes.drilldownXAxis && !changes.drilldownXAxis.firstChange;
|
||||||
|
const drilldownYAxisChanged = changes.drilldownYAxis && !changes.drilldownYAxis.firstChange;
|
||||||
|
const drilldownLayersChanged = changes.drilldownLayers && !changes.drilldownLayers.firstChange;
|
||||||
|
|
||||||
// Respond to input changes
|
// Respond to input changes
|
||||||
if (xAxisChanged || yAxisChanged || tableChanged || connectionChanged) {
|
if (!this.isFetchingData && (xAxisChanged || yAxisChanged || tableChanged || connectionChanged || baseFiltersChanged ||
|
||||||
console.log('X or Y axis or table or connection changed, fetching new data');
|
drilldownEnabledChanged || drilldownApiUrlChanged || drilldownXAxisChanged || drilldownYAxisChanged ||
|
||||||
// Only fetch data if xAxis, yAxis, table, or connection has changed (and it's not the first change)
|
drilldownLayersChanged)) {
|
||||||
|
console.log('X or Y axis or table or connection or base filters or drilldown config changed, fetching new data');
|
||||||
|
// Only fetch data if xAxis, yAxis, table, connection, baseFilters or drilldown config has changed (and it's not the first change)
|
||||||
this.fetchGridData();
|
this.fetchGridData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,20 +115,87 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
// Dynamic headers for the grid
|
// Dynamic headers for the grid
|
||||||
|
|
||||||
fetchGridData(): void {
|
fetchGridData(): void {
|
||||||
|
// Set flag to prevent recursive calls
|
||||||
|
this.isFetchingData = true;
|
||||||
|
|
||||||
|
// If we're in drilldown mode, fetch the appropriate drilldown data
|
||||||
|
if (this.currentDrilldownLevel > 0 && this.drilldownStack.length > 0) {
|
||||||
|
this.fetchDrilldownData();
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If we have the necessary data, fetch grid data from the service
|
// If we have the necessary data, fetch grid data from the service
|
||||||
if (this.table && this.xAxis) {
|
// if (this.table && this.xAxis) {
|
||||||
console.log('Fetching grid data for:', { table: this.table, xAxis: this.xAxis, yAxis: this.yAxis, connection: this.connection });
|
if (this.table) {
|
||||||
|
|
||||||
|
console.log('=== GRID VIEW DEBUG INFO ===');
|
||||||
|
console.log('Table:', this.table);
|
||||||
|
console.log('X-Axis:', this.xAxis);
|
||||||
|
console.log('Y-Axis:', this.yAxis);
|
||||||
|
console.log('Connection:', this.connection);
|
||||||
|
|
||||||
// Convert yAxis to string if it's an array
|
// Convert yAxis to string if it's an array
|
||||||
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
|
const yAxisString = Array.isArray(this.yAxis) ? this.yAxis.join(',') : this.yAxis;
|
||||||
|
|
||||||
|
// Get the parameter value from the drilldown stack for base level (should be empty)
|
||||||
|
let parameterValue = '';
|
||||||
|
|
||||||
|
// Log the URL that will be called
|
||||||
|
let url = `chart/getdashjson/grid?tableName=${this.table}&xAxis=${this.xAxis}&yAxes=${yAxisString}${this.connection ? `&sureId=${this.connection}` : ''}`;
|
||||||
|
console.log('Grid data URL:', url);
|
||||||
|
|
||||||
|
// Get filter parameters from base filters
|
||||||
|
const filterObj = {};
|
||||||
|
|
||||||
|
// Add base filters
|
||||||
|
if (this.baseFilters && this.baseFilters.length > 0) {
|
||||||
|
this.baseFilters.forEach(filter => {
|
||||||
|
if (filter.field && filter.value) {
|
||||||
|
filterObj[filter.field] = filter.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add common filters directly as key-value pairs
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Add common filters using the field name as the key
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('GridView: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
// Fetch data from the dashboard service, similar to other chart components
|
// Fetch data from the dashboard service, similar to other chart components
|
||||||
this.dashboardService.getChartData(this.table, 'grid', this.xAxis, yAxisString, this.connection).subscribe(
|
this.dashboardService.getChartData(this.table, 'grid', this.xAxis, yAxisString, this.connection, '', '', filterParams).subscribe(
|
||||||
(data: any) => {
|
(data: any) => {
|
||||||
|
console.log('=== GRID VIEW DATA RESPONSE ===');
|
||||||
console.log('Received grid data:', data);
|
console.log('Received grid data:', data);
|
||||||
if (data === null) {
|
if (data === null) {
|
||||||
console.warn('Grid API returned null data. Check if the API endpoint is working correctly.');
|
console.warn('Grid API returned null data. Check if the API endpoint is working correctly.');
|
||||||
this.error = "No data Available";
|
this.error = "No data Available";
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,27 +204,36 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
this.givendata = data.chartData;
|
this.givendata = data.chartData;
|
||||||
this.extractDynamicHeaders(data.chartData);
|
this.extractDynamicHeaders(data.chartData);
|
||||||
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
console.log('Updated grid with data:', this.givendata);
|
console.log('Updated grid with data:', this.givendata);
|
||||||
} else if (data && data.data) {
|
} else if (data && data.data) {
|
||||||
// Handle the original expected format as fallback
|
// Handle the original expected format as fallback
|
||||||
this.givendata = data.data;
|
this.givendata = data.data;
|
||||||
this.extractDynamicHeaders(data.data);
|
this.extractDynamicHeaders(data.data);
|
||||||
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
console.log('Updated grid with legacy data format:', this.givendata);
|
console.log('Updated grid with legacy data format:', this.givendata);
|
||||||
} else if (Array.isArray(data)) {
|
} else if (Array.isArray(data)) {
|
||||||
// Handle case where data is directly an array
|
// Handle case where data is directly an array
|
||||||
this.givendata = data;
|
this.givendata = data;
|
||||||
this.extractDynamicHeaders(data);
|
this.extractDynamicHeaders(data);
|
||||||
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
console.log('Updated grid with array data:', this.givendata);
|
console.log('Updated grid with array data:', this.givendata);
|
||||||
} else {
|
} else {
|
||||||
console.warn('Grid received data does not have expected structure', data);
|
console.warn('Grid received data does not have expected structure', data);
|
||||||
this.error = "No valid data received";
|
this.error = "No valid data received";
|
||||||
this.givendata = [];
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
}
|
}
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
console.log('Error fetching grid data:', error);
|
console.log('Error fetching grid data:', error);
|
||||||
this.error = "Server Error";
|
this.error = "Server Error";
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
});
|
});
|
||||||
} else if (this.table) {
|
} else if (this.table) {
|
||||||
console.log('Missing xAxis, falling back to default data fetching');
|
console.log('Missing xAxis, falling back to default data fetching');
|
||||||
@ -126,13 +249,342 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
this.givendata = Array.isArray(data) ? data : [];
|
this.givendata = Array.isArray(data) ? data : [];
|
||||||
this.extractDynamicHeaders(data);
|
this.extractDynamicHeaders(data);
|
||||||
this.error = this.givendata && this.givendata.length === 0 ? "No data Available" : undefined;
|
this.error = this.givendata && this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata && this.givendata.length === 0;
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
}, (error) => {
|
}, (error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
this.error = "Server Error";
|
this.error = "Server Error";
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('Missing required data for grid:', { table: this.table });
|
console.log('Missing required data for grid:', { table: this.table });
|
||||||
this.error = "Table name is required";
|
this.error = "Table name is required";
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
// Reset flag after fetching
|
||||||
|
this.isFetchingData = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch drilldown data based on current drilldown level
|
||||||
|
fetchDrilldownData(): void {
|
||||||
|
console.log('Fetching drilldown data, current level:', this.currentDrilldownLevel);
|
||||||
|
console.log('Drilldown stack:', this.drilldownStack);
|
||||||
|
|
||||||
|
// Get the current drilldown configuration based on the current level
|
||||||
|
let drilldownConfig;
|
||||||
|
if (this.currentDrilldownLevel === 1) {
|
||||||
|
// Base drilldown level
|
||||||
|
drilldownConfig = {
|
||||||
|
apiUrl: this.drilldownApiUrl,
|
||||||
|
xAxis: this.drilldownXAxis,
|
||||||
|
yAxis: this.drilldownYAxis,
|
||||||
|
parameter: this.drilldownParameter
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Multi-layer drilldown level
|
||||||
|
const layerIndex = this.currentDrilldownLevel - 2; // -2 because level 1 is base drilldown
|
||||||
|
if (layerIndex >= 0 && layerIndex < this.drilldownLayers.length) {
|
||||||
|
drilldownConfig = this.drilldownLayers[layerIndex];
|
||||||
|
} else {
|
||||||
|
console.warn('Invalid drilldown layer index:', layerIndex);
|
||||||
|
this.error = "Invalid drilldown configuration";
|
||||||
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Drilldown config for level', this.currentDrilldownLevel, ':', drilldownConfig);
|
||||||
|
|
||||||
|
// Check if we have valid drilldown configuration
|
||||||
|
if (!drilldownConfig || !drilldownConfig.apiUrl || !drilldownConfig.xAxis || !drilldownConfig.yAxis) {
|
||||||
|
console.warn('Missing drilldown configuration for level:', this.currentDrilldownLevel);
|
||||||
|
this.error = "Missing drilldown configuration";
|
||||||
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the parameter value from the drilldown stack
|
||||||
|
let parameterValue = '';
|
||||||
|
if (this.drilldownStack.length > 0) {
|
||||||
|
const lastEntry = this.drilldownStack[this.drilldownStack.length - 1];
|
||||||
|
parameterValue = lastEntry.clickedValue || '';
|
||||||
|
console.log('Parameter value from last click:', parameterValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the parameter field from drilldown config
|
||||||
|
const parameterField = drilldownConfig.parameter || '';
|
||||||
|
console.log('Parameter field:', parameterField);
|
||||||
|
|
||||||
|
console.log('Fetching drilldown data for level:', this.currentDrilldownLevel, {
|
||||||
|
apiUrl: drilldownConfig.apiUrl,
|
||||||
|
xAxis: drilldownConfig.xAxis,
|
||||||
|
yAxis: drilldownConfig.yAxis,
|
||||||
|
parameterField: parameterField,
|
||||||
|
parameterValue: parameterValue,
|
||||||
|
connection: this.connection
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build the actual API URL with parameter replacement
|
||||||
|
let actualApiUrl = drilldownConfig.apiUrl;
|
||||||
|
console.log('Original API URL:', actualApiUrl);
|
||||||
|
console.log('Parameter value to use:', parameterValue);
|
||||||
|
console.log('Parameter field:', parameterField);
|
||||||
|
|
||||||
|
// Check if the URL contains angle brackets for parameter replacement
|
||||||
|
const hasAngleBrackets = /<[^>]+>/.test(actualApiUrl);
|
||||||
|
|
||||||
|
if (hasAngleBrackets && parameterValue) {
|
||||||
|
// Replace angle brackets placeholder with actual value
|
||||||
|
console.log('Replacing angle brackets with parameter value');
|
||||||
|
const encodedValue = encodeURIComponent(parameterValue);
|
||||||
|
actualApiUrl = actualApiUrl.replace(/<[^>]+>/g, encodedValue);
|
||||||
|
console.log('URL after angle bracket replacement:', actualApiUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the URL that will be called
|
||||||
|
let url = `chart/getdashjson/grid?tableName=${actualApiUrl}&xAxis=${drilldownConfig.xAxis}&yAxes=${drilldownConfig.yAxis}${this.connection ? `&sureId=${this.connection}` : ''}`;
|
||||||
|
if (parameterField && parameterValue) {
|
||||||
|
url += `¶meter=${encodeURIComponent(parameterField)}¶meterValue=${encodeURIComponent(parameterValue)}`;
|
||||||
|
}
|
||||||
|
console.log('Drilldown data URL:', url);
|
||||||
|
|
||||||
|
// Convert drilldown layer filters to filter parameters (if applicable)
|
||||||
|
const filterObj = {};
|
||||||
|
|
||||||
|
// Add drilldown layer filters
|
||||||
|
if (drilldownConfig.filters && drilldownConfig.filters.length > 0) {
|
||||||
|
drilldownConfig.filters.forEach((filter: any) => {
|
||||||
|
if (filter.field && filter.value) {
|
||||||
|
filterObj[filter.field] = filter.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add drilldownFilters
|
||||||
|
if (this.drilldownFilters && this.drilldownFilters.length > 0) {
|
||||||
|
this.drilldownFilters.forEach(filter => {
|
||||||
|
if (filter.field && filter.value) {
|
||||||
|
filterObj[filter.field] = filter.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let drilldownFilterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
drilldownFilterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Drilldown filter parameters:', drilldownFilterParams);
|
||||||
|
|
||||||
|
// For drilldown level, we pass the parameter value from the drilldown stack and drilldown filters
|
||||||
|
this.dashboardService.getChartData(
|
||||||
|
drilldownConfig.apiUrl, 'grid',
|
||||||
|
drilldownConfig.xAxis, drilldownConfig.yAxis,
|
||||||
|
this.connection,
|
||||||
|
parameterField, parameterValue,
|
||||||
|
drilldownFilterParams
|
||||||
|
).subscribe(
|
||||||
|
(data: any) => {
|
||||||
|
console.log('Received drilldown data:', data);
|
||||||
|
if (data === null) {
|
||||||
|
console.warn('Drilldown API returned null data. Check if the API endpoint is working correctly.');
|
||||||
|
this.error = "No data Available";
|
||||||
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the actual data structure returned by the API
|
||||||
|
if (data && data.chartData) {
|
||||||
|
this.givendata = data.chartData;
|
||||||
|
this.extractDynamicHeaders(data.chartData);
|
||||||
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
|
console.log('Updated grid with drilldown data:', this.givendata);
|
||||||
|
} else if (data && data.data) {
|
||||||
|
// Handle the original expected format as fallback
|
||||||
|
this.givendata = data.data;
|
||||||
|
this.extractDynamicHeaders(data.data);
|
||||||
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
|
console.log('Updated grid with drilldown legacy data format:', this.givendata);
|
||||||
|
} else if (Array.isArray(data)) {
|
||||||
|
// Handle case where data is directly an array
|
||||||
|
this.givendata = data;
|
||||||
|
this.extractDynamicHeaders(data);
|
||||||
|
this.error = this.givendata.length === 0 ? "No data Available" : undefined;
|
||||||
|
this.noDataAvailable = this.givendata.length === 0;
|
||||||
|
console.log('Updated grid with drilldown array data:', this.givendata);
|
||||||
|
} else {
|
||||||
|
console.warn('Drilldown received data does not have expected structure', data);
|
||||||
|
this.error = "No valid data received";
|
||||||
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(error) => {
|
||||||
|
console.error('Error fetching drilldown data:', error);
|
||||||
|
this.error = "Server Error";
|
||||||
|
this.givendata = [];
|
||||||
|
this.noDataAvailable = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset to original data (go back to base level)
|
||||||
|
resetToOriginalData(): void {
|
||||||
|
console.log('Resetting to original data');
|
||||||
|
console.log('Current stack before reset:', this.drilldownStack);
|
||||||
|
console.log('Current level before reset:', this.currentDrilldownLevel);
|
||||||
|
|
||||||
|
this.currentDrilldownLevel = 0;
|
||||||
|
this.drilldownStack = [];
|
||||||
|
|
||||||
|
if (this.originalGridData.length > 0) {
|
||||||
|
// Create a deep copy to avoid reference issues
|
||||||
|
this.givendata = JSON.parse(JSON.stringify(this.originalGridData));
|
||||||
|
this.extractDynamicHeaders(this.givendata);
|
||||||
|
console.log('Restored original data');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('After reset - data:', this.givendata);
|
||||||
|
|
||||||
|
// Re-fetch original data
|
||||||
|
this.fetchGridData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate back to previous drilldown level
|
||||||
|
navigateBack(): void {
|
||||||
|
console.log('Navigating back, current stack:', this.drilldownStack);
|
||||||
|
console.log('Current level:', this.currentDrilldownLevel);
|
||||||
|
|
||||||
|
if (this.drilldownStack.length > 0) {
|
||||||
|
// Remove the last entry from the stack
|
||||||
|
const removedEntry = this.drilldownStack.pop();
|
||||||
|
console.log('Removed entry from stack:', removedEntry);
|
||||||
|
|
||||||
|
// Update the current drilldown level
|
||||||
|
this.currentDrilldownLevel = this.drilldownStack.length;
|
||||||
|
console.log('New level after pop:', this.currentDrilldownLevel);
|
||||||
|
console.log('Stack after pop:', this.drilldownStack);
|
||||||
|
|
||||||
|
if (this.drilldownStack.length > 0) {
|
||||||
|
// Fetch data for the previous level
|
||||||
|
console.log('Fetching data for previous level');
|
||||||
|
this.fetchDrilldownData();
|
||||||
|
} else {
|
||||||
|
// Back to base level
|
||||||
|
console.log('Back to base level, resetting to original data');
|
||||||
|
this.resetToOriginalData();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Already at base level, reset to original data
|
||||||
|
console.log('Already at base level, resetting to original data');
|
||||||
|
this.resetToOriginalData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to handle grid row clicks for drilldown
|
||||||
|
onRowClick(item: any, key: string): void {
|
||||||
|
console.log('Grid row clicked:', { item, key });
|
||||||
|
|
||||||
|
// If drilldown is enabled
|
||||||
|
if (this.drilldownEnabled) {
|
||||||
|
// Get the value for the clicked key
|
||||||
|
const clickedValue = item[key];
|
||||||
|
|
||||||
|
console.log('Clicked on row value:', { key, value: clickedValue });
|
||||||
|
|
||||||
|
// If we're not at the base level, store original data
|
||||||
|
if (this.currentDrilldownLevel === 0) {
|
||||||
|
// Store original data before entering drilldown mode
|
||||||
|
// Create a deep copy to avoid reference issues
|
||||||
|
this.originalGridData = JSON.parse(JSON.stringify(this.givendata));
|
||||||
|
console.log('Stored original data for drilldown');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the next drilldown level
|
||||||
|
const nextDrilldownLevel = this.currentDrilldownLevel + 1;
|
||||||
|
|
||||||
|
console.log('Next drilldown level will be:', nextDrilldownLevel);
|
||||||
|
|
||||||
|
// Check if there's a drilldown configuration for this level
|
||||||
|
let hasDrilldownConfig = false;
|
||||||
|
let drilldownConfig;
|
||||||
|
|
||||||
|
if (nextDrilldownLevel === 1) {
|
||||||
|
// Base drilldown level
|
||||||
|
drilldownConfig = {
|
||||||
|
apiUrl: this.drilldownApiUrl,
|
||||||
|
xAxis: this.drilldownXAxis,
|
||||||
|
yAxis: this.drilldownYAxis,
|
||||||
|
parameter: this.drilldownParameter
|
||||||
|
};
|
||||||
|
hasDrilldownConfig = !!this.drilldownApiUrl && !!this.drilldownXAxis && !!this.drilldownYAxis;
|
||||||
|
} else {
|
||||||
|
// Multi-layer drilldown level
|
||||||
|
const layerIndex = nextDrilldownLevel - 2; // -2 because level 1 is base drilldown
|
||||||
|
if (layerIndex < this.drilldownLayers.length) {
|
||||||
|
drilldownConfig = this.drilldownLayers[layerIndex];
|
||||||
|
hasDrilldownConfig = drilldownConfig.enabled &&
|
||||||
|
!!drilldownConfig.apiUrl &&
|
||||||
|
!!drilldownConfig.xAxis &&
|
||||||
|
!!drilldownConfig.yAxis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Drilldown config for next level:', drilldownConfig);
|
||||||
|
console.log('Has drilldown config:', hasDrilldownConfig);
|
||||||
|
|
||||||
|
// If there's a drilldown configuration for the next level, proceed
|
||||||
|
if (hasDrilldownConfig) {
|
||||||
|
// Add this click to the drilldown stack
|
||||||
|
const stackEntry = {
|
||||||
|
level: nextDrilldownLevel,
|
||||||
|
clickedKey: key,
|
||||||
|
clickedValue: clickedValue
|
||||||
|
};
|
||||||
|
|
||||||
|
this.drilldownStack.push(stackEntry);
|
||||||
|
|
||||||
|
console.log('Added to drilldown stack:', stackEntry);
|
||||||
|
console.log('Current drilldown stack:', this.drilldownStack);
|
||||||
|
|
||||||
|
// Update the current drilldown level
|
||||||
|
this.currentDrilldownLevel = nextDrilldownLevel;
|
||||||
|
|
||||||
|
console.log('Entering drilldown level:', this.currentDrilldownLevel);
|
||||||
|
|
||||||
|
// Fetch drilldown data for the new level
|
||||||
|
this.fetchDrilldownData();
|
||||||
|
} else {
|
||||||
|
console.log('No drilldown configuration for level:', nextDrilldownLevel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Drilldown not enabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,4 +627,23 @@ export class GridViewComponent implements OnInit, OnChanges {
|
|||||||
.replace(/([A-Z])/g, ' $1')
|
.replace(/([A-Z])/g, ' $1')
|
||||||
.replace(/^./, str => str.toUpperCase());
|
.replace(/^./, str => str.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('GridViewComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
// Clear data to help with garbage collection
|
||||||
|
this.givendata = [];
|
||||||
|
this.dynamicHeaders = [];
|
||||||
|
this.drilldownStack = [];
|
||||||
|
this.originalGridData = [];
|
||||||
|
|
||||||
|
console.log('GridViewComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -11,6 +11,9 @@
|
|||||||
<h3>{{ 'all_dashboard' | translate }}</h3>
|
<h3>{{ 'all_dashboard' | translate }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col-4" style="text-align: right;">
|
<div class="clr-col-4" style="text-align: right;">
|
||||||
|
<button class="btn btn-success" [routerLink]="['/cns-portal/shield-dashboard']">
|
||||||
|
<clr-icon shape="shield"></clr-icon>Shield Dashboard
|
||||||
|
</button>
|
||||||
<button id="add" class="btn btn-primary" (click)="gotoadd()">
|
<button id="add" class="btn btn-primary" (click)="gotoadd()">
|
||||||
<clr-icon shape="plus"></clr-icon>{{ 'dashboard_builder' | translate }}
|
<clr-icon shape="plus"></clr-icon>{{ 'dashboard_builder' | translate }}
|
||||||
</button>
|
</button>
|
||||||
@ -112,6 +115,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -3,6 +3,10 @@ import { DashrunnerService } from '../dashrunner.service';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bar-runner',
|
selector: 'app-bar-runner',
|
||||||
@ -24,8 +28,19 @@ export class BarRunnerComponent implements OnInit {
|
|||||||
JsonData;
|
JsonData;
|
||||||
|
|
||||||
barData;
|
barData;
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
ConnectionId: number; // Add ConnectionId property
|
||||||
private router : Router,) { }
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private Dashtestservive:DashrunnerService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private dashboardService: Dashboard3Service,
|
||||||
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService
|
||||||
|
) { }
|
||||||
|
|
||||||
barChartLabels: any[] = [];
|
barChartLabels: any[] = [];
|
||||||
barChartType: string = 'bar';
|
barChartType: string = 'bar';
|
||||||
@ -47,6 +62,13 @@ export class BarRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -74,22 +96,62 @@ export class BarRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.barChartLegend = ChartObject[i].chartlegend;
|
this.barChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Bar Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.barChartData = this.JsonData.barChartData;
|
|
||||||
this.barChartLabels = this.JsonData.barChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('BarRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Bar Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.barChartData = this.JsonData.barChartData;
|
||||||
|
this.barChartLabels = this.JsonData.barChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -98,4 +160,16 @@ export class BarRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('BarRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('BarRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -5,6 +5,10 @@ import { ChartConfiguration, ChartDataset, ChartOptions } from 'chart.js';
|
|||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
import { DashrunnerService } from '../dashrunner.service';
|
import { DashrunnerService } from '../dashrunner.service';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bubble-runner',
|
selector: 'app-bubble-runner',
|
||||||
@ -25,9 +29,15 @@ export class BubbleRunnerComponent implements OnInit {
|
|||||||
JsonData;
|
JsonData;
|
||||||
lineChartNoLabels: [] = [];
|
lineChartNoLabels: [] = [];
|
||||||
ChartLegend = false;
|
ChartLegend = false;
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
public bubbleChartOptions: ChartConfiguration['options'] = {
|
public bubbleChartOptions: ChartConfiguration['options'] = {
|
||||||
// scales: {
|
// scales: {
|
||||||
@ -87,6 +97,13 @@ export class BubbleRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -112,22 +129,62 @@ export class BubbleRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.ChartLegend = ChartObject[i].chartlegend;
|
this.ChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Bubble Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.bubbleChartData = this.JsonData.bubbleChartData;
|
|
||||||
// this.radarChartLabels = this.JsonData.radarChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('BubbleRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Bubble Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.bubbleChartData = this.JsonData.bubbleChartData;
|
||||||
|
// this.radarChartLabels = this.JsonData.radarChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -136,5 +193,18 @@ export class BubbleRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('BubbleRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('BubbleRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,64 @@
|
|||||||
|
<!-- Display Mode - No configuration UI in runner -->
|
||||||
|
<div class="compact-filter">
|
||||||
|
<div class="filter-header">
|
||||||
|
<span class="filter-label" *ngIf="filterLabel">{{ filterLabel }}</span>
|
||||||
|
<span class="filter-key" *ngIf="!filterLabel && filterKey">{{ filterKey }}</span>
|
||||||
|
<span class="filter-type">({{ filterType }})</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Text Filter -->
|
||||||
|
<div class="filter-control" *ngIf="filterType === 'text'">
|
||||||
|
<input type="text"
|
||||||
|
[(ngModel)]="filterValue"
|
||||||
|
(ngModelChange)="onFilterValueChange($event)"
|
||||||
|
[placeholder]="filterLabel || filterKey"
|
||||||
|
class="clr-input compact-input">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dropdown Filter -->
|
||||||
|
<div class="filter-control" *ngIf="filterType === 'dropdown'">
|
||||||
|
<select [(ngModel)]="filterValue"
|
||||||
|
(ngModelChange)="onFilterValueChange($event)"
|
||||||
|
class="clr-select compact-select">
|
||||||
|
<option value="">{{ filterLabel || filterKey }}</option>
|
||||||
|
<option *ngFor="let option of filterOptions" [value]="option">{{ option }}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Multi-Select Filter -->
|
||||||
|
<div class="filter-control" *ngIf="filterType === 'multiselect'">
|
||||||
|
<div class="checkbox-group">
|
||||||
|
<div *ngFor="let option of filterOptions" class="checkbox-item">
|
||||||
|
<input type="checkbox"
|
||||||
|
[checked]="filterValue && filterValue.includes(option)"
|
||||||
|
(change)="onMultiSelectChange(option, $event)"
|
||||||
|
[id]="'checkbox-' + option">
|
||||||
|
<label [for]="'checkbox-' + option">{{ option }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Date Range Filter -->
|
||||||
|
<div class="filter-control date-range" *ngIf="filterType === 'date-range'">
|
||||||
|
<input type="date"
|
||||||
|
[(ngModel)]="filterValue.start"
|
||||||
|
(ngModelChange)="onDateRangeChange({ start: $event, end: filterValue.end })"
|
||||||
|
placeholder="Start Date"
|
||||||
|
class="clr-input compact-date">
|
||||||
|
<input type="date"
|
||||||
|
[(ngModel)]="filterValue.end"
|
||||||
|
(ngModelChange)="onDateRangeChange({ start: filterValue.start, end: $event })"
|
||||||
|
placeholder="End Date"
|
||||||
|
class="clr-input compact-date">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Toggle Filter -->
|
||||||
|
<div class="filter-control toggle" *ngIf="filterType === 'toggle'">
|
||||||
|
<input type="checkbox"
|
||||||
|
[(ngModel)]="filterValue"
|
||||||
|
(ngModelChange)="onToggleChange($event)"
|
||||||
|
clrToggle
|
||||||
|
class="clr-toggle">
|
||||||
|
<label class="toggle-label">{{ filterLabel || filterKey }}</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
.compact-filter {
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
|
||||||
|
.filter-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.filter-label, .filter-key {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-type {
|
||||||
|
font-size: 0.8em;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-control {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
.compact-input, .compact-select, .compact-date {
|
||||||
|
width: 100%;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact-multiselect {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.checkbox-item {
|
||||||
|
margin: 5px 0;
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.date-range {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.compact-date {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.toggle {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.clr-toggle {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-label {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,206 @@
|
|||||||
|
import { Component, OnInit, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
|
import { FilterService, Filter } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-compact-filter-runner',
|
||||||
|
templateUrl: './compact-filter-runner.component.html',
|
||||||
|
styleUrls: ['./compact-filter-runner.component.scss']
|
||||||
|
})
|
||||||
|
export class CompactFilterRunnerComponent implements OnInit, OnChanges {
|
||||||
|
@Input() filterKey: string = '';
|
||||||
|
@Input() filterType: string = 'text';
|
||||||
|
@Input() filterOptions: string[] = [];
|
||||||
|
@Input() filterLabel: string = '';
|
||||||
|
@Input() apiUrl: string = '';
|
||||||
|
@Input() connection: number | undefined;
|
||||||
|
@Output() filterChange = new EventEmitter<any>();
|
||||||
|
|
||||||
|
selectedFilter: Filter | null = null;
|
||||||
|
filterValue: any = '';
|
||||||
|
availableFilters: Filter[] = [];
|
||||||
|
availableKeys: string[] = [];
|
||||||
|
availableValues: string[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private filterService: FilterService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
console.log('CompactFilterRunnerComponent initialized with inputs:', {
|
||||||
|
filterKey: this.filterKey,
|
||||||
|
filterType: this.filterType,
|
||||||
|
filterOptions: this.filterOptions,
|
||||||
|
filterLabel: this.filterLabel,
|
||||||
|
apiUrl: this.apiUrl,
|
||||||
|
connection: this.connection
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register this filter with the filter service
|
||||||
|
this.registerFilter();
|
||||||
|
|
||||||
|
// Subscribe to filter definitions to get available filters
|
||||||
|
this.filterService.filters$.subscribe(filters => {
|
||||||
|
this.availableFilters = filters;
|
||||||
|
this.updateSelectedFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Subscribe to filter state changes
|
||||||
|
this.filterService.filterState$.subscribe(state => {
|
||||||
|
if (this.selectedFilter && state.hasOwnProperty(this.selectedFilter.id)) {
|
||||||
|
this.filterValue = state[this.selectedFilter.id];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
|
console.log('CompactFilterRunnerComponent inputs changed:', changes);
|
||||||
|
|
||||||
|
// If filterKey or filterType changes, re-register the filter
|
||||||
|
if (changes.filterKey || changes.filterType || changes.filterOptions) {
|
||||||
|
this.registerFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this filter with the filter service
|
||||||
|
registerFilter(): void {
|
||||||
|
console.log('Registering filter with key:', this.filterKey, 'type:', this.filterType);
|
||||||
|
|
||||||
|
if (this.filterKey) {
|
||||||
|
// Get current filter values from the service
|
||||||
|
const currentFilterValues = this.filterService.getFilterValues();
|
||||||
|
|
||||||
|
// Create a filter definition for this compact filter
|
||||||
|
const filterDef: Filter = {
|
||||||
|
id: `${this.filterKey}`,
|
||||||
|
field: this.filterKey,
|
||||||
|
label: this.filterLabel || this.filterKey,
|
||||||
|
type: this.filterType as any,
|
||||||
|
options: this.filterOptions,
|
||||||
|
value: this.filterValue // Use the current filter value
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Created filter definition:', filterDef);
|
||||||
|
|
||||||
|
// Get current filters
|
||||||
|
const currentFilters = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Check if this filter is already registered
|
||||||
|
const existingFilterIndex = currentFilters.findIndex(f => f.id === filterDef.id);
|
||||||
|
|
||||||
|
if (existingFilterIndex >= 0) {
|
||||||
|
// Preserve the existing filter configuration
|
||||||
|
const existingFilter = currentFilters[existingFilterIndex];
|
||||||
|
console.log('Found existing filter:', existingFilter);
|
||||||
|
|
||||||
|
// Preserve the existing filter value if it exists in the service
|
||||||
|
if (currentFilterValues.hasOwnProperty(existingFilter.id)) {
|
||||||
|
filterDef.value = currentFilterValues[existingFilter.id];
|
||||||
|
this.filterValue = filterDef.value; // Update local value
|
||||||
|
console.log('Using value from service:', filterDef.value);
|
||||||
|
} else if (existingFilter.value !== undefined) {
|
||||||
|
// Fallback to existing filter's value if no service value
|
||||||
|
filterDef.value = existingFilter.value;
|
||||||
|
this.filterValue = filterDef.value;
|
||||||
|
console.log('Using value from existing filter:', filterDef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preserve other configuration properties
|
||||||
|
filterDef.label = existingFilter.label;
|
||||||
|
filterDef.options = existingFilter.options || this.filterOptions;
|
||||||
|
|
||||||
|
// Update existing filter
|
||||||
|
currentFilters[existingFilterIndex] = filterDef;
|
||||||
|
console.log('Updated existing filter:', filterDef);
|
||||||
|
} else {
|
||||||
|
// For new filters, check if there's already a value in the service
|
||||||
|
if (currentFilterValues.hasOwnProperty(filterDef.id)) {
|
||||||
|
filterDef.value = currentFilterValues[filterDef.id];
|
||||||
|
this.filterValue = filterDef.value; // Update local value
|
||||||
|
console.log('Using value from service for new filter:', filterDef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new filter
|
||||||
|
currentFilters.push(filterDef);
|
||||||
|
console.log('Added new filter:', filterDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the filter service with the new filter list
|
||||||
|
this.filterService.setFilters(currentFilters);
|
||||||
|
|
||||||
|
// Update the selected filter reference
|
||||||
|
this.selectedFilter = filterDef;
|
||||||
|
console.log('Selected filter set to:', this.selectedFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSelectedFilter(): void {
|
||||||
|
if (this.filterKey && this.availableFilters.length > 0) {
|
||||||
|
this.selectedFilter = this.availableFilters.find(f => f.field === this.filterKey) || null;
|
||||||
|
if (this.selectedFilter) {
|
||||||
|
// Get current value for this filter from the service
|
||||||
|
const currentState = this.filterService.getFilterValues();
|
||||||
|
const filterValue = currentState[this.selectedFilter.id];
|
||||||
|
if (filterValue !== undefined) {
|
||||||
|
this.filterValue = filterValue;
|
||||||
|
} else if (this.selectedFilter.value !== undefined) {
|
||||||
|
// Use the filter's default value if no service value
|
||||||
|
this.filterValue = this.selectedFilter.value;
|
||||||
|
} else {
|
||||||
|
// Use the current filter value as fallback
|
||||||
|
this.filterValue = this.filterValue || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Updated selected filter value:', this.filterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onFilterValueChange(value: any): void {
|
||||||
|
console.log('Filter value changed:', value);
|
||||||
|
|
||||||
|
if (this.selectedFilter) {
|
||||||
|
this.filterValue = value;
|
||||||
|
this.filterService.updateFilterValue(this.selectedFilter.id, value);
|
||||||
|
this.filterChange.emit({ filterId: this.selectedFilter.id, value: value });
|
||||||
|
|
||||||
|
// Update the filter definition in the service to reflect the new value
|
||||||
|
const currentFilters = this.filterService.getFilters();
|
||||||
|
const filterIndex = currentFilters.findIndex(f => f.id === this.selectedFilter.id);
|
||||||
|
if (filterIndex >= 0) {
|
||||||
|
currentFilters[filterIndex].value = value;
|
||||||
|
this.filterService.setFilters(currentFilters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleChange(checked: boolean): void {
|
||||||
|
this.onFilterValueChange(checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDateRangeChange(dateRange: { start: string | null, end: string | null }): void {
|
||||||
|
this.onFilterValueChange(dateRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle multi-select changes
|
||||||
|
onMultiSelectChange(option: string, event: any): void {
|
||||||
|
const checked = event.target.checked;
|
||||||
|
|
||||||
|
// Initialize filterValue as array if it's not already
|
||||||
|
if (!Array.isArray(this.filterValue)) {
|
||||||
|
this.filterValue = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
// Add option to array if not already present
|
||||||
|
if (!this.filterValue.includes(option)) {
|
||||||
|
this.filterValue.push(option);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove option from array
|
||||||
|
this.filterValue = this.filterValue.filter((item: string) => item !== option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the change
|
||||||
|
this.onFilterValueChange(this.filterValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -160,7 +160,27 @@ getlinechart(): any[] {
|
|||||||
return this._http.get(url);
|
return this._http.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New method to support filters
|
||||||
|
public getChartDataWithFilters(tableName: string, jobType: string, xAxis:any, yAxes:any, sureId: number | undefined, parameterField: string, parameterValue: string, filterParams: string): Observable<any> {
|
||||||
|
let url = `${baseUrl}/chart/getdashjson/${jobType}?tableName=${tableName}&xAxis=${xAxis}&yAxes=${yAxes}`;
|
||||||
|
|
||||||
|
// Add sureId if provided
|
||||||
|
if (sureId) {
|
||||||
|
url += `&sureId=${sureId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add parameter field and value if provided
|
||||||
|
if (parameterField && parameterValue) {
|
||||||
|
url += `¶meter=${encodeURIComponent(parameterField)}¶meterValue=${encodeURIComponent(parameterValue)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add filter parameters if provided
|
||||||
|
if (filterParams) {
|
||||||
|
url += `&filters=${encodeURIComponent(filterParams)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._http.get(url);
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,11 @@
|
|||||||
<!-- <span><button class="btn btn-primary" (click)="Export(item.name)">Export</button></span> -->
|
<!-- <span><button class="btn btn-primary" (click)="Export(item.name)">Export</button></span> -->
|
||||||
<!-- <span><app-line-runner (buttonClicked)="generatePDFFile()"></app-line-runner></span> -->
|
<!-- <span><app-line-runner (buttonClicked)="generatePDFFile()"></app-line-runner></span> -->
|
||||||
<!-- <h4 style="margin-top: 10px; margin-left: 10px;">{{ item.charttitle }}</h4> -->
|
<!-- <h4 style="margin-top: 10px; margin-left: 10px;">{{ item.charttitle }}</h4> -->
|
||||||
<ndc-dynamic class="no-drag" [ndcDynamicComponent]="item.component" (moduleInfo)="display($event)"></ndc-dynamic>
|
<ndc-dynamic class="no-drag"
|
||||||
|
[ndcDynamicComponent]="item.component"
|
||||||
|
[ndcDynamicInputs]="getComponentInputs(item)"
|
||||||
|
(moduleInfo)="display($event)">
|
||||||
|
</ndc-dynamic>
|
||||||
</gridster-item>
|
</gridster-item>
|
||||||
</gridster>
|
</gridster>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -17,6 +17,10 @@ import { BubbleRunnerComponent } from './bubble-runner/bubble-runner.component';
|
|||||||
import { ScatterRunnerComponent } from './scatter-runner/scatter-runner.component';
|
import { ScatterRunnerComponent } from './scatter-runner/scatter-runner.component';
|
||||||
import { PolarRunnerComponent } from './polar-runner/polar-runner.component';
|
import { PolarRunnerComponent } from './polar-runner/polar-runner.component';
|
||||||
import { RadarRunnerComponent } from './radar-runner/radar-runner.component';
|
import { RadarRunnerComponent } from './radar-runner/radar-runner.component';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add CompactFilterRunnerComponent import
|
||||||
|
import { CompactFilterRunnerComponent } from './compact-filter-runner/compact-filter-runner.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashrunnerline',
|
selector: 'app-dashrunnerline',
|
||||||
@ -44,10 +48,13 @@ export class DashrunnerlineComponent implements OnInit {
|
|||||||
{ name: "Radar Chart", componentInstance: RadarRunnerComponent },
|
{ name: "Radar Chart", componentInstance: RadarRunnerComponent },
|
||||||
{ name: "Grid View", componentInstance: GridRunnerComponent },
|
{ name: "Grid View", componentInstance: GridRunnerComponent },
|
||||||
{ name: "To Do Chart", componentInstance: TodoRunnerComponent },
|
{ name: "To Do Chart", componentInstance: TodoRunnerComponent },
|
||||||
|
{ name: "Compact Filter", componentInstance: CompactFilterRunnerComponent }, // Add Compact Filter Runner
|
||||||
];
|
];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService, private dashboardService: Dashboard3Service,private route: ActivatedRoute,
|
constructor(private Dashtestservive:DashrunnerService, private dashboardService: Dashboard3Service,private route: ActivatedRoute,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
@ -288,4 +295,48 @@ dashboard_name = "Dashtest";
|
|||||||
console.log('Button clicked in SomeComponent');
|
console.log('Button clicked in SomeComponent');
|
||||||
// Add your custom logic here when the button is clicked in SomeComponent
|
// Add your custom logic here when the button is clicked in SomeComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to provide inputs for dynamic components based on their type
|
||||||
|
getComponentInputs(item: any): any {
|
||||||
|
const inputs: any = {};
|
||||||
|
|
||||||
|
// Common inputs for all components
|
||||||
|
if (item.table !== undefined) inputs.table = item.table;
|
||||||
|
if (item.xAxis !== undefined) inputs.xAxis = item.xAxis;
|
||||||
|
if (item.yAxis !== undefined) inputs.yAxis = item.yAxis;
|
||||||
|
if (item.connection !== undefined) inputs.connection = item.connection;
|
||||||
|
if (item.charttitle !== undefined) inputs.charttitle = item.charttitle;
|
||||||
|
if (item.chartlegend !== undefined) inputs.chartlegend = item.chartlegend;
|
||||||
|
if (item.showlabel !== undefined) inputs.showlabel = item.showlabel;
|
||||||
|
|
||||||
|
// Compact Filter specific inputs
|
||||||
|
if (item.name === 'Compact Filter') {
|
||||||
|
if (item.filterKey !== undefined) inputs.filterKey = item.filterKey;
|
||||||
|
if (item.filterType !== undefined) inputs.filterType = item.filterType;
|
||||||
|
if (item.filterLabel !== undefined) inputs.filterLabel = item.filterLabel;
|
||||||
|
if (item.filterOptions !== undefined) inputs.filterOptions = item.filterOptions;
|
||||||
|
if (item.table !== undefined) inputs.apiUrl = item.table; // Use table as API URL for compact filter
|
||||||
|
if (item.connection !== undefined) inputs.connection = item.connection ? parseInt(item.connection, 10) : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grid View specific inputs
|
||||||
|
if (item.name === 'Grid View') {
|
||||||
|
if (item.baseFilters !== undefined) inputs.baseFilters = item.baseFilters;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chart specific inputs
|
||||||
|
if (item.name.includes('Chart') && item.name !== 'Compact Filter') {
|
||||||
|
if (item.baseFilters !== undefined) inputs.baseFilters = item.baseFilters;
|
||||||
|
if (item.drilldownEnabled !== undefined) inputs.drilldownEnabled = item.drilldownEnabled;
|
||||||
|
if (item.drilldownApiUrl !== undefined) inputs.drilldownApiUrl = item.drilldownApiUrl;
|
||||||
|
if (item.drilldownXAxis !== undefined) inputs.drilldownXAxis = item.drilldownXAxis;
|
||||||
|
if (item.drilldownYAxis !== undefined) inputs.drilldownYAxis = item.drilldownYAxis;
|
||||||
|
if (item.drilldownParameter !== undefined) inputs.drilldownParameter = item.drilldownParameter;
|
||||||
|
if (item.drilldownFilters !== undefined) inputs.drilldownFilters = item.drilldownFilters;
|
||||||
|
if (item.drilldownLayers !== undefined) inputs.drilldownLayers = item.drilldownLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Component inputs for', item.name, ':', inputs);
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import { ChartDataset, ChartType, } from 'chart.js';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-doughnut-runner',
|
selector: 'app-doughnut-runner',
|
||||||
@ -33,10 +37,16 @@ export class DoughnutRunnerComponent implements OnInit {
|
|||||||
"chartLabels": ["Project", "Repository", "Wireframe"]
|
"chartLabels": ["Project", "Repository", "Wireframe"]
|
||||||
}
|
}
|
||||||
doughnutChartType: ChartType = 'doughnut';
|
doughnutChartType: ChartType = 'doughnut';
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.doughnutChartData = this.doughnutData.chartData;
|
this.doughnutChartData = this.doughnutData.chartData;
|
||||||
this.doughnutChartLabels = this.doughnutData.chartLabels;
|
this.doughnutChartLabels = this.doughnutData.chartLabels;
|
||||||
@ -44,6 +54,14 @@ export class DoughnutRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
this.workflowLine = data.dashbord1_Line[0].model;
|
this.workflowLine = data.dashbord1_Line[0].model;
|
||||||
@ -70,22 +88,62 @@ export class DoughnutRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.doughnutChartLegend = ChartObject[i].chartlegend;
|
this.doughnutChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Doughnut Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.doughnutChartData = this.JsonData.chartData;
|
|
||||||
this.doughnutChartLabels = this.JsonData.chartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('DoughnutRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Doughnut Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.doughnutChartData = this.JsonData.chartData;
|
||||||
|
this.doughnutChartLabels = this.JsonData.chartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
// this.buttonClicked.emit();
|
// this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -94,6 +152,19 @@ export class DoughnutRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('DoughnutRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('DoughnutRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -39,16 +39,35 @@
|
|||||||
</div> -->
|
</div> -->
|
||||||
<div><button class="btn btn-primary" (click)="generatePDFFile()">Export</button></div>
|
<div><button class="btn btn-primary" (click)="generatePDFFile()">Export</button></div>
|
||||||
<div style="max-height: 400px; overflow: auto; padding: 10px;">
|
<div style="max-height: 400px; overflow: auto; padding: 10px;">
|
||||||
<table class="table">
|
<!-- Debug information -->
|
||||||
|
<div *ngIf="false" style="background-color: #f0f0f0; padding: 10px; margin-bottom: 10px;">
|
||||||
|
<h4>Debug Information</h4>
|
||||||
|
<p><strong>TableName:</strong> {{ TableName }}</p>
|
||||||
|
<p><strong>XAxis:</strong> {{ XAxis }}</p>
|
||||||
|
<p><strong>YAxis:</strong> {{ YAxis }}</p>
|
||||||
|
<p><strong>Rows:</strong> {{ rows?.length }} items</p>
|
||||||
|
<p><strong>Headers:</strong> {{ getHeaders() | json }}</p>
|
||||||
|
<div *ngIf="error"><strong>Error:</strong> {{ error }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="error" class="error_mess">
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table" *ngIf="rows && rows.length > 0; else noData">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th *ngFor="let co of getHeaders();let i=index">{{co}}</th>
|
<th *ngFor="let co of getHeaders();let i=index">{{co}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let item of rows?.slice()?.reverse()">
|
<tr *ngFor="let item of rows">
|
||||||
<td *ngFor="let key of getHeaders()">{{item[key]}}</td>
|
<td *ngFor="let key of getHeaders()">{{item[key]}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<ng-template #noData>
|
||||||
|
<p *ngIf="!error">No data available</p>
|
||||||
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
@ -3,6 +3,10 @@ import { DashrunnerService } from '../dashrunner.service';
|
|||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-grid-runner',
|
selector: 'app-grid-runner',
|
||||||
@ -26,86 +30,191 @@ export class GridRunnerComponent implements OnInit {
|
|||||||
public DashtestboardArray: DashboardContentModel[] = [];
|
public DashtestboardArray: DashboardContentModel[] = [];
|
||||||
workflowLine;
|
workflowLine;
|
||||||
TableName;
|
TableName;
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
private Dashtestservive:DashrunnerService,
|
||||||
private router : Router
|
private route: ActivatedRoute,
|
||||||
|
private dashboardService: Dashboard3Service,
|
||||||
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log('GridRunner: Component initialized with editId:', this.editId);
|
||||||
// this.getbyId();
|
// this.getbyId();
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
// Subscribe to filter changes
|
||||||
console.log(data);
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
console.log('GridRunner: Filter state changed:', filters);
|
||||||
|
// When filters change, refresh the grid data
|
||||||
|
this.fetchGridData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.dashboardService.getById(this.editId).subscribe((data) => {
|
||||||
|
console.log('GridRunner: Received dashboard data:', data);
|
||||||
this.workflowLine = data.dashbord1_Line[0].model;
|
this.workflowLine = data.dashbord1_Line[0].model;
|
||||||
const dash = JSON.parse(this.workflowLine) ;
|
const dash = JSON.parse(this.workflowLine);
|
||||||
// this.DashtestboardArray = dash.dashboard;
|
// this.DashtestboardArray = dash.dashboard;
|
||||||
// console.log(this.DashtestboardArray);
|
// console.log(this.DashtestboardArray);
|
||||||
|
|
||||||
const ChartObject = dash.dashboard.filter(obj => obj.name === "Grid View");
|
const ChartObject = dash.dashboard.filter(obj => obj.name === "Grid View");
|
||||||
console.log(ChartObject);
|
console.log('GridRunner: ChartObject for Grid View:', ChartObject);
|
||||||
for (let i = 0; i < ChartObject.length; i++) {
|
for (let i = 0; i < ChartObject.length; i++) {
|
||||||
const ids = this.Dashtestservive.getgridview();
|
const ids = this.Dashtestservive.getgridview();
|
||||||
|
console.log('GridRunner: Current gridview ids:', ids);
|
||||||
|
console.log('GridRunner: Checking chartid:', ChartObject[i].chartid);
|
||||||
// console.log(ids);
|
// console.log(ids);
|
||||||
if (ids.includes(ChartObject[i].chartid)) {
|
if (ids.includes(ChartObject[i].chartid)) {
|
||||||
// If the chartid is already in the ids array, continue to the next iteration
|
// If the chartid is already in the ids array, continue to the next iteration
|
||||||
|
console.log('GridRunner: Skipping chartid as it already exists:', ChartObject[i].chartid);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
console.log('GridRunner: Adding new chartid:', ChartObject[i].chartid);
|
||||||
this.Dashtestservive.setgridview(ChartObject[i].chartid);
|
this.Dashtestservive.setgridview(ChartObject[i].chartid);
|
||||||
const id = ids[i];
|
|
||||||
console.log(id);
|
|
||||||
|
|
||||||
if (ChartObject[i].chartid === id) {
|
|
||||||
this.TableName = ChartObject[i].table;
|
this.TableName = ChartObject[i].table;
|
||||||
this.XAxis = ChartObject[i].xAxis;
|
this.XAxis = ChartObject[i].xAxis;
|
||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
console.log(this.TableName);
|
// Add connection ID if available
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Grid View",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
this.ConnectionId = ChartObject[i].connection;
|
||||||
console.log(Ldata);
|
console.log('GridRunner: TableName:', this.TableName);
|
||||||
this.rows = Ldata;
|
console.log('GridRunner: XAxis:', this.XAxis);
|
||||||
this.rowdata = this.rows
|
console.log('GridRunner: YAxis:', this.YAxis);
|
||||||
|
console.log('GridRunner: ConnectionId:', this.ConnectionId);
|
||||||
},(error) => {
|
// Fetch data with filters
|
||||||
console.log(error);
|
this.fetchGridData();
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}, (error) => {
|
||||||
|
console.log('GridRunner: Error fetching dashboard data:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch grid data with filter support
|
||||||
|
fetchGridData(): void {
|
||||||
|
console.log('fetching grid data ...')
|
||||||
|
if (this.TableName) {
|
||||||
|
console.log('GridRunner: Fetching data for TableName:', this.TableName, 'XAxis:', this.XAxis, 'YAxis:', this.YAxis);
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
//dynamic table
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
getTableData(id){
|
if (filterDef && filterDef.field) {
|
||||||
}
|
const fieldName = filterDef.field;
|
||||||
getHeaders() {
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
let headers: string[] = [];
|
filterObj[fieldName] = filterValue;
|
||||||
if(this.rows) {
|
}
|
||||||
this.rows.forEach((value) => {
|
}
|
||||||
Object.keys(value).forEach((key) => {
|
});
|
||||||
if(!headers.find((header) => header == key)){
|
|
||||||
headers.push(key)
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
console.log('GridRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
})
|
// Fetch data from the dashboard service with filters
|
||||||
}
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "grid", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
return headers;
|
console.log('GridRunner: Received data from API:', Ldata);
|
||||||
}
|
|
||||||
|
|
||||||
generatePDFFile(){
|
// Handle the actual data structure returned by the API
|
||||||
|
if (Ldata && Ldata.chartData) {
|
||||||
|
this.rows = Ldata.chartData;
|
||||||
|
this.rowdata = this.rows;
|
||||||
|
} else if (Ldata && Ldata.data) {
|
||||||
|
// Handle the original expected format as fallback
|
||||||
|
this.rows = Ldata.data;
|
||||||
|
this.rowdata = this.rows;
|
||||||
|
} else if (Array.isArray(Ldata)) {
|
||||||
|
// Handle case where data is directly an array
|
||||||
|
this.rows = Ldata;
|
||||||
|
this.rowdata = this.rows;
|
||||||
|
} else {
|
||||||
|
console.warn('GridRunner: Received data does not have expected structure', Ldata);
|
||||||
|
this.rows = [];
|
||||||
|
this.rowdata = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log the structure of the received data
|
||||||
|
if (this.rows) {
|
||||||
|
console.log('GridRunner: Rows length:', this.rows.length);
|
||||||
|
if (this.rows.length > 0) {
|
||||||
|
console.log('GridRunner: First row structure:', this.rows[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('GridRunner: No data received');
|
||||||
|
}
|
||||||
|
}, (error) => {
|
||||||
|
console.log('GridRunner: Error fetching data:', error);
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('GridRunner: Missing TableName or XAxis');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//dynamic table
|
||||||
|
|
||||||
|
|
||||||
|
getTableData(id) {
|
||||||
|
}
|
||||||
|
getHeaders() {
|
||||||
|
let headers: string[] = [];
|
||||||
|
if (this.rows) {
|
||||||
|
console.log('GridRunner: Getting headers from rows:', this.rows);
|
||||||
|
this.rows.forEach((value) => {
|
||||||
|
Object.keys(value).forEach((key) => {
|
||||||
|
if (!headers.find((header) => header == key)) {
|
||||||
|
headers.push(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
console.log('GridRunner: Computed headers:', headers);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
generatePDFFile() {
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
const filename = 'gridview.pdf'; // You can provide any desired filename here
|
const filename = 'gridview.pdf'; // You can provide any desired filename here
|
||||||
|
|
||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('GridRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('GridRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,10 @@ import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
|||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
import { jsPDF } from 'jspdf';
|
import { jsPDF } from 'jspdf';
|
||||||
import domtoimage from 'dom-to-image';
|
import domtoimage from 'dom-to-image';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-line-runner',
|
selector: 'app-line-runner',
|
||||||
templateUrl: './line-runner.component.html',
|
templateUrl: './line-runner.component.html',
|
||||||
@ -54,8 +58,14 @@ export class LineRunnerComponent implements OnInit {
|
|||||||
lineChartLegend = false;
|
lineChartLegend = false;
|
||||||
lineChartPlugins = [];
|
lineChartPlugins = [];
|
||||||
lineChartType = 'line';
|
lineChartType = 'line';
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
||||||
@ -65,6 +75,13 @@ export class LineRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -92,16 +109,10 @@ export class LineRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.lineChartLegend = ChartObject[i].chartlegend;
|
this.lineChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Line Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.lineChartData = this.JsonData.chartData;
|
|
||||||
this.lineChartLabels = this.JsonData.chartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,6 +139,52 @@ export class LineRunnerComponent implements OnInit {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('LineRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Line Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.lineChartData = this.JsonData.chartData;
|
||||||
|
this.lineChartLabels = this.JsonData.chartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -166,4 +223,17 @@ export class LineRunnerComponent implements OnInit {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('LineRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('LineRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,6 +3,10 @@ import { DashrunnerService } from '../dashrunner.service';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -23,9 +27,15 @@ export class PieRunnerComponent implements OnInit {
|
|||||||
showlabel;
|
showlabel;
|
||||||
JsonData;
|
JsonData;
|
||||||
lineChartNoLabels: any[] = [];
|
lineChartNoLabels: any[] = [];
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
public pieChartLabels: string[] = ['SciFi', 'Drama', 'Comedy'];
|
public pieChartLabels: string[] = ['SciFi', 'Drama', 'Comedy'];
|
||||||
public pieChartData: number[] = [30, 50, 20];
|
public pieChartData: number[] = [30, 50, 20];
|
||||||
@ -39,6 +49,13 @@ export class PieRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -66,22 +83,62 @@ export class PieRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.ChartLegend = ChartObject[i].chartlegend;
|
this.ChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Pie Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.pieChartData = this.JsonData.pieChartData;
|
|
||||||
this.pieChartLabels = this.JsonData.pieChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('PieRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Pie Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.pieChartData = this.JsonData.pieChartData;
|
||||||
|
this.pieChartLabels = this.JsonData.pieChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -89,4 +146,17 @@ export class PieRunnerComponent implements OnInit {
|
|||||||
|
|
||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('PieRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('PieRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,10 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
// import { Label } from 'ng2-charts';
|
// import { Label } from 'ng2-charts';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-polar-runner',
|
selector: 'app-polar-runner',
|
||||||
@ -23,9 +27,15 @@ export class PolarRunnerComponent implements OnInit {
|
|||||||
showlabel;
|
showlabel;
|
||||||
JsonData;
|
JsonData;
|
||||||
lineChartNoLabels: any[] = [];
|
lineChartNoLabels: any[] = [];
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
public polarAreaChartLabels: string[] = [ 'Download Sales', 'In-Store Sales', 'Mail Sales', 'Telesales', 'Corporate Sales' ];
|
public polarAreaChartLabels: string[] = [ 'Download Sales', 'In-Store Sales', 'Mail Sales', 'Telesales', 'Corporate Sales' ];
|
||||||
public polarAreaChartData: any = [
|
public polarAreaChartData: any = [
|
||||||
@ -41,6 +51,13 @@ export class PolarRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -66,22 +83,62 @@ export class PolarRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.ChartLegend = ChartObject[i].chartlegend;
|
this.ChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"PolarArea Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.polarAreaChartData = this.JsonData.polarAreaChartData;
|
|
||||||
this.polarAreaChartLabels = this.JsonData.polarAreaChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('PolarRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "PolarArea Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.polarAreaChartData = this.JsonData.polarAreaChartData;
|
||||||
|
this.polarAreaChartLabels = this.JsonData.polarAreaChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -90,4 +147,17 @@ export class PolarRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('PolarRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('PolarRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,10 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
// import { Label } from 'ng2-charts';
|
// import { Label } from 'ng2-charts';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-radar-runner',
|
selector: 'app-radar-runner',
|
||||||
@ -24,9 +28,15 @@ export class RadarRunnerComponent implements OnInit {
|
|||||||
JsonData;
|
JsonData;
|
||||||
lineChartNoLabels: any[] = [];
|
lineChartNoLabels: any[] = [];
|
||||||
ChartLegend = false;
|
ChartLegend = false;
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
public radarChartLabels: string[] = [
|
public radarChartLabels: string[] = [
|
||||||
"Eating",
|
"Eating",
|
||||||
@ -50,6 +60,13 @@ export class RadarRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -75,22 +92,62 @@ export class RadarRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.ChartLegend = ChartObject[i].chartlegend;
|
this.ChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Radar Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.radarChartData = this.JsonData.radarChartData;
|
|
||||||
this.radarChartLabels = this.JsonData.radarChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('RadarRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Radar Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.radarChartData = this.JsonData.radarChartData;
|
||||||
|
this.radarChartLabels = this.JsonData.radarChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -99,4 +156,17 @@ export class RadarRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('RadarRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('RadarRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,10 @@ import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
|||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
// import { Label } from 'ng2-charts';
|
// import { Label } from 'ng2-charts';
|
||||||
import { ChartDataset } from 'chart.js';
|
import { ChartDataset } from 'chart.js';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-scatter-runner',
|
selector: 'app-scatter-runner',
|
||||||
@ -25,9 +29,15 @@ export class ScatterRunnerComponent implements OnInit {
|
|||||||
JsonData;
|
JsonData;
|
||||||
lineChartNoLabels: any[] = [];
|
lineChartNoLabels: any[] = [];
|
||||||
ChartLegend = false;
|
ChartLegend = false;
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
constructor(private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
private router : Router,) { }
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
public scatterChartLabels: string[] = [ 'Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running' ];
|
public scatterChartLabels: string[] = [ 'Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running' ];
|
||||||
|
|
||||||
@ -69,6 +79,13 @@ export class ScatterRunnerComponent implements OnInit {
|
|||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the chart data
|
||||||
|
this.fetchChartData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
@ -94,22 +111,62 @@ export class ScatterRunnerComponent implements OnInit {
|
|||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
this.showlabel = ChartObject[i].showlabel;
|
this.showlabel = ChartObject[i].showlabel;
|
||||||
this.ChartLegend = ChartObject[i].chartlegend;
|
this.ChartLegend = ChartObject[i].chartlegend;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Scatter Chart",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchChartData();
|
||||||
this.JsonData = Ldata;
|
|
||||||
this.scatterChartData = this.JsonData.scatterChartData;
|
|
||||||
this.scatterChartLabels = this.JsonData.scatterChartLabels;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch chart data with filter support
|
||||||
|
fetchChartData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Convert YAxis to string if it's an array
|
||||||
|
const yAxisString = Array.isArray(this.YAxis) ? this.YAxis.join(',') : this.YAxis;
|
||||||
|
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
const filterDefinitions = this.filterService.getFilters();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('ScatterRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Scatter Chart", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.JsonData = Ldata;
|
||||||
|
this.scatterChartData = this.JsonData.scatterChartData;
|
||||||
|
this.scatterChartLabels = this.JsonData.scatterChartLabels;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
generatePDFFile(){
|
generatePDFFile(){
|
||||||
this.buttonClicked.emit();
|
this.buttonClicked.emit();
|
||||||
const content = this.contentContainerRef.nativeElement;
|
const content = this.contentContainerRef.nativeElement;
|
||||||
@ -118,4 +175,17 @@ export class ScatterRunnerComponent implements OnInit {
|
|||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('ScatterRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('ScatterRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,10 @@ import { DashrunnerService } from '../dashrunner.service';
|
|||||||
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
import { DashboardContentModel } from 'src/app/models/builder/dashboard';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
||||||
|
// Add FilterService import
|
||||||
|
import { FilterService } from '../../../dashboardnew/common-filter/filter.service';
|
||||||
|
// Add Subscription import
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-todo-runner',
|
selector: 'app-todo-runner',
|
||||||
@ -12,8 +16,9 @@ import { Dashboard3Service } from 'src/app/services/builder/dashboard3.service';
|
|||||||
export class TodoRunnerComponent implements OnInit {
|
export class TodoRunnerComponent implements OnInit {
|
||||||
@ViewChild('contentContainer') contentContainerRef!: ElementRef;
|
@ViewChild('contentContainer') contentContainerRef!: ElementRef;
|
||||||
@Output() buttonClicked = new EventEmitter<void>();
|
@Output() buttonClicked = new EventEmitter<void>();
|
||||||
constructor( private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
|
||||||
private router : Router) { }
|
// Add subscriptions to unsubscribe on destroy
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
givendata;
|
givendata;
|
||||||
@ -25,6 +30,7 @@ export class TodoRunnerComponent implements OnInit {
|
|||||||
public DashtestboardArray: DashboardContentModel[] = [];
|
public DashtestboardArray: DashboardContentModel[] = [];
|
||||||
workflowLine;
|
workflowLine;
|
||||||
TableName;
|
TableName;
|
||||||
|
ConnectionId: number; // Add ConnectionId property
|
||||||
|
|
||||||
list;
|
list;
|
||||||
data: any;
|
data: any;
|
||||||
@ -34,11 +40,25 @@ export class TodoRunnerComponent implements OnInit {
|
|||||||
listName: "title123",
|
listName: "title123",
|
||||||
List:['todo 1','todo 2'],
|
List:['todo 1','todo 2'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor( private Dashtestservive:DashrunnerService,private route: ActivatedRoute,private dashboardService: Dashboard3Service,
|
||||||
|
private router : Router,
|
||||||
|
// Add FilterService to constructor
|
||||||
|
private filterService: FilterService) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.editId = this.route.snapshot.params.id;
|
this.editId = this.route.snapshot.params.id;
|
||||||
console.log(this.editId);
|
console.log(this.editId);
|
||||||
// this.getbyId();
|
// this.getbyId();
|
||||||
|
|
||||||
|
// Subscribe to filter changes
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.filterService.filterState$.subscribe(filters => {
|
||||||
|
// When filters change, refresh the todo data
|
||||||
|
this.fetchTodoData();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
this.dashboardService.getById(this.editId).subscribe((data)=>{
|
||||||
console.log(data);
|
console.log(data);
|
||||||
this.workflowLine = data.dashbord1_Line[0].model;
|
this.workflowLine = data.dashbord1_Line[0].model;
|
||||||
@ -63,15 +83,10 @@ export class TodoRunnerComponent implements OnInit {
|
|||||||
this.TableName = ChartObject[i].table;
|
this.TableName = ChartObject[i].table;
|
||||||
this.XAxis = ChartObject[i].xAxis;
|
this.XAxis = ChartObject[i].xAxis;
|
||||||
this.YAxis = ChartObject[i].yAxis;
|
this.YAxis = ChartObject[i].yAxis;
|
||||||
|
this.ConnectionId = ChartObject[i].connection; // Add connection ID
|
||||||
console.log(this.TableName);
|
console.log(this.TableName);
|
||||||
this.Dashtestservive.getChartData(this.TableName,"Todo List",this.XAxis,this.YAxis).subscribe((Ldata) => {
|
// Fetch data with filters
|
||||||
console.log(Ldata);
|
this.fetchTodoData();
|
||||||
this.todoList.listName = Ldata.listName;
|
|
||||||
this.todoList.List = Ldata.List;
|
|
||||||
|
|
||||||
},(error) => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
break; // No need to continue the loop once the correct placeholder is found
|
break; // No need to continue the loop once the correct placeholder is found
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,4 +115,58 @@ generatePDFFile(){
|
|||||||
|
|
||||||
this.Dashtestservive.generatePDF(content, filename);
|
this.Dashtestservive.generatePDF(content, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch todo data with filter support
|
||||||
|
fetchTodoData(): void {
|
||||||
|
if (this.TableName && this.XAxis && this.YAxis) {
|
||||||
|
// Get filter parameters from common filters
|
||||||
|
const commonFilters = this.filterService.getFilterValues();
|
||||||
|
|
||||||
|
// Build filter object using field names as keys
|
||||||
|
const filterObj = {};
|
||||||
|
Object.keys(commonFilters).forEach(filterId => {
|
||||||
|
const filterValue = commonFilters[filterId];
|
||||||
|
|
||||||
|
// Find the filter definition to get the field name
|
||||||
|
const filterDef = this.filterService.getFilters().find(f => f.id === filterId);
|
||||||
|
|
||||||
|
if (filterDef && filterDef.field) {
|
||||||
|
const fieldName = filterDef.field;
|
||||||
|
if (filterValue !== undefined && filterValue !== null && filterValue !== '') {
|
||||||
|
filterObj[fieldName] = filterValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert to JSON string for API call
|
||||||
|
let filterParams = '';
|
||||||
|
if (Object.keys(filterObj).length > 0) {
|
||||||
|
filterParams = JSON.stringify(filterObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('TodoRunner: Final filter object to send to API:', filterObj);
|
||||||
|
|
||||||
|
// Fetch data from the dashboard service with filters
|
||||||
|
this.Dashtestservive.getChartDataWithFilters(this.TableName, "Todo List", this.XAxis, this.YAxis, this.ConnectionId, '', '', filterParams).subscribe((Ldata) => {
|
||||||
|
console.log(Ldata);
|
||||||
|
this.todoList.listName = Ldata.listName;
|
||||||
|
this.todoList.List = Ldata.List;
|
||||||
|
},(error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
// Unsubscribe from all subscriptions to prevent memory leaks
|
||||||
|
console.log('TodoRunnerComponent ngOnDestroy called, unsubscribing from', this.subscriptions.length, 'subscriptions');
|
||||||
|
this.subscriptions.forEach(subscription => {
|
||||||
|
if (subscription && !subscription.closed) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.subscriptions = [];
|
||||||
|
|
||||||
|
console.log('TodoRunnerComponent destroyed and cleaned up');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user