Commit 2ad457f5 by Ooh-Ao

s

parent cc462cc0
......@@ -744,8 +744,7 @@ export class DashboardManagementComponent implements OnInit {
this.dashboardData.datasetId = dataset.itemId;
this.dashboardData.templateId = dataset.templateId;
this.dashboardData.fileName = dataset.fileName;
this.dashboardStateService.selectDataset(dataset);
// this.getDatasetByTemplate(dataset);
this.dashboardStateService.selectDataset(dataset.itemId);
}
}
......
<div *ngIf="errorMessage" class="alert alert-danger">{{errorMessage}}</div>
<div class="dashboard-viewer-container">
<div *ngIf="dashboardData" class="dashboard-viewer-container p-4">
<h1 class="text-2xl font-bold mb-4 text-gray-800">{{ dashboardData.thName }}</h1>
<div class="control-section">
<ejs-dashboardlayout id='dashboard_viewer' #viewerLayout [cellSpacing]="cellSpacing" [panels]="panels" [columns]="6" [allowResizing]="false" [allowDragging]="false">
<e-panels>
<e-panel *ngFor="let panel of panels" [row]="panel.row" [col]="panel.col" [sizeX]="panel.sizeX" [sizeY]="panel.sizeY" [id]="panel.id">
<ng-template #header>
<div class="p-2 bg-white border-b border-gray-200 text-gray-700 font-semibold flex justify-between items-center">
<div class="e-panel-header flex justify-between items-center">
<span>{{panel.header}}</span>
</div>
</ng-template>
......
import { Component, OnInit, Type, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; // Import Type
import { Component, OnInit, Type, ChangeDetectorRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, RouterModule } from '@angular/router';
import { DashboardLayoutModule, PanelModel } from '@syncfusion/ej2-angular-layouts';
import { Observable, of, forkJoin } from 'rxjs'; // Import forkJoin
import { map, switchMap, tap } from 'rxjs/operators'; // Import tap
import { NgComponentOutlet } from '@angular/common'; // Import NgComponentOutlet
import { of } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';
import { NgComponentOutlet } from '@angular/common';
import { DashboardDataService } from '../services/dashboard-data.service';
import { WidgetDataService } from '../services/widget-data.service';
import { DashboardModel, WidgetModel } from '../models/widgets.model';
import { DashboardStateService } from '../services/dashboard-state.service'; // Import DashboardStateService
import { DashboardStateService } from '../services/dashboard-state.service';
// Import all the widget components
// Import all widget components
import { CompanyInfoWidgetComponent } from '../widgets/company-info-widget.component';
import { HeadcountWidgetComponent } from '../widgets/headcount-widget.component';
import { AttendanceOverviewWidgetComponent } from '../widgets/attendance-overview-widget.component';
......@@ -20,11 +19,10 @@ import { KpiWidgetComponent } from '../widgets/kpi-widget/kpi-widget.component';
import { WelcomeWidgetComponent } from '../widgets/welcome-widget/welcome-widget.component';
import { ChartWidgetComponent } from '../widgets/chart-widget/chart-widget.component';
import { QuickLinksWidgetComponent } from '../widgets/quick-links-widget/quick-links-widget.component';
// New Syncfusion Widget Imports
import { SyncfusionDatagridWidgetComponent } from '../widgets/syncfusion-datagrid-widget/syncfusion-datagrid-widget.component';
import { SyncfusionPivotWidgetComponent } from '../widgets/syncfusion-pivot-widget/syncfusion-pivot-widget.component';
import { SyncfusionChartWidgetComponent } from '../widgets/syncfusion-chart-widget/syncfusion-chart-widget.component';
import { DataTableWidgetComponent } from '../widgets/dynamic-widgets/data-table-widget.component'; // Import new widget
import { DataTableWidgetComponent } from '../widgets/dynamic-widgets/data-table-widget.component';
import { AreaChartWidgetComponent } from '../widgets/area-chart-widget/area-chart-widget.component';
import { BarChartWidgetComponent } from '../widgets/bar-chart-widget/bar-chart-widget.component';
import { PieChartWidgetComponent } from '../widgets/pie-chart-widget/pie-chart-widget.component';
......@@ -41,49 +39,30 @@ import { SlicerWidgetComponent } from '../widgets/slicer-widget/slicer-widget.co
import { SimpleTableWidgetComponent } from '../widgets/simple-table-widget/simple-table-widget.component';
import { WaterfallChartWidgetComponent } from '../widgets/waterfall-chart-widget/waterfall-chart-widget.component';
import { TreemapWidgetComponent } from '../widgets/treemap-widget/treemap-widget.component';
import { HttpClientModule } from '@angular/common/http';
export interface DashboardPanel extends PanelModel {
componentType: Type<any>;
componentInputs?: { [key: string]: any };
}
@Component({
selector: 'app-dashboard-viewer',
standalone: true,
imports: [
CommonModule,
RouterModule,
DashboardLayoutModule,
NgComponentOutlet,
SyncfusionDatagridWidgetComponent,
SyncfusionPivotWidgetComponent,
SyncfusionChartWidgetComponent,
DataTableWidgetComponent, // Add new widget to imports
AreaChartWidgetComponent,
BarChartWidgetComponent,
PieChartWidgetComponent,
ScatterBubbleChartWidgetComponent,
MultiRowCardWidgetComponent,
ComboChartWidgetComponent,
DoughnutChartWidgetComponent,
FunnelChartWidgetComponent,
GaugeChartWidgetComponent,
SimpleKpiWidgetComponent,
FilledMapWidgetComponent,
MatrixWidgetComponent,
SlicerWidgetComponent,
SimpleTableWidgetComponent,
WaterfallChartWidgetComponent,
TreemapWidgetComponent,
CommonModule, RouterModule, DashboardLayoutModule, NgComponentOutlet,
// Add all widget components here to make them available for NgComponentOutlet
CompanyInfoWidgetComponent, HeadcountWidgetComponent, AttendanceOverviewWidgetComponent, PayrollSummaryWidgetComponent, EmployeeDirectoryWidgetComponent, KpiWidgetComponent, WelcomeWidgetComponent, ChartWidgetComponent, QuickLinksWidgetComponent, SyncfusionDatagridWidgetComponent, SyncfusionPivotWidgetComponent, SyncfusionChartWidgetComponent, DataTableWidgetComponent, AreaChartWidgetComponent, BarChartWidgetComponent, PieChartWidgetComponent, ScatterBubbleChartWidgetComponent, MultiRowCardWidgetComponent, ComboChartWidgetComponent, DoughnutChartWidgetComponent, FunnelChartWidgetComponent, GaugeChartWidgetComponent, SimpleKpiWidgetComponent, FilledMapWidgetComponent, MatrixWidgetComponent, SlicerWidgetComponent, SimpleTableWidgetComponent, WaterfallChartWidgetComponent, TreemapWidgetComponent
],
templateUrl: './dashboard-viewer.component.html',
styleUrls: ['./dashboard-viewer.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class DashboardViewerComponent implements OnInit {
public panels: (PanelModel & { componentType: Type<any>, componentInputs?: { [key: string]: any }, componentName?: string })[] = []; // Update type
public panels: DashboardPanel[] = [];
public cellSpacing: number[] = [10, 10];
public dashboardName: string = '';
public dashboardData: DashboardModel | null = null;
public errorMessage: string | null = null;
// Map string names to actual component classes
private widgetComponentMap: { [key: string]: Type<any> } = {
'CompanyInfoWidgetComponent': CompanyInfoWidgetComponent,
'HeadcountWidgetComponent': HeadcountWidgetComponent,
......@@ -94,11 +73,10 @@ export class DashboardViewerComponent implements OnInit {
'WelcomeWidgetComponent': WelcomeWidgetComponent,
'ChartWidgetComponent': ChartWidgetComponent,
'QuickLinksWidgetComponent': QuickLinksWidgetComponent,
// New Syncfusion Widget Mappings
'SyncfusionDatagridWidgetComponent': SyncfusionDatagridWidgetComponent,
'SyncfusionPivotWidgetComponent': SyncfusionPivotWidgetComponent,
'SyncfusionChartWidgetComponent': SyncfusionChartWidgetComponent,
'NewDataTableWidget': DataTableWidgetComponent, // Add new widget to map
'NewDataTableWidget': DataTableWidgetComponent,
'AreaChartWidgetComponent': AreaChartWidgetComponent,
'BarChartWidgetComponent': BarChartWidgetComponent,
'PieChartWidgetComponent': PieChartWidgetComponent,
......@@ -117,14 +95,10 @@ export class DashboardViewerComponent implements OnInit {
'TreemapWidgetComponent': TreemapWidgetComponent,
};
public errorMessage: string | null = null;
constructor(
private route: ActivatedRoute,
private dashboardDataService: DashboardDataService,
private dashboardStateService: DashboardStateService, // Inject DashboardStateService
private widgetDataService: WidgetDataService,
private cdr: ChangeDetectorRef
private dashboardStateService: DashboardStateService,
) { }
ngOnInit(): void {
......@@ -133,7 +107,6 @@ export class DashboardViewerComponent implements OnInit {
switchMap(id => {
if (!id) {
this.errorMessage = 'Dashboard ID is missing from the route.';
console.error(this.errorMessage);
return of(null);
}
return this.dashboardDataService.getDashboardById(id);
......@@ -141,7 +114,11 @@ export class DashboardViewerComponent implements OnInit {
).subscribe({
next: dashboard => {
if (dashboard) {
this.loadDashboard(dashboard);
this.dashboardData = dashboard;
this.panels = this.mapWidgetsToPanels(dashboard.widgets || []);
if (dashboard.datasetId) {
this.dashboardStateService.selectDataset(dashboard.datasetId);
}
} else {
this.errorMessage = 'Could not load the dashboard.';
}
......@@ -150,49 +127,19 @@ export class DashboardViewerComponent implements OnInit {
});
}
loadDashboard(dashboard: DashboardModel): void {
this.dashboardName = dashboard.thName;
if (dashboard.datasetId) {
// this.dashboardStateService.selectDataset(dashboard.datasetId);
}
// Process widgets and fetch data if necessary
const dataFetchTasks: Observable<any>[] = dashboard.widgets
.filter(widget => widget.config?.source?.type === 'url' && widget.config?.source?.url)
.map(widget =>
this.widgetDataService.fetchDataForWidget(widget.config).pipe(
tap(data => {
// Mutate the config object to include the fetched data
widget.config.data = data;
})
)
);
if (dataFetchTasks.length > 0) {
forkJoin(dataFetchTasks).subscribe(() => {
this.createPanels(dashboard.widgets);
});
} else {
this.createPanels(dashboard.widgets);
}
}
createPanels(widgets: WidgetModel[]): void {
this.panels = widgets.map(widget => {
mapWidgetsToPanels(widgets: WidgetModel[]): DashboardPanel[] {
return widgets.map(widget => {
const widgetConfig = widget.config || {};
return {
id: widget.widgetId,
row: widget.y,
col: widget.x,
header: widget.thName,
sizeX: widget.cols,
sizeY: widget.rows,
header: widget.thName,
componentName: widget.component,
row: widget.y,
col: widget.x,
componentType: this.widgetComponentMap[widget.component],
componentInputs: { config: widgetConfig }
componentInputs: { config: widgetConfig },
};
});
this.cdr.detectChanges(); // Manually trigger change detection
}
}
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { switchMap, map, shareReplay } from 'rxjs/operators';
import { switchMap, map, shareReplay, tap } from 'rxjs/operators';
import { DatasetService } from './dataset.service';
import { HttpClient } from '@angular/common/http';
import { DatasetModel } from '../models/widgets.model';
......@@ -14,35 +14,43 @@ export interface SelectedDataset {
providedIn: 'root'
})
export class DashboardStateService {
private selectedDatasetId = new BehaviorSubject<DatasetModel | null>(null);
private selectedDatasetId = new BehaviorSubject<string | null>(null);
public selectedDataset$: Observable<SelectedDataset | null>;
constructor(private datasetService: DatasetService, private http: HttpClient) {
this.selectedDataset$ = this.selectedDatasetId.pipe(
switchMap(dataset => {
if (dataset) {
return this.datasetService.getDatasetByTemplate(dataset.templateId, dataset.fileName).pipe(
switchMap(id => {
if (!id) {
return of(null);
}
// First, get all datasets to find the selected one's details
return this.datasetService.getDatasets().pipe(
switchMap(datasets => {
const selected = datasets.find(d => d.itemId === id);
if (selected) {
// Now fetch the actual data using templateId and fileName
return this.datasetService.getDatasetByTemplate(selected.templateId, selected.fileName).pipe(
map(response => {
// The API might return an array directly, or an object with a 'data' property.
const dataArray = Array.isArray(response) ? response : (response && Array.isArray(response.data)) ? response.data : null;
if (dataArray && dataArray.length > 0) {
return {
data: dataArray,
columns: Object.keys(dataArray[0])
};
}
return null; // Return null if data is not in the expected format
return null;
})
);
}
return of(null); // No dataset ID selected
return of(null); // Dataset with the given ID not found
})
);
}),
shareReplay(1) // Cache and replay the last emitted value
shareReplay(1)
);
}
selectDataset(dataset: DatasetModel): void {
this.selectedDatasetId.next(dataset);
selectDataset(datasetId: string | null): void {
this.selectedDatasetId.next(datasetId);
}
}
......@@ -49,3 +49,4 @@ export class ComboChartWidgetComponent extends BaseWidgetComponent {
];
}
}
......@@ -65,3 +65,4 @@ export class FilledMapWidgetComponent extends BaseWidgetComponent {
];
}
}
......@@ -64,3 +64,4 @@ export class GaugeChartWidgetComponent extends BaseWidgetComponent {
}];
}
}
......@@ -58,3 +58,4 @@ export class ScatterBubbleChartWidgetComponent extends BaseWidgetComponent {
this.primaryYAxis = { title: 'Y-Value' };
}
}
......@@ -51,3 +51,4 @@ export class TreemapWidgetComponent extends BaseWidgetComponent {
};
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment