dashboard
This commit is contained in:
parent
f2b6a4d145
commit
8266bfdc01
@ -23,18 +23,6 @@
|
|||||||
|
|
||||||
<!-- Main Dashboard Content -->
|
<!-- Main Dashboard Content -->
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
<!-- KPI Metrics -->
|
|
||||||
<!-- <div class="kpi-section">
|
|
||||||
<div class="kpi-card total-leads">
|
|
||||||
<div class="kpi-title">Total Leads</div>
|
|
||||||
<div class="kpi-value">1,248</div>
|
|
||||||
</div>
|
|
||||||
<div class="kpi-card total-deals">
|
|
||||||
<div class="kpi-title">Total Deals</div>
|
|
||||||
<div class="kpi-value">842</div>
|
|
||||||
</div>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- Deleted Items Section -->
|
<!-- Deleted Items Section -->
|
||||||
<div class="deleted-items-section" *ngIf="deletedItems.length > 0">
|
<div class="deleted-items-section" *ngIf="deletedItems.length > 0">
|
||||||
<h3>Deleted Items</h3>
|
<h3>Deleted Items</h3>
|
||||||
@ -52,9 +40,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dashboard Grid with Drag and Drop -->
|
<!-- Dashboard Grid with Drag and Drop -->
|
||||||
<!-- <div class="drop-zone-indicator" *ngIf="dashboard.length === 0">
|
|
||||||
<p>Drag components here from the sidebar</p>
|
|
||||||
</div> -->
|
|
||||||
<gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent; min-height: 500px;">
|
<gridster [options]="options" (drop)="onDrop($event)" style="background-color: transparent; min-height: 500px;">
|
||||||
<gridster-item [item]="item" *ngFor="let item of dashboard">
|
<gridster-item [item]="item" *ngFor="let item of dashboard">
|
||||||
<!-- Remove Button -->
|
<!-- Remove Button -->
|
||||||
@ -62,6 +47,11 @@
|
|||||||
<clr-icon shape="trash"></clr-icon>
|
<clr-icon shape="trash"></clr-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<!-- Edit Button -->
|
||||||
|
<button class="btn btn-icon" style="margin-top: 10px; float: right;" (click)="editGadget(item)">
|
||||||
|
<clr-icon shape="pencil"></clr-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
<!-- Drag Handle -->
|
<!-- Drag Handle -->
|
||||||
<button class="btn btn-icon drag-handler" style="margin-left: 10px; margin-top: 10px;">
|
<button class="btn btn-icon drag-handler" style="margin-left: 10px; margin-top: 10px;">
|
||||||
<clr-icon shape="drag-handle"></clr-icon>
|
<clr-icon shape="drag-handle"></clr-icon>
|
||||||
@ -97,3 +87,360 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Configuration Modal -->
|
||||||
|
<clr-modal [(clrModalOpen)]="modeledit" [clrModalStaticBackdrop]="true" clrModalSize="lg">
|
||||||
|
<h3 class="modal-title">Configure Chart</h3>
|
||||||
|
<div class="modal-body" *ngIf="selectedItem">
|
||||||
|
<form [formGroup]="configForm" class="clr-form-horizontal">
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="charttitle">Chart Title</label>
|
||||||
|
<input id="charttitle" type="text" formControlName="charttitle" class="clr-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Connection Selection Field -->
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="connection">Connection</label>
|
||||||
|
<select id="connection" formControlName="connection" class="clr-select">
|
||||||
|
<option value="">Select Connection</option>
|
||||||
|
<option *ngFor="let conn of sureconnectData" [value]="conn.id">
|
||||||
|
{{conn.connection_name || conn.id}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<div class="clr-subtext">Select a SureConnect connection to use for this chart</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<div class="clr-form-control" style="margin-top: 5px;margin-bottom: 10px;">
|
||||||
|
<div class="clr-control-container">
|
||||||
|
<div class="clr-checkbox-wrapper">
|
||||||
|
<input type="checkbox" id="chartlegend" formControlName="chartlegend" class="clr-checkbox" />
|
||||||
|
<label for="chartlegend" class="clr-control-label">Show Chart Legend</label>
|
||||||
|
</div>
|
||||||
|
<div class="clr-checkbox-wrapper">
|
||||||
|
<input type="checkbox" id="showlabel" formControlName="showlabel" class="clr-checkbox" />
|
||||||
|
<label for="showlabel" class="clr-control-label">Show Chart Label</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="table">Api Url</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="table" formControlName="table" class="clr-input" style="width:90%">
|
||||||
|
<span>
|
||||||
|
<button class="btn btn-icon btn-primary" style="margin: 0px;" (click)="getColumns(configForm.value.connection, configForm.value.table)">
|
||||||
|
<clr-icon shape="redo"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="xAxis">X-Axis</label>
|
||||||
|
<select id="xAxis" formControlName="xAxis">
|
||||||
|
<option value="null">choose Column</option>
|
||||||
|
<option *ngFor="let data of columnData" [value]="data">{{data}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.name !== 'Data Table' && selectedItem?.name !== 'Deal Details'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="yAxis">Y-Axis (Numeric)</label>
|
||||||
|
<clr-combobox-container style="margin-top: 10px !important;">
|
||||||
|
<clr-combobox id="yAxis" formControlName="yAxis" clrMulti="true" required>
|
||||||
|
<ng-container *clrOptionSelected="let selected">
|
||||||
|
{{selected}}
|
||||||
|
</ng-container>
|
||||||
|
<clr-options>
|
||||||
|
<clr-option *clrOptionItems="let state of columnData" [clrValue]="state">
|
||||||
|
{{state}}
|
||||||
|
</clr-option>
|
||||||
|
</clr-options>
|
||||||
|
</clr-combobox>
|
||||||
|
</clr-combobox-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Base API Filters -->
|
||||||
|
<div class="clr-row" style="margin-top: 15px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h5>Base API Filters</h5>
|
||||||
|
|
||||||
|
<!-- Add Base Filter Button -->
|
||||||
|
<button class="btn btn-sm btn-primary" (click)="addBaseFilter()" style="margin-top: 10px; margin-bottom: 10px;">
|
||||||
|
<clr-icon shape="plus"></clr-icon> Add Filter
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Base Filter Fields List -->
|
||||||
|
<div *ngFor="let filter of selectedItem?.baseFilters; let i = index"
|
||||||
|
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<span>Filter {{i + 1}}</span>
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 8px;">
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Field Name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Filter Value" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-2">
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeBaseFilter(i)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Base Drilldown Configuration Section -->
|
||||||
|
<div class="clr-row" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h4>Base Drilldown Configuration</h4>
|
||||||
|
<div class="clr-form-control">
|
||||||
|
<div class="clr-control-container">
|
||||||
|
<div class="clr-checkbox-wrapper">
|
||||||
|
<input type="checkbox" id="drilldownEnabled" [(ngModel)]="selectedItem.drilldownEnabled"
|
||||||
|
[ngModelOptions]="{standalone: true}" class="clr-checkbox" />
|
||||||
|
<label for="drilldownEnabled" class="clr-control-label">Enable Base Drilldown</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="drilldownApiUrl">Base Drilldown API URL</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" id="drilldownApiUrl" [(ngModel)]="selectedItem.drilldownApiUrl"
|
||||||
|
[ngModelOptions]="{standalone: true}" class="clr-input" style="width:90%">
|
||||||
|
<span>
|
||||||
|
<button class="btn btn-icon btn-primary" style="margin: 0px;"
|
||||||
|
(click)="refreshDrilldownColumns()" [disabled]="!selectedItem.drilldownApiUrl">
|
||||||
|
<clr-icon shape="redo"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="drilldownXAxis">Base Drilldown X-Axis</label>
|
||||||
|
<select id="drilldownXAxis" [(ngModel)]="selectedItem.drilldownXAxis" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select X-Axis Column</option>
|
||||||
|
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled && selectedItem?.name !== 'Deal Details'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="drilldownYAxis">Base Drilldown Y-Axis</label>
|
||||||
|
<select id="drilldownYAxis" [(ngModel)]="selectedItem.drilldownYAxis" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Y-Axis Column</option>
|
||||||
|
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Base Drilldown Parameter Configuration -->
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label for="drilldownParameter">Base Drilldown Parameter</label>
|
||||||
|
<select id="drilldownParameter" [(ngModel)]="selectedItem.drilldownParameter" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Parameter Column</option>
|
||||||
|
<option *ngFor="let column of drilldownColumnData" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Base Drilldown Filter Configuration -->
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled" style="margin-top: 15px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h5>Base Drilldown Filters</h5>
|
||||||
|
|
||||||
|
<!-- Add Drilldown Filter Button -->
|
||||||
|
<button class="btn btn-sm btn-primary" (click)="addDrilldownFilter()" style="margin-top: 10px; margin-bottom: 10px;">
|
||||||
|
<clr-icon shape="plus"></clr-icon> Add Filter
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Drilldown Filter Fields List -->
|
||||||
|
<div *ngFor="let filter of selectedItem?.drilldownFilters; let i = index"
|
||||||
|
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<span>Filter {{i + 1}}</span>
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownFilter(i)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 8px;">
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Field Name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Filter Value" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-2">
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownFilter(i)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Multi-Layer Drilldown Configurations -->
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.drilldownEnabled" style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #ddd;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h4>Multi-Layer Drilldown Configurations</h4>
|
||||||
|
<button class="btn btn-sm btn-primary" (click)="addDrilldownLayer()">
|
||||||
|
<clr-icon shape="plus"></clr-icon> Add Drilldown Layer
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dynamic Drilldown Layers -->
|
||||||
|
<div class="clr-row" *ngFor="let layer of selectedItem?.drilldownLayers; let i = index">
|
||||||
|
<div class="clr-col-sm-12" style="margin-top: 15px; padding: 10px; border: 1px solid #eee; border-radius: 4px;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<h5>Drilldown Layer {{i + 1}}</h5>
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeDrilldownLayer(i)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-form-control">
|
||||||
|
<div class="clr-control-container">
|
||||||
|
<div class="clr-checkbox-wrapper">
|
||||||
|
<input type="checkbox" [id]="'layerEnabled' + i" [(ngModel)]="layer.enabled"
|
||||||
|
[ngModelOptions]="{standalone: true}" class="clr-checkbox" />
|
||||||
|
<label [for]="'layerEnabled' + i" class="clr-control-label">Enable Layer {{i + 1}} Drilldown</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label [for]="'layerApiUrl' + i">Layer {{i + 1}} API URL</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" [id]="'layerApiUrl' + i" class="clr-input"
|
||||||
|
[(ngModel)]="layer.apiUrl" style="width:90%" [ngModelOptions]="{standalone: true}">
|
||||||
|
<span>
|
||||||
|
<button class="btn btn-icon btn-primary" style="margin: 0px;"
|
||||||
|
(click)="refreshDrilldownLayerColumns(i)" [disabled]="!layer.apiUrl">
|
||||||
|
<clr-icon shape="redo"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label [for]="'layerXAxis' + i">Layer {{i + 1}} X-Axis</label>
|
||||||
|
<select [id]="'layerXAxis' + i" [(ngModel)]="layer.xAxis" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select X-Axis Column</option>
|
||||||
|
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" *ngIf="selectedItem?.name !== 'Deal Details'">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label [for]="'layerYAxis' + i">Layer {{i + 1}} Y-Axis</label>
|
||||||
|
<select [id]="'layerYAxis' + i" [(ngModel)]="layer.yAxis" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Y-Axis Column</option>
|
||||||
|
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Parameter Selection for Drilldown Layer -->
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<label [for]="'layerParameter' + i">Layer {{i + 1}} Parameter</label>
|
||||||
|
<select [id]="'layerParameter' + i" [(ngModel)]="layer.parameter" [ngModelOptions]="{standalone: true}">
|
||||||
|
<option value="">Select Parameter Column</option>
|
||||||
|
<option *ngFor="let column of layerColumnData[i] || []" [value]="column">{{column}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Layer Filter Configuration -->
|
||||||
|
<div class="clr-row" style="margin-top: 15px;">
|
||||||
|
<div class="clr-col-sm-12">
|
||||||
|
<h5>Layer {{i + 1}} Filters</h5>
|
||||||
|
|
||||||
|
<!-- Add Layer Filter Button -->
|
||||||
|
<button class="btn btn-sm btn-primary" (click)="addLayerFilter(i)" style="margin-top: 10px; margin-bottom: 10px;">
|
||||||
|
<clr-icon shape="plus"></clr-icon> Add Filter
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Layer Filter Fields List -->
|
||||||
|
<div *ngFor="let filter of layer.filters; let j = index"
|
||||||
|
style="margin-bottom: 10px; padding: 8px; border: 1px solid #eee; border-radius: 4px; background-color: #f9f9f9;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<span>Filter {{j + 1}}</span>
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeLayerFilter(i, j)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-row" style="margin-top: 8px;">
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.field" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Field Name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-5">
|
||||||
|
<input type="text" [(ngModel)]="filter.value" [ngModelOptions]="{standalone: true}"
|
||||||
|
class="clr-input" placeholder="Filter Value" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="clr-col-sm-2">
|
||||||
|
<button class="btn btn-icon btn-danger btn-sm" (click)="removeLayerFilter(i, j)">
|
||||||
|
<clr-icon shape="trash"></clr-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-outline" (click)="cancelConfiguration()">Cancel</button>
|
||||||
|
<button type="button" class="btn btn-primary" (click)="saveConfiguration()">Save</button>
|
||||||
|
</div>
|
||||||
|
</clr-modal>
|
||||||
@ -1,11 +1,31 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { GridsterConfig, GridsterItem } from 'angular-gridster2';
|
import { GridsterConfig, GridsterItem } from 'angular-gridster2';
|
||||||
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { DatastoreService } from 'src/app/services/fnd/datastore.service';
|
||||||
|
import { AlertsService } from 'src/app/services/fnd/alerts.service';
|
||||||
|
import { SureconnectService } from '../../sureconnect/sureconnect.service';
|
||||||
|
|
||||||
interface ShieldDashboardItem extends GridsterItem {
|
interface ShieldDashboardItem extends GridsterItem {
|
||||||
chartType: string;
|
chartType: string;
|
||||||
name: string;
|
name: string;
|
||||||
id: number;
|
id: number;
|
||||||
component?: any;
|
component?: any;
|
||||||
|
// Configuration properties
|
||||||
|
charttitle?: string;
|
||||||
|
connection?: string;
|
||||||
|
table?: string;
|
||||||
|
xAxis?: string;
|
||||||
|
yAxis?: string[];
|
||||||
|
chartlegend?: boolean;
|
||||||
|
showlabel?: boolean;
|
||||||
|
baseFilters?: any[];
|
||||||
|
drilldownEnabled?: boolean;
|
||||||
|
drilldownApiUrl?: string;
|
||||||
|
drilldownXAxis?: string;
|
||||||
|
drilldownYAxis?: string;
|
||||||
|
drilldownParameter?: string;
|
||||||
|
drilldownFilters?: any[];
|
||||||
|
drilldownLayers?: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WidgetModel {
|
interface WidgetModel {
|
||||||
@ -22,6 +42,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
options: GridsterConfig;
|
options: GridsterConfig;
|
||||||
dashboard: Array<ShieldDashboardItem>;
|
dashboard: Array<ShieldDashboardItem>;
|
||||||
|
|
||||||
|
// Configuration modal
|
||||||
|
configModalOpen = false;
|
||||||
|
modeledit = false; // Add this to match the main dashboard pattern
|
||||||
|
configForm: FormGroup;
|
||||||
|
selectedItem: ShieldDashboardItem | null = null;
|
||||||
|
|
||||||
// Component palette
|
// Component palette
|
||||||
showComponentPalette = false;
|
showComponentPalette = false;
|
||||||
WidgetsMock: WidgetModel[] = [
|
WidgetsMock: WidgetModel[] = [
|
||||||
@ -51,10 +77,22 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Services data
|
||||||
|
storedata: any[] = [];
|
||||||
|
columnData: any[] = [];
|
||||||
|
sureconnectData: any[] = [];
|
||||||
|
drilldownColumnData: any[] = [];
|
||||||
|
layerColumnData: { [key: number]: any[] } = {};
|
||||||
|
|
||||||
// Keep track of deleted items
|
// Keep track of deleted items
|
||||||
deletedItems: Array<ShieldDashboardItem> = [];
|
deletedItems: Array<ShieldDashboardItem> = [];
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private _fb: FormBuilder,
|
||||||
|
private datastoreService: DatastoreService,
|
||||||
|
private alertService: AlertsService,
|
||||||
|
private sureconnectService: SureconnectService
|
||||||
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.options = {
|
this.options = {
|
||||||
@ -81,6 +119,33 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
|
|
||||||
// Initialize the dashboard with empty canvas
|
// Initialize the dashboard with empty canvas
|
||||||
this.dashboard = [];
|
this.dashboard = [];
|
||||||
|
|
||||||
|
// Initialize form
|
||||||
|
this.configForm = this._fb.group({
|
||||||
|
charttitle: [''],
|
||||||
|
connection: [''],
|
||||||
|
table: [''],
|
||||||
|
xAxis: [''],
|
||||||
|
yAxis: [''],
|
||||||
|
chartlegend: [true],
|
||||||
|
showlabel: [true]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load service data
|
||||||
|
this.loadServicesData();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load initial data from services
|
||||||
|
loadServicesData() {
|
||||||
|
// Load sureconnect data
|
||||||
|
this.sureconnectService.getAll().subscribe((data: any[]) => {
|
||||||
|
this.sureconnectData = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load datastore data
|
||||||
|
this.datastoreService.getAll().subscribe((data) => {
|
||||||
|
this.storedata = data as any[];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle component palette visibility
|
// Toggle component palette visibility
|
||||||
@ -128,7 +193,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'bar-chart',
|
chartType: 'bar-chart',
|
||||||
name: 'Bar Chart',
|
name: 'Bar Chart',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "doughnut_chart":
|
case "doughnut_chart":
|
||||||
@ -142,7 +212,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'donut-chart',
|
chartType: 'donut-chart',
|
||||||
name: 'End Customer Donut',
|
name: 'End Customer Donut',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
newItem = {
|
newItem = {
|
||||||
@ -152,7 +227,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'donut-chart',
|
chartType: 'donut-chart',
|
||||||
name: 'Segment Penetration Donut',
|
name: 'Segment Penetration Donut',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -164,7 +244,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'map-chart',
|
chartType: 'map-chart',
|
||||||
name: 'Map Chart',
|
name: 'Map Chart',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "grid_view":
|
case "grid_view":
|
||||||
@ -175,7 +260,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'data-table',
|
chartType: 'data-table',
|
||||||
name: 'Data Table',
|
name: 'Data Table',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "to_do_chart":
|
case "to_do_chart":
|
||||||
@ -186,7 +276,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'deal-details',
|
chartType: 'deal-details',
|
||||||
name: 'Deal Details',
|
name: 'Deal Details',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case "line_chart":
|
case "line_chart":
|
||||||
@ -197,7 +292,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: 'quarterwise-flow',
|
chartType: 'quarterwise-flow',
|
||||||
name: 'Quarterwise Flow',
|
name: 'Quarterwise Flow',
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -208,7 +308,12 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
x: 0,
|
x: 0,
|
||||||
chartType: componentType,
|
chartType: componentType,
|
||||||
name: componentType,
|
name: componentType,
|
||||||
id: newId
|
id: newId,
|
||||||
|
chartlegend: true,
|
||||||
|
showlabel: true,
|
||||||
|
baseFilters: [],
|
||||||
|
drilldownEnabled: false,
|
||||||
|
drilldownLayers: []
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +361,22 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
// Only pass properties that are relevant to chart components
|
// Only pass properties that are relevant to chart components
|
||||||
const chartInputs = {
|
const chartInputs = {
|
||||||
chartType: item.chartType,
|
chartType: item.chartType,
|
||||||
name: item.name
|
name: item.name,
|
||||||
|
charttitle: item.charttitle,
|
||||||
|
connection: item.connection,
|
||||||
|
table: item.table,
|
||||||
|
xAxis: item.xAxis,
|
||||||
|
yAxis: item.yAxis,
|
||||||
|
chartlegend: item.chartlegend,
|
||||||
|
showlabel: item.showlabel,
|
||||||
|
baseFilters: item.baseFilters || [],
|
||||||
|
drilldownEnabled: item.drilldownEnabled,
|
||||||
|
drilldownApiUrl: item.drilldownApiUrl,
|
||||||
|
drilldownXAxis: item.drilldownXAxis,
|
||||||
|
drilldownYAxis: item.drilldownYAxis,
|
||||||
|
drilldownParameter: item.drilldownParameter,
|
||||||
|
drilldownFilters: item.drilldownFilters || [],
|
||||||
|
drilldownLayers: item.drilldownLayers || []
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove undefined properties to avoid passing unnecessary data
|
// Remove undefined properties to avoid passing unnecessary data
|
||||||
@ -268,4 +388,193 @@ export class ShieldDashboardComponent implements OnInit {
|
|||||||
|
|
||||||
return chartInputs;
|
return chartInputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open configuration modal for a chart
|
||||||
|
editGadget(item: ShieldDashboardItem) {
|
||||||
|
console.log('Opening configuration modal for item:', item);
|
||||||
|
this.selectedItem = item;
|
||||||
|
this.modeledit = true; // Use modeledit instead of configModalOpen
|
||||||
|
|
||||||
|
// Initialize form with item data
|
||||||
|
this.configForm.patchValue({
|
||||||
|
charttitle: item.charttitle || '',
|
||||||
|
connection: item.connection || '',
|
||||||
|
table: item.table || '',
|
||||||
|
xAxis: item.xAxis || '',
|
||||||
|
yAxis: item.yAxis || [],
|
||||||
|
chartlegend: item.chartlegend !== undefined ? item.chartlegend : true,
|
||||||
|
showlabel: item.showlabel !== undefined ? item.showlabel : true
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Form values after patch:', this.configForm.value);
|
||||||
|
|
||||||
|
// Load columns if table is set
|
||||||
|
if (item.table) {
|
||||||
|
this.getColumns(item.connection, item.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load drilldown columns if drilldown API URL is set
|
||||||
|
if (item.drilldownApiUrl) {
|
||||||
|
this.refreshDrilldownColumns();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save configuration changes
|
||||||
|
saveConfiguration() {
|
||||||
|
if (this.selectedItem) {
|
||||||
|
const formData = this.configForm.value;
|
||||||
|
console.log('Saving configuration:', formData);
|
||||||
|
|
||||||
|
// Update the selected item with form data
|
||||||
|
Object.assign(this.selectedItem, formData);
|
||||||
|
|
||||||
|
// Close the modal
|
||||||
|
this.modeledit = false; // Use modeledit instead of configModalOpen
|
||||||
|
this.selectedItem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel configuration changes
|
||||||
|
cancelConfiguration() {
|
||||||
|
console.log('Canceling configuration');
|
||||||
|
this.modeledit = false; // Use modeledit instead of configModalOpen
|
||||||
|
this.selectedItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get tables from datastore
|
||||||
|
getTables(id: string) {
|
||||||
|
this.alertService.getTablefromstore(parseInt(id, 10)).subscribe(gateway => {
|
||||||
|
console.log(gateway);
|
||||||
|
// Handle table data
|
||||||
|
}, (error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get columns from API
|
||||||
|
getColumns(connectionId: string, table: string) {
|
||||||
|
const connId = connectionId ? parseInt(connectionId, 10) : undefined;
|
||||||
|
this.alertService.getColumnfromurl(table, connId).subscribe(data => {
|
||||||
|
console.log('Column data:', data);
|
||||||
|
this.columnData = data;
|
||||||
|
}, (error) => {
|
||||||
|
console.log(error);
|
||||||
|
this.columnData = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh drilldown columns
|
||||||
|
refreshDrilldownColumns() {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownApiUrl) {
|
||||||
|
const connId = this.selectedItem.connection ? parseInt(this.selectedItem.connection, 10) : undefined;
|
||||||
|
this.alertService.getColumnfromurl(this.selectedItem.drilldownApiUrl, connId).subscribe(data => {
|
||||||
|
console.log('Drilldown column data:', data);
|
||||||
|
this.drilldownColumnData = data;
|
||||||
|
}, (error) => {
|
||||||
|
console.log('Error fetching drilldown columns:', error);
|
||||||
|
this.drilldownColumnData = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add base filter
|
||||||
|
addBaseFilter() {
|
||||||
|
if (this.selectedItem) {
|
||||||
|
if (!this.selectedItem.baseFilters) {
|
||||||
|
this.selectedItem.baseFilters = [];
|
||||||
|
}
|
||||||
|
this.selectedItem.baseFilters.push({ field: '', value: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove base filter
|
||||||
|
removeBaseFilter(index: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.baseFilters) {
|
||||||
|
this.selectedItem.baseFilters.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add drilldown filter
|
||||||
|
addDrilldownFilter() {
|
||||||
|
if (this.selectedItem) {
|
||||||
|
if (!this.selectedItem.drilldownFilters) {
|
||||||
|
this.selectedItem.drilldownFilters = [];
|
||||||
|
}
|
||||||
|
this.selectedItem.drilldownFilters.push({ field: '', value: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove drilldown filter
|
||||||
|
removeDrilldownFilter(index: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownFilters) {
|
||||||
|
this.selectedItem.drilldownFilters.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add drilldown layer
|
||||||
|
addDrilldownLayer() {
|
||||||
|
if (this.selectedItem) {
|
||||||
|
if (!this.selectedItem.drilldownLayers) {
|
||||||
|
this.selectedItem.drilldownLayers = [];
|
||||||
|
}
|
||||||
|
this.selectedItem.drilldownLayers.push({
|
||||||
|
enabled: false,
|
||||||
|
apiUrl: '',
|
||||||
|
xAxis: '',
|
||||||
|
yAxis: '',
|
||||||
|
parameter: '',
|
||||||
|
filters: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove drilldown layer
|
||||||
|
removeDrilldownLayer(index: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownLayers) {
|
||||||
|
this.selectedItem.drilldownLayers.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add layer filter
|
||||||
|
addLayerFilter(layerIndex: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownLayers) {
|
||||||
|
const layer = this.selectedItem.drilldownLayers[layerIndex];
|
||||||
|
if (layer) {
|
||||||
|
if (!layer.filters) {
|
||||||
|
layer.filters = [];
|
||||||
|
}
|
||||||
|
layer.filters.push({ field: '', value: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh drilldown columns for a specific layer
|
||||||
|
refreshDrilldownLayerColumns(layerIndex: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownLayers && this.selectedItem.drilldownLayers[layerIndex]) {
|
||||||
|
const layer = this.selectedItem.drilldownLayers[layerIndex];
|
||||||
|
if (layer && layer.apiUrl) {
|
||||||
|
const connId = this.selectedItem.connection ? parseInt(this.selectedItem.connection, 10) : undefined;
|
||||||
|
this.alertService.getColumnfromurl(layer.apiUrl, connId).subscribe(data => {
|
||||||
|
console.log(`Drilldown layer ${layerIndex} column data:`, data);
|
||||||
|
// Store layer column data in the layerColumnData property
|
||||||
|
this.layerColumnData[layerIndex] = data;
|
||||||
|
}, (error) => {
|
||||||
|
console.log(`Error fetching drilldown layer ${layerIndex} columns:`, error);
|
||||||
|
this.layerColumnData[layerIndex] = [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove layer filter
|
||||||
|
removeLayerFilter(layerIndex: number, filterIndex: number) {
|
||||||
|
if (this.selectedItem && this.selectedItem.drilldownLayers) {
|
||||||
|
const layer = this.selectedItem.drilldownLayers[layerIndex];
|
||||||
|
if (layer && layer.filters) {
|
||||||
|
layer.filters.splice(filterIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
|
import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { ClarityModule } from '@clr/angular';
|
import { ClarityModule } from '@clr/angular';
|
||||||
import { GridsterModule } from 'angular-gridster2';
|
import { GridsterModule } from 'angular-gridster2';
|
||||||
import { NgChartsModule } from 'ng2-charts';
|
import { NgChartsModule } from 'ng2-charts';
|
||||||
@ -32,6 +32,7 @@ import { LoadingShimmerComponent } from './components/loading-shimmer/loading-sh
|
|||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
|
ReactiveFormsModule,
|
||||||
ClarityModule,
|
ClarityModule,
|
||||||
GridsterModule,
|
GridsterModule,
|
||||||
NgChartsModule,
|
NgChartsModule,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user