dashboard
This commit is contained in:
		
							parent
							
								
									02f37a1bc5
								
							
						
					
					
						commit
						f2b6a4d145
					
				| @ -1,76 +1,3 @@ | ||||
| <div class="sidebar-filters"> | ||||
|   <!-- Application Header --> | ||||
|   <div class="app-header"> | ||||
|     <h1 class="app-name">Shield</h1> | ||||
|     <h2 class="dashboard-title">Overall Dashboard</h2> | ||||
|   </div> | ||||
|    | ||||
|   <!-- KPI Metrics --> | ||||
|   <div class="kpi-section"> | ||||
|     <div class="kpi-card total-leads"> | ||||
|       <div class="kpi-title">Total Leads</div> | ||||
|       <div class="kpi-value">{{ totalLeads }}</div> | ||||
|     </div> | ||||
|     <div class="kpi-card total-deals"> | ||||
|       <div class="kpi-title">Total Deals</div> | ||||
|       <div class="kpi-value">{{ totalDeals }}</div> | ||||
|     </div> | ||||
|   </div> | ||||
|    | ||||
|   <!-- Filters Section --> | ||||
|   <div class="filters-section"> | ||||
|     <h3 class="filters-title">Filters</h3> | ||||
|      | ||||
|     <div class="filter-group"> | ||||
|       <label for="salesRep">Sales Rep</label> | ||||
|       <select  | ||||
|         id="salesRep"  | ||||
|         [(ngModel)]="selectedSalesRep"  | ||||
|         (ngModelChange)="updateFilter('salesRep', $event)" | ||||
|         class="filter-select"> | ||||
|         <option value="">All Sales Reps</option> | ||||
|         <option *ngFor="let rep of salesReps" [value]="rep">{{ rep }}</option> | ||||
|       </select> | ||||
|     </div> | ||||
|      | ||||
|     <div class="filter-group"> | ||||
|       <label for="partner">Partner</label> | ||||
|       <select  | ||||
|         id="partner"  | ||||
|         [(ngModel)]="selectedPartner"  | ||||
|         (ngModelChange)="updateFilter('partner', $event)" | ||||
|         class="filter-select"> | ||||
|         <option value="">All Partners</option> | ||||
|         <option *ngFor="let partner of partners" [value]="partner">{{ partner }}</option> | ||||
|       </select> | ||||
|     </div> | ||||
|      | ||||
|     <div class="filter-group"> | ||||
|       <label for="tractionChannel">Traction Channel</label> | ||||
|       <select  | ||||
|         id="tractionChannel"  | ||||
|         [(ngModel)]="selectedTractionChannel"  | ||||
|         (ngModelChange)="updateFilter('tractionChannel', $event)" | ||||
|         class="filter-select"> | ||||
|         <option value="">All Channels</option> | ||||
|         <option *ngFor="let channel of tractionChannels" [value]="channel">{{ channel }}</option> | ||||
|       </select> | ||||
|     </div> | ||||
|      | ||||
|     <div class="filter-group"> | ||||
|       <label for="subProductLine">Sub Product Line</label> | ||||
|       <select  | ||||
|         id="subProductLine"  | ||||
|         [(ngModel)]="selectedSubProductLine"  | ||||
|         (ngModelChange)="updateFilter('subProductLine', $event)" | ||||
|         class="filter-select"> | ||||
|         <option value="">All Lines</option> | ||||
|         <option *ngFor="let line of subProductLines" [value]="line">{{ line }}</option> | ||||
|       </select> | ||||
|     </div> | ||||
|      | ||||
|     <button class="reset-button" (click)="resetFilters()"> | ||||
|       Reset Filters | ||||
|     </button> | ||||
|   </div> | ||||
|   <!-- Component Palette Button and List have been moved to the main shield dashboard component --> | ||||
| </div> | ||||
| @ -3,6 +3,35 @@ | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|    | ||||
|   .componentbtn { | ||||
|     margin: 10px; | ||||
|     width: calc(100% - 20px); | ||||
|   } | ||||
|    | ||||
|   .nav-list { | ||||
|     padding: 0; | ||||
|     margin: 0 10px; | ||||
|      | ||||
|     .nav-link { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       padding: 8px 12px; | ||||
|       margin-bottom: 5px; | ||||
|       background: #f8f9fa; | ||||
|       border: 1px solid #e9ecef; | ||||
|       border-radius: 4px; | ||||
|       cursor: move; | ||||
|        | ||||
|       &:hover { | ||||
|         background: #e9ecef; | ||||
|       } | ||||
|        | ||||
|       .has-badge { | ||||
|         margin-left: auto; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   .app-header { | ||||
|     margin-bottom: 30px; | ||||
|      | ||||
| @ -55,6 +84,74 @@ | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   .component-palette-section { | ||||
|     margin: 20px; | ||||
|      | ||||
|     .component-palette-button { | ||||
|       width: 100%; | ||||
|       padding: 12px; | ||||
|       background: rgba(255, 107, 53, 0.2); | ||||
|       color: white; | ||||
|       border: 1px solid rgba(255, 107, 53, 0.5); | ||||
|       border-radius: 8px; | ||||
|       font-size: 16px; | ||||
|       font-weight: 500; | ||||
|       cursor: pointer; | ||||
|       transition: all 0.2s ease; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       gap: 8px; | ||||
|        | ||||
|       &:hover { | ||||
|         background: rgba(255, 107, 53, 0.3); | ||||
|         border-color: #ff6b35; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     .component-palette { | ||||
|       margin-top: 15px; | ||||
|       background: rgba(255, 255, 255, 0.05); | ||||
|       border-radius: 8px; | ||||
|       padding: 15px; | ||||
|        | ||||
|       .palette-title { | ||||
|         font-size: 16px; | ||||
|         color: white; | ||||
|         margin: 0 0 15px 0; | ||||
|         text-align: center; | ||||
|       } | ||||
|        | ||||
|       .component-list { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         gap: 10px; | ||||
|          | ||||
|         .component-item { | ||||
|           padding: 10px 15px; | ||||
|           background: rgba(255, 255, 255, 0.1); | ||||
|           border: 1px solid rgba(255, 255, 255, 0.2); | ||||
|           border-radius: 6px; | ||||
|           color: white; | ||||
|           cursor: move; | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           gap: 10px; | ||||
|           transition: all 0.2s ease; | ||||
|            | ||||
|           &:hover { | ||||
|             background: rgba(255, 107, 53, 0.2); | ||||
|             border-color: #ff6b35; | ||||
|           } | ||||
|            | ||||
|           .drag-icon { | ||||
|             font-size: 16px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   .filters-section { | ||||
|     flex: 1; | ||||
|      | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| import { Component, OnInit } from '@angular/core'; | ||||
| import { DashboardFilterService, FilterState } from '../../services/dashboard-filter.service'; | ||||
| import { Observable } from 'rxjs'; | ||||
| import { DashboardFilterService } from '../../services/dashboard-filter.service'; | ||||
| 
 | ||||
| @Component({ | ||||
|   selector: 'app-shield-sidebar-filters', | ||||
| @ -8,44 +7,10 @@ import { Observable } from 'rxjs'; | ||||
|   styleUrls: ['./sidebar-filters.component.scss'] | ||||
| }) | ||||
| export class SidebarFiltersComponent implements OnInit { | ||||
|   // Filter options
 | ||||
|   salesReps = ['All Sales Reps', 'John Smith', 'Jane Doe', 'Mike Johnson', 'Sarah Wilson']; | ||||
|   partners = ['All Partners', 'Partner A', 'Partner B', 'Partner C', 'Partner D']; | ||||
|   tractionChannels = ['All Channels', 'Direct', 'Indirect', 'Online', 'Referral']; | ||||
|   subProductLines = ['All Lines', 'Product Line 1', 'Product Line 2', 'Product Line 3']; | ||||
|    | ||||
|   // Current filter values
 | ||||
|   selectedSalesRep = ''; | ||||
|   selectedPartner = ''; | ||||
|   selectedTractionChannel = ''; | ||||
|   selectedSubProductLine = ''; | ||||
|    | ||||
|   // KPI data
 | ||||
|   totalLeads = 1248; | ||||
|   totalDeals = 842; | ||||
| 
 | ||||
|   constructor(private filterService: DashboardFilterService) { } | ||||
| 
 | ||||
|   ngOnInit(): void { | ||||
|     // Subscribe to KPI data changes
 | ||||
|     this.filterService.kpiData$.subscribe(kpiData => { | ||||
|       this.totalLeads = kpiData.totalLeads; | ||||
|       this.totalDeals = kpiData.totalDeals; | ||||
|     }); | ||||
|   } | ||||
|    | ||||
|   // Update filter state when any filter changes
 | ||||
|   updateFilter(filterType: keyof FilterState, value: string): void { | ||||
|     this.filterService.updateFilter(filterType, value); | ||||
|   } | ||||
|    | ||||
|   // Reset all filters to default values
 | ||||
|   resetFilters(): void { | ||||
|     this.selectedSalesRep = ''; | ||||
|     this.selectedPartner = ''; | ||||
|     this.selectedTractionChannel = ''; | ||||
|     this.selectedSubProductLine = ''; | ||||
|      | ||||
|     this.filterService.resetFilters(); | ||||
|     // Component initialization
 | ||||
|   } | ||||
| } | ||||
| @ -1,12 +1,30 @@ | ||||
| <div class="shield-dashboard"> | ||||
|   <div class="dashboard-container"> | ||||
|     <!-- Sidebar Filters --> | ||||
|     <app-shield-sidebar-filters class="sidebar"></app-shield-sidebar-filters> | ||||
|     <div class="sidebar"> | ||||
|       <button class="btn componentbtn" (click)="toggleComponentPalette()"> | ||||
|         <clr-icon shape="plus"></clr-icon> Component | ||||
|       </button> | ||||
|        | ||||
|       <ul class="nav-list" style="list-style-type: none;" *ngIf="showComponentPalette"> | ||||
|         <li *ngFor="let widget of WidgetsMock"> | ||||
|           <!-- | ||||
|             Draggable widget from store using vanilla javascript event (dragstart) | ||||
|             onDrag() is call, it take $event and a widget identifier as parameters | ||||
|           --> | ||||
|           <a draggable="true" class="nav-link" (dragstart)="onDrag($event, widget.identifier)"> | ||||
|             <clr-icon shape="drag-handle" style="margin-right: 10px;"></clr-icon> | ||||
|             {{ widget.name }} | ||||
|             <clr-icon shape="plugin" class="has-badge"></clr-icon> | ||||
|           </a> | ||||
|         </li> | ||||
|       </ul> | ||||
|     </div> | ||||
|      | ||||
|     <!-- Main Dashboard Content --> | ||||
|     <div class="main-content"> | ||||
|       <!-- KPI Metrics --> | ||||
|       <div class="kpi-section"> | ||||
|       <!-- <div class="kpi-section"> | ||||
|         <div class="kpi-card total-leads"> | ||||
|           <div class="kpi-title">Total Leads</div> | ||||
|           <div class="kpi-value">1,248</div> | ||||
| @ -15,10 +33,29 @@ | ||||
|           <div class="kpi-title">Total Deals</div> | ||||
|           <div class="kpi-value">842</div> | ||||
|         </div> | ||||
|       </div> --> | ||||
|        | ||||
|       <!-- Deleted Items Section --> | ||||
|       <div class="deleted-items-section" *ngIf="deletedItems.length > 0"> | ||||
|         <h3>Deleted Items</h3> | ||||
|         <div class="deleted-items-list"> | ||||
|           <div *ngFor="let item of deletedItems" class="deleted-item"> | ||||
|             <span>{{ item.name }}</span> | ||||
|             <button class="btn btn-sm btn-primary" (click)="restoreItem(item)"> | ||||
|               <clr-icon shape="undo"></clr-icon> Restore | ||||
|             </button> | ||||
|           </div> | ||||
|         </div> | ||||
|         <button class="btn btn-sm btn-danger" (click)="clearDeletedItems()"> | ||||
|           <clr-icon shape="trash"></clr-icon> Clear All | ||||
|         </button> | ||||
|       </div> | ||||
|        | ||||
|       <!-- Dashboard Grid with Drag and Drop --> | ||||
|       <gridster [options]="options" style="background-color: transparent;"> | ||||
|       <!-- <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-item [item]="item" *ngFor="let item of dashboard"> | ||||
|           <!-- Remove Button --> | ||||
|           <button class="btn btn-icon btn-danger" style="margin-left: 10px; margin-top: 10px;" (click)="removeItem(item)"> | ||||
| @ -36,10 +73,10 @@ | ||||
|             <div *ngIf="item.chartType === 'bar-chart'"> | ||||
|               <app-shield-bar-chart></app-shield-bar-chart> | ||||
|             </div> | ||||
|             <div *ngIf="item.chartType === 'donut-chart' && item.name === 'End Customer'"> | ||||
|             <div *ngIf="item.chartType === 'donut-chart' && item.name === 'End Customer Donut'"> | ||||
|               <app-shield-donut-chart chartType="endCustomer"></app-shield-donut-chart> | ||||
|             </div> | ||||
|             <div *ngIf="item.chartType === 'donut-chart' && item.name === 'Segment Penetration'"> | ||||
|             <div *ngIf="item.chartType === 'donut-chart' && item.name === 'Segment Penetration Donut'"> | ||||
|               <app-shield-donut-chart chartType="segmentPenetration"></app-shield-donut-chart> | ||||
|             </div> | ||||
|             <div *ngIf="item.chartType === 'map-chart'"> | ||||
|  | ||||
| @ -59,6 +59,42 @@ | ||||
|   border-top: 4px solid #0f9d58; | ||||
| } | ||||
| 
 | ||||
| .deleted-items-section { | ||||
|   background: white; | ||||
|   border-radius: 4px; | ||||
|   box-shadow: 0 2px 4px rgba(0,0,0,0.1); | ||||
|   padding: 20px; | ||||
|    | ||||
|   h3 { | ||||
|     margin-top: 0; | ||||
|     color: #333; | ||||
|     border-bottom: 1px solid #eee; | ||||
|     padding-bottom: 10px; | ||||
|   } | ||||
|    | ||||
|   .deleted-items-list { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
|     gap: 10px; | ||||
|     margin-bottom: 15px; | ||||
|      | ||||
|     .deleted-item { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       gap: 10px; | ||||
|       background: #f8f9fa; | ||||
|       border: 1px solid #e9ecef; | ||||
|       border-radius: 4px; | ||||
|       padding: 8px 12px; | ||||
|        | ||||
|       span { | ||||
|         font-size: 14px; | ||||
|         color: #495057; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .dashboard-grid { | ||||
|   display: grid; | ||||
|   grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); | ||||
| @ -81,6 +117,23 @@ | ||||
|   cursor: move; | ||||
| } | ||||
| 
 | ||||
| .drop-zone-indicator { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   min-height: 500px; | ||||
|   background-color: #f8f9fa; | ||||
|   border: 2px dashed #dee2e6; | ||||
|   border-radius: 4px; | ||||
|   color: #6c757d; | ||||
|   font-size: 18px; | ||||
|   text-align: center; | ||||
|    | ||||
|   p { | ||||
|     margin: 0; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* Gridster specific styles */ | ||||
| gridster { | ||||
|   background: transparent !important; | ||||
|  | ||||
| @ -5,6 +5,12 @@ interface ShieldDashboardItem extends GridsterItem { | ||||
|   chartType: string; | ||||
|   name: string; | ||||
|   id: number; | ||||
|   component?: any; | ||||
| } | ||||
| 
 | ||||
| interface WidgetModel { | ||||
|   name: string; | ||||
|   identifier: string; | ||||
| } | ||||
| 
 | ||||
| @Component({ | ||||
| @ -15,6 +21,38 @@ interface ShieldDashboardItem extends GridsterItem { | ||||
| export class ShieldDashboardComponent implements OnInit { | ||||
|   options: GridsterConfig; | ||||
|   dashboard: Array<ShieldDashboardItem>; | ||||
|    | ||||
|   // Component palette
 | ||||
|   showComponentPalette = false; | ||||
|   WidgetsMock: WidgetModel[] = [ | ||||
|     { | ||||
|       name: 'Bar Chart', | ||||
|       identifier: 'bar_chart' | ||||
|     }, | ||||
|     { | ||||
|       name: 'Doughnut Chart', | ||||
|       identifier: 'doughnut_chart' | ||||
|     }, | ||||
|     { | ||||
|       name: 'Map Chart', | ||||
|       identifier: 'map_chart' | ||||
|     }, | ||||
|     { | ||||
|       name: 'Data Table', | ||||
|       identifier: 'grid_view' | ||||
|     }, | ||||
|     { | ||||
|       name: 'Deal Details', | ||||
|       identifier: 'to_do_chart' | ||||
|     }, | ||||
|     { | ||||
|       name: 'Quarterwise Flow', | ||||
|       identifier: 'line_chart' | ||||
|     } | ||||
|   ]; | ||||
|    | ||||
|   // Keep track of deleted items
 | ||||
|   deletedItems: Array<ShieldDashboardItem> = []; | ||||
| 
 | ||||
|   constructor() { } | ||||
| 
 | ||||
| @ -22,7 +60,7 @@ export class ShieldDashboardComponent implements OnInit { | ||||
|     this.options = { | ||||
|       gridType: 'fit', | ||||
|       enableEmptyCellDrop: true, | ||||
|       emptyCellDropCallback: this.onDrop.bind(this), | ||||
|       emptyCellDropCallback: this.onDrop, | ||||
|       pushItems: true, | ||||
|       swap: true, | ||||
|       pushDirections: { north: true, east: true, south: true, west: true }, | ||||
| @ -41,26 +79,164 @@ export class ShieldDashboardComponent implements OnInit { | ||||
|       itemResizeCallback: this.itemResize.bind(this) | ||||
|     }; | ||||
| 
 | ||||
|     // Initialize the dashboard with default components
 | ||||
|     this.dashboard = [ | ||||
|       { cols: 5, rows: 6, y: 0, x: 0, chartType: 'bar-chart', name: 'Bar Chart', id: 1 }, | ||||
|       { cols: 5, rows: 6, y: 0, x: 5, chartType: 'donut-chart', name: 'End Customer', id: 2 }, | ||||
|       { cols: 5, rows: 6, y: 6, x: 0, chartType: 'donut-chart', name: 'Segment Penetration', id: 3 }, | ||||
|       { cols: 5, rows: 6, y: 6, x: 5, chartType: 'map-chart', name: 'Map Chart', id: 4 }, | ||||
|       { cols: 10, rows: 6, y: 12, x: 0, chartType: 'data-table', name: 'Data Table', id: 5 }, | ||||
|       { cols: 5, rows: 6, y: 18, x: 0, chartType: 'deal-details', name: 'Deal Details', id: 6 }, | ||||
|       { cols: 5, rows: 6, y: 18, x: 5, chartType: 'quarterwise-flow', name: 'Quarterwise Flow', id: 7 } | ||||
|     ]; | ||||
|     // Initialize the dashboard with empty canvas
 | ||||
|     this.dashboard = []; | ||||
|   } | ||||
|    | ||||
|   // Toggle component palette visibility
 | ||||
|   toggleComponentPalette(): void { | ||||
|     this.showComponentPalette = !this.showComponentPalette; | ||||
|   } | ||||
|    | ||||
|   // Handle drag start event for components - matching the working implementation
 | ||||
|   onDrag(event: DragEvent, identifier: string): void { | ||||
|     console.log("on drag", identifier); | ||||
|     console.log("on drag ", event); | ||||
|     if (event.dataTransfer) { | ||||
|       event.dataTransfer.setData('widgetIdentifier', identifier); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   onDrop(event: any) { | ||||
|   onDrop(ev: any) { | ||||
|     // Handle dropping new components onto the dashboard
 | ||||
|     console.log('Item dropped:', event); | ||||
|     console.log('Item dropped:', ev); | ||||
|      | ||||
|     // Get the component identifier from the drag event
 | ||||
|     const componentType = ev.dataTransfer ? ev.dataTransfer.getData('widgetIdentifier') : ''; | ||||
|     console.log('Component type dropped:', componentType); | ||||
|      | ||||
|     if (componentType) { | ||||
|       this.addComponentToDashboard(componentType); | ||||
|     } else { | ||||
|       console.log('No component type found in drag data'); | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   // Add a new component to the dashboard
 | ||||
|   addComponentToDashboard(componentType: string) { | ||||
|     // Generate a new ID for the component
 | ||||
|     const newId = this.dashboard.length > 0 ? Math.max(...this.dashboard.map(item => item.id), 0) + 1 : 1; | ||||
|      | ||||
|     let newItem: ShieldDashboardItem; | ||||
|      | ||||
|     switch (componentType) { | ||||
|       case "bar_chart": | ||||
|         newItem = {  | ||||
|           cols: 5,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: 'bar-chart',  | ||||
|           name: 'Bar Chart',  | ||||
|           id: newId | ||||
|         }; | ||||
|         break; | ||||
|       case "doughnut_chart": | ||||
|         // For doughnut charts, we'll need to determine which one based on existing items
 | ||||
|         const donutCount = this.dashboard.filter(item => item.chartType === 'donut-chart').length; | ||||
|         if (donutCount % 2 === 0) { | ||||
|           newItem = {  | ||||
|             cols: 5,  | ||||
|             rows: 6,  | ||||
|             y: 0,  | ||||
|             x: 0,  | ||||
|             chartType: 'donut-chart',  | ||||
|             name: 'End Customer Donut',  | ||||
|             id: newId | ||||
|           }; | ||||
|         } else { | ||||
|           newItem = {  | ||||
|             cols: 5,  | ||||
|             rows: 6,  | ||||
|             y: 0,  | ||||
|             x: 0,  | ||||
|             chartType: 'donut-chart',  | ||||
|             name: 'Segment Penetration Donut',  | ||||
|             id: newId | ||||
|           }; | ||||
|         } | ||||
|         break; | ||||
|       case "map_chart": | ||||
|         newItem = {  | ||||
|           cols: 5,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: 'map-chart',  | ||||
|           name: 'Map Chart',  | ||||
|           id: newId | ||||
|         }; | ||||
|         break; | ||||
|       case "grid_view": | ||||
|         newItem = {  | ||||
|           cols: 10,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: 'data-table',  | ||||
|           name: 'Data Table',  | ||||
|           id: newId | ||||
|         }; | ||||
|         break; | ||||
|       case "to_do_chart": | ||||
|         newItem = {  | ||||
|           cols: 5,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: 'deal-details',  | ||||
|           name: 'Deal Details',  | ||||
|           id: newId | ||||
|         }; | ||||
|         break; | ||||
|       case "line_chart": | ||||
|         newItem = {  | ||||
|           cols: 5,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: 'quarterwise-flow',  | ||||
|           name: 'Quarterwise Flow',  | ||||
|           id: newId | ||||
|         }; | ||||
|         break; | ||||
|       default: | ||||
|         newItem = {  | ||||
|           cols: 5,  | ||||
|           rows: 6,  | ||||
|           y: 0,  | ||||
|           x: 0,  | ||||
|           chartType: componentType,  | ||||
|           name: componentType,  | ||||
|           id: newId | ||||
|         }; | ||||
|     } | ||||
|      | ||||
|     // Add the new item to the dashboard
 | ||||
|     this.dashboard.push(newItem); | ||||
|   } | ||||
| 
 | ||||
|   removeItem(item: ShieldDashboardItem) { | ||||
|     // Add the item to deleted items list before removing
 | ||||
|     this.deletedItems.push({...item}); | ||||
|      | ||||
|     // Remove the item from the dashboard
 | ||||
|     this.dashboard.splice(this.dashboard.indexOf(item), 1); | ||||
|   } | ||||
|    | ||||
|   // Restore a deleted item
 | ||||
|   restoreItem(item: ShieldDashboardItem) { | ||||
|     // Remove from deleted items
 | ||||
|     this.deletedItems.splice(this.deletedItems.indexOf(item), 1); | ||||
|      | ||||
|     // Add back to dashboard
 | ||||
|     this.dashboard.push(item); | ||||
|   } | ||||
|    | ||||
|   // Clear all deleted items
 | ||||
|   clearDeletedItems() { | ||||
|     this.deletedItems = []; | ||||
|   } | ||||
| 
 | ||||
|   itemChange() { | ||||
|     console.log('Item changed:', this.dashboard); | ||||
| @ -71,4 +247,25 @@ export class ShieldDashboardComponent implements OnInit { | ||||
|     // Trigger a window resize event to notify charts to resize
 | ||||
|     window.dispatchEvent(new Event('resize')); | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|    * Extract only the relevant chart configuration properties to pass to chart components | ||||
|    * This prevents errors when trying to set properties that don't exist on the components | ||||
|    */ | ||||
|   getChartInputs(item: any): any { | ||||
|     // Only pass properties that are relevant to chart components
 | ||||
|     const chartInputs = { | ||||
|       chartType: item.chartType, | ||||
|       name: item.name | ||||
|     }; | ||||
|      | ||||
|     // Remove undefined properties to avoid passing unnecessary data
 | ||||
|     Object.keys(chartInputs).forEach(key => { | ||||
|       if (chartInputs[key] === undefined) { | ||||
|         delete chartInputs[key]; | ||||
|       } | ||||
|     }); | ||||
|      | ||||
|     return chartInputs; | ||||
|   } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user