5 Commits

Author SHA1 Message Date
Gaurav Kumar
82425d5377 Update editnewdash.component.html 2025-10-28 12:13:15 +05:30
Gaurav Kumar
2995328ec1 compact filter 2025-10-27 20:36:22 +05:30
Gaurav Kumar
afc2c1f8a1 filter with runner 2025-10-27 20:12:22 +05:30
Gaurav Kumar
418b02acd7 checkbox multislect filter, in edit new dash 2025-10-27 19:02:47 +05:30
Gaurav Kumar
cdd752469c builder 2025-10-27 18:48:16 +05:30
9 changed files with 981 additions and 559 deletions

View File

@@ -79,12 +79,16 @@
<!-- Multi-Select Filter --> <!-- Multi-Select Filter -->
<div class="filter-control" *ngIf="filterType === 'multiselect'"> <div class="filter-control" *ngIf="filterType === 'multiselect'">
<select [(ngModel)]="filterValue" <div class="compact-multiselect-checkboxes" style="max-height: 200px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;">
(ngModelChange)="onFilterValueChange($event)" <div *ngFor="let option of filterOptions" class="clr-checkbox-wrapper" style="margin-bottom: 5px;">
multiple <input type="checkbox"
class="clr-select compact-multiselect"> [id]="'multiselect-' + option"
<option *ngFor="let option of filterOptions" [value]="option">{{ option }}</option> [value]="option"
</select> [checked]="isOptionSelected(option)"
(change)="onMultiselectOptionChange($event, option)">
<label [for]="'multiselect-' + option" class="clr-control-label">{{ option }}</label>
</div>
</div>
</div> </div>
<!-- Date Range Filter --> <!-- Date Range Filter -->

View File

@@ -331,4 +331,48 @@ export class CompactFilterComponent implements OnInit, OnChanges {
this.loadAvailableValues(this.configFilterKey); this.loadAvailableValues(this.configFilterKey);
} }
} }
// Add method to check if an option is selected for checkboxes
isOptionSelected(option: string): boolean {
if (!this.filterValue) {
return false;
}
// Ensure filterValue is an array for multiselect
if (!Array.isArray(this.filterValue)) {
this.filterValue = [];
return false;
}
return this.filterValue.includes(option);
}
// need to check this
// Add method to handle multiselect option change
onMultiselectOptionChange(event: any, option: string): void {
// Initialize filterValue array if it doesn't exist
if (!this.filterValue) {
this.filterValue = [];
}
// Ensure filterValue is an array
if (!Array.isArray(this.filterValue)) {
this.filterValue = [];
}
if (event.target.checked) {
// Add option if not already in array
if (!this.filterValue.includes(option)) {
this.filterValue.push(option);
}
} else {
// Remove option from array
const index = this.filterValue.indexOf(option);
if (index > -1) {
this.filterValue.splice(index, 1);
}
}
// Emit the change event
this.onFilterValueChange(this.filterValue);
}
} }

View File

@@ -90,11 +90,106 @@
</div> </div>
</div> </div>
<!-- Compact Filter Configuration (shown only for Compact Filter components) -->
<div class="clr-row" *ngIf="gadgetsEditdata?.fieldName === 'Compact Filter'">
<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="clr-row" *ngIf="gadgetsEditdata?.fieldName !== 'Compact Filter'"
style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
<!-- Add Connection Selection Field --> <!-- Add Connection Selection Field -->
<div class="clr-row"> <div class="clr-row">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="connection">Connection</label> <label for="connection">Connection</label>
<select id="connection" formControlName="connection" [(ngModel)]="gadgetsEditdata.connection" class="clr-select"> <select id="connection" formControlName="connection" [(ngModel)]="gadgetsEditdata.connection"
class="clr-select">
<option value="">Select Connection</option> <option value="">Select Connection</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id"> <option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.connection_name || conn.id}} {{conn.connection_name || conn.id}}
@@ -149,8 +244,8 @@
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="table">Api Url</label> <label for="table">Api Url</label>
<div><input type="urk" id="table" formControlName="table" class="clr-input" <div><input type="urk" id="table" formControlName="table" class="clr-input"
[(ngModel)]="gadgetsEditdata.table" style="width:90%">&nbsp;<span><button class="btn btn-icon btn-primary" [(ngModel)]="gadgetsEditdata.table" style="width:90%">&nbsp;<span><button
style="margin: 0px;" (click)="callApi(gadgetsEditdata.table)"> class="btn btn-icon btn-primary" style="margin: 0px;" (click)="callApi(gadgetsEditdata.table)">
<clr-icon shape="redo"></clr-icon> </button></span></div> <clr-icon shape="redo"></clr-icon> </button></span></div>
<!-- <select id="table" formControlName="table" [(ngModel)]="gadgetsEditdata.table" (change)="tablename($event.target.value)"> <!-- <select id="table" formControlName="table" [(ngModel)]="gadgetsEditdata.table" (change)="tablename($event.target.value)">
<option value="null">choose Table</option> <option value="null">choose Table</option>
@@ -223,8 +318,8 @@
</div> </div>
<!-- Add Base Filter Button --> <!-- Add Base Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addBaseFilter()" style="margin-top: 10px; margin-bottom: 10px;" <button class="btn btn-sm btn-primary" (click)="addBaseFilter()"
[disabled]="gadgetsEditdata.commonFilterEnabled"> style="margin-top: 10px; margin-bottom: 10px;" [disabled]="gadgetsEditdata.commonFilterEnabled">
<clr-icon shape="plus"></clr-icon> Add Filter <clr-icon shape="plus"></clr-icon> Add Filter
</button> </button>
@@ -245,14 +340,14 @@
[disabled]="gadgetsEditdata.commonFilterEnabled"> [disabled]="gadgetsEditdata.commonFilterEnabled">
<option value="">Select Field</option> <option value="">Select Field</option>
<!-- Base API filters should always use columnData, not drilldownColumnData --> <!-- Base API filters should always use columnData, not drilldownColumnData -->
<option *ngFor="let column of getAvailableFields(gadgetsEditdata.baseFilters, i, columnData)" [value]="column">{{column}}</option> <option *ngFor="let column of getAvailableFields(gadgetsEditdata.baseFilters, i, columnData)"
[value]="column">{{column}}</option>
</select> </select>
</div> </div>
<div class="clr-col-sm-5"> <div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" <input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" class="clr-input"
class="clr-input" placeholder="Filter Value" placeholder="Filter Value" [disabled]="gadgetsEditdata.commonFilterEnabled" />
[disabled]="gadgetsEditdata.commonFilterEnabled"/>
</div> </div>
<div class="clr-col-sm-2"> <div class="clr-col-sm-2">
@@ -288,22 +383,25 @@
<label for="drilldownApiUrl">Base Drilldown API URL</label> <label for="drilldownApiUrl">Base Drilldown API URL</label>
<div> <div>
<input type="text" id="drilldownApiUrl" formControlName="drilldownApiUrl" class="clr-input" <input type="text" id="drilldownApiUrl" formControlName="drilldownApiUrl" class="clr-input"
[(ngModel)]="gadgetsEditdata.drilldownApiUrl" style="width:90%" [ngModelOptions]="{standalone: true}">&nbsp; [(ngModel)]="gadgetsEditdata.drilldownApiUrl" style="width:90%"
[ngModelOptions]="{standalone: true}">&nbsp;
<span> <span>
<button class="btn btn-icon btn-primary" style="margin: 0px;" <button class="btn btn-icon btn-primary" style="margin: 0px;" (click)="refreshBaseDrilldownColumns()"
(click)="refreshBaseDrilldownColumns()" [disabled]="!gadgetsEditdata.drilldownApiUrl"> [disabled]="!gadgetsEditdata.drilldownApiUrl">
<clr-icon shape="redo"></clr-icon> <clr-icon shape="redo"></clr-icon>
</button> </button>
</span> </span>
</div> </div>
<div class="clr-subtext">Enter the API URL for base drilldown data. Use angle brackets for parameters, e.g., http://api.example.com/data/&lt;country&gt;</div> <div class="clr-subtext">Enter the API URL for base drilldown data. Use angle brackets for parameters, e.g.,
http://api.example.com/data/&lt;country&gt;</div>
</div> </div>
</div> </div>
<div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled"> <div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="drilldownXAxis">Base Drilldown X-Axis</label> <label for="drilldownXAxis">Base Drilldown X-Axis</label>
<select id="drilldownXAxis" formControlName="drilldownXAxis" [(ngModel)]="gadgetsEditdata.drilldownXAxis" [ngModelOptions]="{standalone: true}"> <select id="drilldownXAxis" formControlName="drilldownXAxis" [(ngModel)]="gadgetsEditdata.drilldownXAxis"
[ngModelOptions]="{standalone: true}">
<option value="">Select X-Axis Column</option> <option value="">Select X-Axis Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option> <option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select> </select>
@@ -317,7 +415,8 @@
gadgetsEditdata?.fieldName !== 'To Do Chart'"> gadgetsEditdata?.fieldName !== 'To Do Chart'">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="drilldownYAxis">Base Drilldown Y-Axis</label> <label for="drilldownYAxis">Base Drilldown Y-Axis</label>
<select id="drilldownYAxis" formControlName="drilldownYAxis" [(ngModel)]="gadgetsEditdata.drilldownYAxis" [ngModelOptions]="{standalone: true}"> <select id="drilldownYAxis" formControlName="drilldownYAxis" [(ngModel)]="gadgetsEditdata.drilldownYAxis"
[ngModelOptions]="{standalone: true}">
<option value="">Select Y-Axis Column</option> <option value="">Select Y-Axis Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option> <option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select> </select>
@@ -329,11 +428,14 @@
<div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled"> <div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="drilldownParameter">Base Drilldown Parameter</label> <label for="drilldownParameter">Base Drilldown Parameter</label>
<select id="drilldownParameter" [(ngModel)]="gadgetsEditdata.drilldownParameter" [ngModelOptions]="{standalone: true}"> <select id="drilldownParameter" [(ngModel)]="gadgetsEditdata.drilldownParameter"
[ngModelOptions]="{standalone: true}">
<option value="">Select Parameter Column</option> <option value="">Select Parameter Column</option>
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option> <option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
</select> </select>
<div class="clr-subtext">Select the column to use as parameter for URL template replacement in base drilldown</div> <div class="clr-subtext">Select the column to use as parameter for URL template replacement in base
drilldown
</div>
</div> </div>
</div> </div>
@@ -347,16 +449,18 @@
<div class="clr-form-control" style="margin-top: 10px;"> <div class="clr-form-control" style="margin-top: 10px;">
<div class="clr-control-container"> <div class="clr-control-container">
<div class="clr-checkbox-wrapper"> <div class="clr-checkbox-wrapper">
<input type="checkbox" id="commonFilterToggleDrilldown" [(ngModel)]="gadgetsEditdata.commonFilterEnabledDrilldown" <input type="checkbox" id="commonFilterToggleDrilldown"
(change)="onCommonFilterToggleDrilldown()" [ngModelOptions]="{standalone: true}" class="clr-checkbox" /> [(ngModel)]="gadgetsEditdata.commonFilterEnabledDrilldown"
(change)="onCommonFilterToggleDrilldown()" [ngModelOptions]="{standalone: true}"
class="clr-checkbox" />
<label for="commonFilterToggleDrilldown" class="clr-control-label">Use Common Filter</label> <label for="commonFilterToggleDrilldown" class="clr-control-label">Use Common Filter</label>
</div> </div>
</div> </div>
</div> </div>
<!-- Add Drilldown Filter Button --> <!-- Add Drilldown Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addDrilldownFilter()" style="margin-top: 10px; margin-bottom: 10px;" <button class="btn btn-sm btn-primary" (click)="addDrilldownFilter()"
[disabled]="gadgetsEditdata.commonFilterEnabledDrilldown"> style="margin-top: 10px; margin-bottom: 10px;" [disabled]="gadgetsEditdata.commonFilterEnabledDrilldown">
<clr-icon shape="plus"></clr-icon> Add Filter <clr-icon shape="plus"></clr-icon> Add Filter
</button> </button>
@@ -376,14 +480,15 @@
<select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select" <select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select"
[disabled]="gadgetsEditdata.commonFilterEnabledDrilldown"> [disabled]="gadgetsEditdata.commonFilterEnabledDrilldown">
<option value="">Select Field</option> <option value="">Select Field</option>
<option *ngFor="let column of getAvailableFields(gadgetsEditdata.drilldownFilters, i, drilldownColumnData)" [value]="column">{{column}}</option> <option
*ngFor="let column of getAvailableFields(gadgetsEditdata.drilldownFilters, i, drilldownColumnData)"
[value]="column">{{column}}</option>
</select> </select>
</div> </div>
<div class="clr-col-sm-5"> <div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" <input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" class="clr-input"
class="clr-input" placeholder="Filter Value" placeholder="Filter Value" [disabled]="gadgetsEditdata.commonFilterEnabledDrilldown" />
[disabled]="gadgetsEditdata.commonFilterEnabledDrilldown"/>
</div> </div>
<div class="clr-col-sm-2"> <div class="clr-col-sm-2">
@@ -400,7 +505,8 @@
<!-- Multi-Layer Drilldown Configurations --> <!-- Multi-Layer Drilldown Configurations -->
<div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;"> <div class="clr-row" *ngIf="gadgetsEditdata.drilldownEnabled"
style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<h4>Multi-Layer Drilldown Configurations</h4> <h4>Multi-Layer Drilldown Configurations</h4>
<button class="btn btn-sm btn-primary" (click)="addDrilldownLayer()"> <button class="btn btn-sm btn-primary" (click)="addDrilldownLayer()">
@@ -412,7 +518,8 @@
<!-- Dynamic Drilldown Layers --> <!-- Dynamic Drilldown Layers -->
<div class="clr-row" *ngFor="let layer of gadgetsEditdata.drilldownLayers; let i = index"> <div class="clr-row" *ngFor="let layer of gadgetsEditdata.drilldownLayers; let i = index">
<div class="clr-col-sm-12" style="margin-top: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px;"> <div class="clr-col-sm-12"
style="margin-top: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px;">
<div style="display: flex; justify-content: space-between; align-items: center;"> <div style="display: flex; justify-content: space-between; align-items: center;">
<h5>Drilldown Layer {{i + 1}}</h5> <h5>Drilldown Layer {{i + 1}}</h5>
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownLayer(i)"> <button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownLayer(i)">
@@ -423,7 +530,8 @@
<div class="clr-form-control"> <div class="clr-form-control">
<div class="clr-control-container"> <div class="clr-control-container">
<div class="clr-checkbox-wrapper"> <div class="clr-checkbox-wrapper">
<input type="checkbox" [id]="'layerEnabled' + i" [(ngModel)]="layer.enabled" class="clr-checkbox" [ngModelOptions]="{standalone: true}" /> <input type="checkbox" [id]="'layerEnabled' + i" [(ngModel)]="layer.enabled" class="clr-checkbox"
[ngModelOptions]="{standalone: true}" />
<label [for]="'layerEnabled' + i" class="clr-control-label">Enable Layer {{i + 1}} Drilldown</label> <label [for]="'layerEnabled' + i" class="clr-control-label">Enable Layer {{i + 1}} Drilldown</label>
</div> </div>
</div> </div>
@@ -433,8 +541,8 @@
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label [for]="'layerApiUrl' + i">Layer {{i + 1}} API URL</label> <label [for]="'layerApiUrl' + i">Layer {{i + 1}} API URL</label>
<div> <div>
<input type="text" [id]="'layerApiUrl' + i" class="clr-input" <input type="text" [id]="'layerApiUrl' + i" class="clr-input" [(ngModel)]="layer.apiUrl"
[(ngModel)]="layer.apiUrl" style="width:90%" [ngModelOptions]="{standalone: true}">&nbsp; style="width:90%" [ngModelOptions]="{standalone: true}">&nbsp;
<span> <span>
<button class="btn btn-icon btn-primary" style="margin: 0px;" <button class="btn btn-icon btn-primary" style="margin: 0px;"
(click)="refreshDrilldownLayerColumns(i)" [disabled]="!layer.apiUrl"> (click)="refreshDrilldownLayerColumns(i)" [disabled]="!layer.apiUrl">
@@ -442,7 +550,8 @@
</button> </button>
</span> </span>
</div> </div>
<div class="clr-subtext">Enter the API URL for layer {{i + 1}} drilldown data. Use angle brackets for parameters, e.g., http://api.example.com/data/&lt;state&gt;</div> <div class="clr-subtext">Enter the API URL for layer {{i + 1}} drilldown data. Use angle brackets for
parameters, e.g., http://api.example.com/data/&lt;state&gt;</div>
</div> </div>
</div> </div>
@@ -478,7 +587,9 @@
<option value="">Select Parameter Column</option> <option value="">Select Parameter Column</option>
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option> <option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
</select> </select>
<div class="clr-subtext">Select the column to use as parameter for URL template replacement in layer {{i + 1}} drilldown</div> <div class="clr-subtext">Select the column to use as parameter for URL template replacement in layer {{i
+
1}} drilldown</div>
</div> </div>
</div> </div>
@@ -492,16 +603,17 @@
<div class="clr-form-control" style="margin-top: 10px;"> <div class="clr-form-control" style="margin-top: 10px;">
<div class="clr-control-container"> <div class="clr-control-container">
<div class="clr-checkbox-wrapper"> <div class="clr-checkbox-wrapper">
<input type="checkbox" [id]="'commonFilterToggleLayer' + i" [(ngModel)]="layer.commonFilterEnabled" <input type="checkbox" [id]="'commonFilterToggleLayer' + i"
(change)="onCommonFilterToggleLayer(i)" [ngModelOptions]="{standalone: true}" class="clr-checkbox" /> [(ngModel)]="layer.commonFilterEnabled" (change)="onCommonFilterToggleLayer(i)"
[ngModelOptions]="{standalone: true}" class="clr-checkbox" />
<label [for]="'commonFilterToggleLayer' + i" class="clr-control-label">Use Common Filter</label> <label [for]="'commonFilterToggleLayer' + i" class="clr-control-label">Use Common Filter</label>
</div> </div>
</div> </div>
</div> </div>
<!-- Add Layer Filter Button --> <!-- Add Layer Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addLayerFilter(i)" style="margin-top: 10px; margin-bottom: 10px;" <button class="btn btn-sm btn-primary" (click)="addLayerFilter(i)"
[disabled]="layer.commonFilterEnabled"> style="margin-top: 10px; margin-bottom: 10px;" [disabled]="layer.commonFilterEnabled">
<clr-icon shape="plus"></clr-icon> Add Filter <clr-icon shape="plus"></clr-icon> Add Filter
</button> </button>
@@ -521,14 +633,14 @@
<select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select" <select [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}" class="clr-select"
[disabled]="layer.commonFilterEnabled"> [disabled]="layer.commonFilterEnabled">
<option value="">Select Field</option> <option value="">Select Field</option>
<option *ngFor="let column of getAvailableFields(layer.filters, j, layerColumnData[i] || [])" [value]="column">{{column}}</option> <option *ngFor="let column of getAvailableFields(layer.filters, j, layerColumnData[i] || [])"
[value]="column">{{column}}</option>
</select> </select>
</div> </div>
<div class="clr-col-sm-5"> <div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" <input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
class="clr-input" placeholder="Filter Value" class="clr-input" placeholder="Filter Value" [disabled]="layer.commonFilterEnabled" />
[disabled]="layer.commonFilterEnabled"/>
</div> </div>
<div class="clr-col-sm-2"> <div class="clr-col-sm-2">
@@ -550,6 +662,9 @@
<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> -->
</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>
@@ -568,7 +683,8 @@
<div class="clr-row"> <div class="clr-row">
<div class="clr-col-sm-12"> <div class="clr-col-sm-12">
<label for="commonFilterConnection">Connection</label> <label for="commonFilterConnection">Connection</label>
<select id="commonFilterConnection" formControlName="connection" [(ngModel)]="commonFilterData.connection" class="clr-select"> <select id="commonFilterConnection" formControlName="connection" [(ngModel)]="commonFilterData.connection"
class="clr-select">
<option value="">Select Connection</option> <option value="">Select Connection</option>
<option *ngFor="let conn of sureconnectData" [value]="conn.id"> <option *ngFor="let conn of sureconnectData" [value]="conn.id">
{{conn.connection_name || conn.id}} {{conn.connection_name || conn.id}}
@@ -584,8 +700,8 @@
<input type="text" id="commonFilterApiUrl" formControlName="apiUrl" class="clr-input" <input type="text" id="commonFilterApiUrl" formControlName="apiUrl" class="clr-input"
[(ngModel)]="commonFilterData.apiUrl" style="width:90%">&nbsp; [(ngModel)]="commonFilterData.apiUrl" style="width:90%">&nbsp;
<span> <span>
<button class="btn btn-icon btn-primary" style="margin: 0px;" <button class="btn btn-icon btn-primary" style="margin: 0px;" (click)="refreshCommonFilterColumns()"
(click)="refreshCommonFilterColumns()" [disabled]="!commonFilterData.apiUrl"> [disabled]="!commonFilterData.apiUrl">
<clr-icon shape="redo"></clr-icon> <clr-icon shape="redo"></clr-icon>
</button> </button>
</span> </span>
@@ -599,7 +715,8 @@
<h5>Common Filters</h5> <h5>Common Filters</h5>
<!-- Add Common Filter Button --> <!-- Add Common Filter Button -->
<button class="btn btn-sm btn-primary" (click)="addCommonFilter()" style="margin-top: 10px; margin-bottom: 10px;"> <button class="btn btn-sm btn-primary" (click)="addCommonFilter()"
style="margin-top: 10px; margin-bottom: 10px;">
<clr-icon shape="plus"></clr-icon> Add Filter <clr-icon shape="plus"></clr-icon> Add Filter
</button> </button>
@@ -622,8 +739,8 @@
</div> </div>
<div class="clr-col-sm-5"> <div class="clr-col-sm-5">
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" <input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}" class="clr-input"
class="clr-input" placeholder="Filter Value" /> placeholder="Filter Value" />
</div> </div>
<div class="clr-col-sm-2"> <div class="clr-col-sm-2">

View File

@@ -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,11 +816,16 @@ 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.table = this.gadgetsEditdata.table || '';
xyz.connection = this.gadgetsEditdata.connection || undefined; xyz.connection = this.gadgetsEditdata.connection || undefined;
} }
@@ -821,7 +865,7 @@ export class EditnewdashComponent implements OnInit {
*/ */
getChartInputs(item: any): any { getChartInputs(item: any): any {
// For CompactFilterComponent, pass only filter configuration properties // For CompactFilterComponent, pass only filter configuration properties
if (item.component && item.component.name === 'CompactFilterComponent') { if (item.name === 'Compact Filter') {
const filterInputs = { const filterInputs = {
filterKey: item['filterKey'] || '', filterKey: item['filterKey'] || '',
filterType: item['filterType'] || 'text', filterType: item['filterType'] || 'text',
@@ -995,11 +1039,16 @@ 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
@@ -1435,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);
}
}
} }

View File

@@ -1,11 +1,13 @@
<!-- Display Mode - No configuration UI in runner -->
<div class="compact-filter"> <div class="compact-filter">
<div class="filter-header"> <div class="filter-header" (click)="toggleFilter()">
<span class="filter-label" *ngIf="filterLabel">{{ filterLabel }}</span> <span class="filter-label" *ngIf="filterLabel">{{ filterLabel }}</span>
<span class="filter-key" *ngIf="!filterLabel && filterKey">{{ filterKey }}</span> <span class="filter-key" *ngIf="!filterLabel && filterKey">{{ filterKey }}</span>
<span class="filter-type">({{ filterType }})</span> <span class="filter-type">({{ filterType }})</span>
<clr-icon shape="caret down" class="expand-icon" *ngIf="!isExpanded"></clr-icon>
<clr-icon shape="caret up" class="expand-icon" *ngIf="isExpanded"></clr-icon>
</div> </div>
<div class="filter-content" *ngIf="isExpanded">
<!-- Text Filter --> <!-- Text Filter -->
<div class="filter-control" *ngIf="filterType === 'text'"> <div class="filter-control" *ngIf="filterType === 'text'">
<input type="text" <input type="text"
@@ -21,36 +23,42 @@
(ngModelChange)="onFilterValueChange($event)" (ngModelChange)="onFilterValueChange($event)"
class="clr-select compact-select"> class="clr-select compact-select">
<option value="">{{ filterLabel || filterKey }}</option> <option value="">{{ filterLabel || filterKey }}</option>
<option *ngFor="let option of filterOptions" [value]="option">{{ option }}</option> <option *ngFor="let option of filterOptions; let i = index" [value]="option">{{ option }}</option>
</select> </select>
</div> </div>
<!-- Multi-Select Filter --> <!-- Multi-Select Filter -->
<div class="filter-control" *ngIf="filterType === 'multiselect'"> <div class="filter-control" *ngIf="filterType === 'multiselect'">
<div class="multiselect-container">
<div class="checkbox-group"> <div class="checkbox-group">
<div *ngFor="let option of filterOptions" class="checkbox-item"> <div *ngFor="let option of filterOptions; let i = index" class="checkbox-item">
<input type="checkbox" <input type="checkbox"
[checked]="filterValue && filterValue.includes(option)" [checked]="isOptionSelected(option)"
(change)="onMultiSelectChange(option, $event)" (change)="onMultiSelectChange(option, $event)"
[id]="'checkbox-' + option"> [id]="'checkbox-' + filterKey + '-' + i"
<label [for]="'checkbox-' + option">{{ option }}</label> class="clr-checkbox">
<label [for]="'checkbox-' + filterKey + '-' + i" class="checkbox-label">{{ option }}</label>
</div>
</div> </div>
</div> </div>
</div> </div>
<!-- Date Range Filter --> <!-- Date Range Filter -->
<div class="filter-control date-range" *ngIf="filterType === 'date-range'"> <div class="filter-control date-range" *ngIf="filterType === 'date-range'">
<div class="date-input-group">
<input type="date" <input type="date"
[(ngModel)]="filterValue.start" [(ngModel)]="filterValue.start"
(ngModelChange)="onDateRangeChange({ start: $event, end: filterValue.end })" (ngModelChange)="onDateRangeChange({ start: $event, end: filterValue.end })"
placeholder="Start Date" placeholder="Start Date"
class="clr-input compact-date"> class="clr-input compact-date">
<span class="date-separator">to</span>
<input type="date" <input type="date"
[(ngModel)]="filterValue.end" [(ngModel)]="filterValue.end"
(ngModelChange)="onDateRangeChange({ start: filterValue.start, end: $event })" (ngModelChange)="onDateRangeChange({ start: filterValue.start, end: $event })"
placeholder="End Date" placeholder="End Date"
class="clr-input compact-date"> class="clr-input compact-date">
</div> </div>
</div>
<!-- Toggle Filter --> <!-- Toggle Filter -->
<div class="filter-control toggle" *ngIf="filterType === 'toggle'"> <div class="filter-control toggle" *ngIf="filterType === 'toggle'">
@@ -61,4 +69,5 @@
class="clr-toggle"> class="clr-toggle">
<label class="toggle-label">{{ filterLabel || filterKey }}</label> <label class="toggle-label">{{ filterLabel || filterKey }}</label>
</div> </div>
</div>
</div> </div>

View File

@@ -1,74 +1,149 @@
.compact-filter { .compact-filter {
padding: 10px; display: block;
border: 1px solid #ddd; min-width: 200px;
max-width: 300px;
margin: 8px;
padding: 0;
background: #ffffff;
border: 1px solid #d7d7d7;
border-radius: 4px; border-radius: 4px;
margin-bottom: 10px; font-size: 14px;
background-color: #f8f8f8; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
.filter-header { .filter-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 10px; padding: 12px 15px;
cursor: pointer;
background: #f8f8f8;
border-bottom: 1px solid #eaeaea;
border-radius: 4px 4px 0 0;
&:hover {
background: #f0f0f0;
}
.filter-label, .filter-key { .filter-label, .filter-key {
font-weight: bold; font-weight: 500;
color: #333333;
flex-grow: 1;
} }
.filter-type { .filter-type {
font-size: 0.8em; font-size: 12px;
color: #666; color: #666666;
margin: 0 8px;
background: #eaeaea;
padding: 2px 8px;
border-radius: 12px;
}
.expand-icon {
width: 16px;
height: 16px;
color: #666666;
} }
} }
.filter-content {
padding: 15px;
.filter-control { .filter-control {
margin-bottom: 10px; margin-bottom: 12px;
.compact-input, .compact-select, .compact-date { &:last-child {
width: 100%; margin-bottom: 0;
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 { &.date-range {
.date-input-group {
display: flex; display: flex;
gap: 10px; align-items: center;
gap: 8px;
.compact-date { .date-separator {
flex: 1; font-size: 14px;
color: #666666;
}
} }
} }
&.toggle { &.toggle {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
}
}
}
.clr-toggle { .compact-input,
margin-right: 10px; .compact-select,
.compact-date {
width: 100%;
padding: 8px 12px;
font-size: 14px;
border: 1px solid #d7d7d7;
border-radius: 4px;
background: #ffffff;
&:focus {
outline: none;
border-color: #0072ce;
box-shadow: 0 0 0 1px #0072ce;
}
}
.compact-select {
height: 36px;
}
.multiselect-container {
max-height: 200px;
overflow-y: auto;
border: 1px solid #d7d7d7;
border-radius: 4px;
padding: 10px;
background: #ffffff;
}
.checkbox-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.checkbox-item {
display: flex;
align-items: center;
gap: 8px;
.clr-checkbox {
width: 16px;
height: 16px;
cursor: pointer;
}
.checkbox-label {
font-size: 14px;
margin: 0;
cursor: pointer;
color: #333333;
}
} }
.toggle-label { .toggle-label {
margin: 0; margin: 0;
font-size: 14px;
color: #333333;
} }
}
.clr-toggle {
margin: 0;
} }
} }
// Host styling
:host {
display: block;
}

View File

@@ -20,20 +20,24 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
availableFilters: Filter[] = []; availableFilters: Filter[] = [];
availableKeys: string[] = []; availableKeys: string[] = [];
availableValues: string[] = []; availableValues: string[] = [];
isExpanded: boolean = false; // Add expansion state
constructor( constructor(
private filterService: FilterService private filterService: FilterService
) { } ) {
console.log('=== COMPACT FILTER RUNNER CONSTRUCTOR CALLED ===');
}
ngOnInit(): void { ngOnInit(): void {
console.log('CompactFilterRunnerComponent initialized with inputs:', { console.log('=== COMPACT FILTER RUNNER DEBUG INFO ===');
filterKey: this.filterKey, console.log('Component initialized with inputs:');
filterType: this.filterType, console.log('- filterKey:', this.filterKey);
filterOptions: this.filterOptions, console.log('- filterType:', this.filterType);
filterLabel: this.filterLabel, console.log('- filterOptions:', this.filterOptions);
apiUrl: this.apiUrl, console.log('- filterLabel:', this.filterLabel);
connection: this.connection console.log('- apiUrl:', this.apiUrl);
}); console.log('- connection:', this.connection);
console.log('========================================');
// Register this filter with the filter service // Register this filter with the filter service
this.registerFilter(); this.registerFilter();
@@ -41,24 +45,35 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
// Subscribe to filter definitions to get available filters // Subscribe to filter definitions to get available filters
this.filterService.filters$.subscribe(filters => { this.filterService.filters$.subscribe(filters => {
this.availableFilters = filters; this.availableFilters = filters;
console.log('Available filters updated:', filters);
this.updateSelectedFilter(); this.updateSelectedFilter();
}); });
// Subscribe to filter state changes // Subscribe to filter state changes
this.filterService.filterState$.subscribe(state => { this.filterService.filterState$.subscribe(state => {
console.log('Filter state updated:', state);
if (this.selectedFilter && state.hasOwnProperty(this.selectedFilter.id)) { if (this.selectedFilter && state.hasOwnProperty(this.selectedFilter.id)) {
this.filterValue = state[this.selectedFilter.id]; this.filterValue = state[this.selectedFilter.id];
console.log('Filter value updated for', this.selectedFilter.id, ':', this.filterValue);
} }
}); });
} }
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
console.log('CompactFilterRunnerComponent inputs changed:', changes); console.log('=== COMPACT FILTER RUNNER CHANGES DEBUG ===');
console.log('Component inputs changed:', changes);
// If filterKey or filterType changes, re-register the filter // If filterKey or filterType changes, re-register the filter
if (changes.filterKey || changes.filterType || changes.filterOptions) { if (changes.filterKey || changes.filterType || changes.filterOptions) {
console.log('Re-registering filter due to input changes');
this.registerFilter(); this.registerFilter();
} }
console.log('==========================================');
}
// Toggle filter expansion
toggleFilter(): void {
this.isExpanded = !this.isExpanded;
} }
// Register this filter with the filter service // Register this filter with the filter service
@@ -68,6 +83,7 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
if (this.filterKey) { if (this.filterKey) {
// Get current filter values from the service // Get current filter values from the service
const currentFilterValues = this.filterService.getFilterValues(); const currentFilterValues = this.filterService.getFilterValues();
console.log('Current filter values from service:', currentFilterValues);
// Create a filter definition for this compact filter // Create a filter definition for this compact filter
const filterDef: Filter = { const filterDef: Filter = {
@@ -83,9 +99,11 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
// Get current filters // Get current filters
const currentFilters = this.filterService.getFilters(); const currentFilters = this.filterService.getFilters();
console.log('Current filters from service:', currentFilters);
// Check if this filter is already registered // Check if this filter is already registered
const existingFilterIndex = currentFilters.findIndex(f => f.id === filterDef.id); const existingFilterIndex = currentFilters.findIndex(f => f.id === filterDef.id);
console.log('Existing filter index:', existingFilterIndex);
if (existingFilterIndex >= 0) { if (existingFilterIndex >= 0) {
// Preserve the existing filter configuration // Preserve the existing filter configuration
@@ -130,15 +148,20 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
// Update the selected filter reference // Update the selected filter reference
this.selectedFilter = filterDef; this.selectedFilter = filterDef;
console.log('Selected filter set to:', this.selectedFilter); console.log('Selected filter set to:', this.selectedFilter);
} else {
console.log('No filterKey provided, skipping filter registration');
} }
} }
updateSelectedFilter(): void { updateSelectedFilter(): void {
console.log('Updating selected filter. Filter key:', this.filterKey, 'Available filters:', this.availableFilters);
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;
console.log('Found selected filter:', this.selectedFilter);
if (this.selectedFilter) { if (this.selectedFilter) {
// Get current value for this filter from the service // Get current value for this filter from the service
const currentState = this.filterService.getFilterValues(); const currentState = this.filterService.getFilterValues();
console.log('Current state from service:', currentState);
const filterValue = currentState[this.selectedFilter.id]; const filterValue = currentState[this.selectedFilter.id];
if (filterValue !== undefined) { if (filterValue !== undefined) {
this.filterValue = filterValue; this.filterValue = filterValue;
@@ -203,4 +226,20 @@ export class CompactFilterRunnerComponent implements OnInit, OnChanges {
// Emit the change // Emit the change
this.onFilterValueChange(this.filterValue); this.onFilterValueChange(this.filterValue);
} }
// Add method to check if an option is selected for checkboxes (needed for proper UI rendering)
isOptionSelected(option: string): boolean {
console.log('Checking if option is selected:', option, 'Current filter value:', this.filterValue);
if (!this.filterValue) {
return false;
}
// Ensure filterValue is an array for multiselect
if (!Array.isArray(this.filterValue)) {
this.filterValue = [];
return false;
}
return this.filterValue.includes(option);
}
} }

View File

@@ -26,6 +26,9 @@
<!-- <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" <ndc-dynamic class="no-drag"
[ndcDynamicComponent]="item.component" [ndcDynamicComponent]="item.component"
[ndcDynamicInputs]="getComponentInputs(item)" [ndcDynamicInputs]="getComponentInputs(item)"

View File

@@ -311,12 +311,18 @@ dashboard_name = "Dashtest";
// Compact Filter specific inputs // Compact Filter specific inputs
if (item.name === 'Compact Filter') { if (item.name === 'Compact Filter') {
console.log('=== COMPACT FILTER INPUTS DEBUG ===');
console.log('Item data for compact filter:', item);
if (item.filterKey !== undefined) inputs.filterKey = item.filterKey; if (item.filterKey !== undefined) inputs.filterKey = item.filterKey;
if (item.filterType !== undefined) inputs.filterType = item.filterType; if (item.filterType !== undefined) inputs.filterType = item.filterType;
if (item.filterLabel !== undefined) inputs.filterLabel = item.filterLabel; if (item.filterLabel !== undefined) inputs.filterLabel = item.filterLabel;
if (item.filterOptions !== undefined) inputs.filterOptions = item.filterOptions; 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.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; if (item.connection !== undefined) inputs.connection = item.connection ? parseInt(item.connection, 10) : undefined;
console.log('Final inputs for compact filter:', inputs);
console.log('==============================');
} }
// Grid View specific inputs // Grid View specific inputs