Commit eb235a94 by Ooh-Ao

config

parent 2176373c
......@@ -33,8 +33,6 @@ import { QuickLinksWidgetComponent } from '../widgets/quick-links-widget/quick-l
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 { TimeTrackingWidgetComponent } from '../widgets/time-tracking-widget/time-tracking-widget.component';
import { PayrollWidgetComponent } from '../widgets/payroll-widget/payroll-widget.component';
import { DatasetPickerComponent } from './dataset-picker.component';
import { DataTableWidgetComponent } from '../widgets/dynamic-widgets/data-table-widget.component'; // Import new widget
import { AccumulationChartAllModule, ChartAllModule } from '@syncfusion/ej2-angular-charts';
......@@ -744,111 +742,111 @@ export class DashboardManagementComponent implements OnInit {
if (this.dashboardData) {
this.dashboardData.datasetId = dataset.itemId;
this.dashboardStateService.selectDataset(dataset);
this.getDatasetByTemplate(dataset);
// this.getDatasetByTemplate(dataset);
}
}
getDatasetByTemplate(dataset: DatasetModel): void {
this.datasetService.getDatasetByTemplate(dataset.templateId, dataset.fileName).subscribe(dataset => {
if (dataset && this.dashboardData) {
// Update the config of each widget with the new data
this.dashboardData.widgets.forEach(widget => {
if (widget.config) {
widget.config.source.data = dataset; // Assuming the dataset is the data source
}
});
// Remap panels to reflect the changes
this.panels = this.mapWidgetsToPanels(this.dashboardData.widgets);
}
}, (error) => {
console.error('Error fetching dataset by template:', error);
let dataset = [
{
"id": "E001",
"name": "Alice Smith",
"department": "Sales",
"salary": 60000,
"hireDate": "2020-01-15",
"performanceScore": 85,
"gender": "Female",
"age": 30,
"salesAmount": 120000,
"region": "North"
},
{
"id": "E002",
"name": "Bob Johnson",
"department": "Marketing",
"salary": 55000,
"hireDate": "2019-03-20",
"performanceScore": 92,
"gender": "Male",
"age": 35,
"salesAmount": 0,
"region": "East"
},
{
"id": "E003",
"name": "Charlie Brown",
"department": "Sales",
"salary": 62000,
"hireDate": "2021-07-01",
"performanceScore": 78,
"gender": "Male",
"age": 28,
"salesAmount": 110000,
"region": "West"
},
{
"id": "E004",
"name": "Diana Prince",
"department": "HR",
"salary": 70000,
"hireDate": "2018-11-10",
"performanceScore": 95,
"gender": "Female",
"age": 40,
"salesAmount": 0,
"region": "South"
},
{
"id": "E005",
"name": "Eve Adams",
"department": "Marketing",
"salary": 58000,
"hireDate": "2022-05-25",
"performanceScore": 88,
"gender": "Female",
"age": 25,
"salesAmount": 0,
"region": "North"
},
{
"id": "E006",
"name": "Frank White",
"department": "Sales",
"salary": 65000,
"hireDate": "2019-09-01",
"performanceScore": 90,
"gender": "Male",
"age": 32,
"salesAmount": 130000,
"region": "East"
}
]
if (dataset && this.dashboardData) {
// Update the config of each widget with the new data
this.dashboardData.widgets.forEach(widget => {
if (widget.config) {
widget.config.source.data = dataset; // Assuming the dataset is the data source
}
});
// Remap panels to reflect the changes
this.panels = this.mapWidgetsToPanels(this.dashboardData.widgets);
}
});
}
// getDatasetByTemplate(dataset: DatasetModel): void {
// this.datasetService.getDatasetByTemplate(dataset.templateId, dataset.fileName).subscribe(dataset => {
// if (dataset && this.dashboardData) {
// // Update the config of each widget with the new data
// this.dashboardData.widgets.forEach(widget => {
// if (widget.config) {
// widget.config.source.data = dataset; // Assuming the dataset is the data source
// }
// });
// // Remap panels to reflect the changes
// this.panels = this.mapWidgetsToPanels(this.dashboardData.widgets);
// }
// }, (error) => {
// console.error('Error fetching dataset by template:', error);
// let dataset = [
// {
// "id": "E001",
// "name": "Alice Smith",
// "department": "Sales",
// "salary": 60000,
// "hireDate": "2020-01-15",
// "performanceScore": 85,
// "gender": "Female",
// "age": 30,
// "salesAmount": 120000,
// "region": "North"
// },
// {
// "id": "E002",
// "name": "Bob Johnson",
// "department": "Marketing",
// "salary": 55000,
// "hireDate": "2019-03-20",
// "performanceScore": 92,
// "gender": "Male",
// "age": 35,
// "salesAmount": 0,
// "region": "East"
// },
// {
// "id": "E003",
// "name": "Charlie Brown",
// "department": "Sales",
// "salary": 62000,
// "hireDate": "2021-07-01",
// "performanceScore": 78,
// "gender": "Male",
// "age": 28,
// "salesAmount": 110000,
// "region": "West"
// },
// {
// "id": "E004",
// "name": "Diana Prince",
// "department": "HR",
// "salary": 70000,
// "hireDate": "2018-11-10",
// "performanceScore": 95,
// "gender": "Female",
// "age": 40,
// "salesAmount": 0,
// "region": "South"
// },
// {
// "id": "E005",
// "name": "Eve Adams",
// "department": "Marketing",
// "salary": 58000,
// "hireDate": "2022-05-25",
// "performanceScore": 88,
// "gender": "Female",
// "age": 25,
// "salesAmount": 0,
// "region": "North"
// },
// {
// "id": "E006",
// "name": "Frank White",
// "department": "Sales",
// "salary": 65000,
// "hireDate": "2019-09-01",
// "performanceScore": 90,
// "gender": "Male",
// "age": 32,
// "salesAmount": 130000,
// "region": "East"
// }
// ]
// if (dataset && this.dashboardData) {
// // Update the config of each widget with the new data
// this.dashboardData.widgets.forEach(widget => {
// if (widget.config) {
// widget.config.source.data = dataset; // Assuming the dataset is the data source
// }
// });
// // Remap panels to reflect the changes
// this.panels = this.mapWidgetsToPanels(this.dashboardData.widgets);
// }
// });
// }
openWidgetConfigDialog(panel: PanelModel & { componentType: Type<any>, componentInputs?: { [key: string]: any }, originalWidget: WidgetModel }): void {
const widget = panel.originalWidget;
......
......@@ -25,8 +25,6 @@ import { SyncfusionDatagridWidgetComponent } from '../widgets/syncfusion-datagri
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 { TimeTrackingWidgetComponent } from '../widgets/time-tracking-widget/time-tracking-widget.component';
import { PayrollWidgetComponent } from '../widgets/payroll-widget/payroll-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';
......
......@@ -20,10 +20,15 @@ export class AreaChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
applyInitialConfig(): void {
this.title = this.config.title || 'Area Chart';
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.chartData = []; // Start with no data
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
}
onReset(): void {
......
......@@ -42,6 +42,13 @@ export class AttendanceOverviewWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Attendance';
this.present = 0;
this.onLeave = 0;
this.absent = 0;
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
const firstItem = data[0];
......
......@@ -22,11 +22,16 @@ export class BarChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
applyInitialConfig(): void {
this.title = this.config.title || 'Bar Chart';
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.type = this.config.type || 'Column';
this.chartData = [];
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
}
onReset(): void {
......
......@@ -16,7 +16,7 @@ export abstract class BaseWidgetComponent implements OnInit, OnDestroy {
constructor(protected dashboardStateService: DashboardStateService) {}
ngOnInit(): void {
this.title = this.config?.title || 'Widget';
this.applyInitialConfig(); // Apply config first
const datasetSub = this.dashboardStateService.selectedDataset$.subscribe({
next: (selectedDataset: SelectedDataset | null) => {
......@@ -30,8 +30,9 @@ export abstract class BaseWidgetComponent implements OnInit, OnDestroy {
this.handleError(error);
}
} else {
this.onReset();
this.isLoading = false;
// If no dataset is selected, just keep showing the initial config with a loading state.
// The initial state is set by applyInitialConfig().
this.isLoading = true;
}
},
error: (err) => {
......@@ -50,19 +51,23 @@ export abstract class BaseWidgetComponent implements OnInit, OnDestroy {
this.hasError = true;
this.errorMessage = 'An error occurred while loading widget data.';
console.error('Widget Error:', error);
this.onReset();
this.onReset(); // Fallback to a default error state
}
/**
* Abstract method to be implemented by child components.
* This method is called when new data is available from the selected dataset.
* Abstract method for child components to set up their initial state from the config.
* This is called once during ngOnInit.
*/
abstract applyInitialConfig(): void;
/**
* Abstract method for child components to update with new data.
* @param data The data from the selected dataset.
*/
abstract onDataUpdate(data: any[]): void;
/**
* Abstract method to be implemented by child components.
* This method is called when there is no dataset selected or data is not available.
* Abstract method for child components to fall back to a default state on error.
*/
abstract onReset(): void;
}
......@@ -3,7 +3,6 @@ import { CommonModule } from '@angular/common';
import { DashboardStateService } from '../../services/dashboard-state.service';
import { BaseWidgetComponent } from '../base-widget.component';
// Declare ApexCharts globally if it's loaded via a script tag
declare var ApexCharts: any;
@Component({
......@@ -15,7 +14,7 @@ declare var ApexCharts: any;
export class ChartWidgetComponent extends BaseWidgetComponent implements AfterViewInit {
@ViewChild('chart') chartElement!: ElementRef;
private chartInstance: any; // To store the ApexCharts instance
private chartInstance: any;
constructor(protected override dashboardStateService: DashboardStateService) {
super(dashboardStateService);
......@@ -23,15 +22,20 @@ export class ChartWidgetComponent extends BaseWidgetComponent implements AfterVi
ngAfterViewInit(): void {
if (typeof ApexCharts !== 'undefined' && this.chartElement) {
// Initial chart options are set in onReset
this.chartInstance = new ApexCharts(this.chartElement.nativeElement, this.getChartOptions([], []));
this.chartInstance.render();
// The subscription in BaseWidget will trigger onDataUpdate or onReset, which will update the chart.
} else {
console.error('ApexCharts is not loaded or chart element is not available.');
}
}
applyInitialConfig(): void {
this.title = this.config?.title || 'Chart';
if (this.chartInstance) {
this.chartInstance.updateOptions(this.getChartOptions([], []));
}
}
onDataUpdate(data: any[]): void {
const categories = data.map(item => item[this.config.xField]);
const series = this.config.yFields.map((yField: any) => ({
......@@ -106,3 +110,4 @@ export class ChartWidgetComponent extends BaseWidgetComponent implements AfterVi
};
}
}
......@@ -20,10 +20,15 @@ export class ComboChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
this.chartData = data;
applyInitialConfig(): void {
this.title = this.config.title || 'Combo Chart';
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
this.chartData = data;
}
onReset(): void {
......@@ -35,7 +40,6 @@ export class ComboChartWidgetComponent extends BaseWidgetComponent {
];
this.primaryXAxis = { valueType: 'Category', title: 'Month' };
this.primaryYAxis = { title: 'Value' };
// Provide a default series config for the reset state
if (!this.config) {
this.config = {};
}
......
......@@ -40,6 +40,13 @@ export class CompanyInfoWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Company Info';
this.companyName = '...';
this.address = '...';
this.contact = '...';
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
const firstItem = data[0];
......
......@@ -20,6 +20,13 @@ export class CompanyInfoSubfolderWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Company Info';
this.companyName = '...';
this.address = '...';
this.contact = '...';
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
const firstItem = data[0];
......
......@@ -19,8 +19,13 @@ export class DoughnutChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Doughnut Chart';
this.legendSettings = { visible: true };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
let transformedData = data;
if (this.config.aggregation === 'count') {
......
......@@ -43,6 +43,11 @@ export class EmployeeDirectoryWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Employee Directory';
this.employees = [];
}
onDataUpdate(data: any[]): void {
this.employees = data.map(item => ({
name: item[this.config.nameField] || '',
......
......@@ -19,8 +19,13 @@ export class FilledMapWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Map';
this.zoomSettings = { enable: true };
this.updateLayers([]);
}
onDataUpdate(data: any[]): void {
const mapData = data.map(item => ({
country: item[this.config.countryField],
value: item[this.config.valueField]
......
......@@ -19,8 +19,13 @@ export class FunnelChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Funnel Chart';
this.legendSettings = { visible: true };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
}
......
......@@ -18,10 +18,14 @@ export class GaugeChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Gauge';
this.setAxes(0);
}
onDataUpdate(data: any[]): void {
let value = 0;
if (data.length > 0) {
// Assuming gauge shows a single value, either aggregated or the first item's value
if (this.config.aggregation === 'sum') {
value = data.reduce((sum, item) => sum + (item[this.config.valueField] || 0), 0);
} else if (this.config.aggregation === 'avg') {
......
......@@ -47,6 +47,12 @@ export class HeadcountWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Headcount';
this.totalHeadcount = 0;
this.breakdown = [];
}
onDataUpdate(data: any[]): void {
this.totalHeadcount = data.length;
if (this.config.categoryField) {
......
......@@ -10,12 +10,22 @@ import { BaseWidgetComponent } from '../base-widget.component';
templateUrl: './kpi-widget.component.html',
})
export class KpiWidgetComponent extends BaseWidgetComponent {
public kpiData: any = { value: 0, trend: 'neutral', trendValue: '' };
public kpiData: any = { value: '...', trend: 'neutral', trendValue: '' };
constructor(protected override dashboardStateService: DashboardStateService) {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'KPI';
this.kpiData = {
value: '...',
unit: this.config.unit || '',
trend: this.config.trend || 'neutral',
trendValue: this.config.trendValue || ''
};
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
let kpiValue = 0;
......@@ -26,12 +36,7 @@ export class KpiWidgetComponent extends BaseWidgetComponent {
} else {
kpiValue = data[0][this.config.valueField];
}
this.kpiData = {
value: kpiValue.toLocaleString(),
unit: this.config.unit || '',
trend: this.config.trend || 'neutral',
trendValue: this.config.trendValue || ''
};
this.kpiData.value = kpiValue.toLocaleString();
}
}
......
......@@ -18,12 +18,15 @@ export class MatrixWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Matrix';
this.headers = this.config.columns ? this.config.columns.map((col: any) => col.headerText) : [];
this.data = [];
}
onDataUpdate(data: any[]): void {
if (this.config?.columns && data?.length > 0) {
this.headers = this.config.columns.map((col: any) => col.headerText);
this.data = data.map(row => this.config.columns.map((col: any) => row[col.field]));
} else {
this.onReset();
}
}
......
......@@ -17,6 +17,11 @@ export class MultiRowCardWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Multi-Row Card';
this.cardData = [];
}
onDataUpdate(data: any[]): void {
this.cardData = data.map(item => ({
label: item[this.config.labelField],
......
......@@ -40,6 +40,12 @@ export class PayrollSummaryWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Payroll Summary';
this.totalPayroll = 0;
this.employeesPaid = 0;
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
const firstItem = data[0];
......
<div class="card h-100">
<div class="card-header">
<h5 class="card-title">{{ title }}</h5>
</div>
<div class="card-body">
<!-- Loading State -->
<div *ngIf="isLoading" class="flex justify-center items-center h-full">
<div class="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500"></div>
</div>
<!-- Error State -->
<div *ngIf="hasError" class="flex flex-col justify-center items-center h-full text-red-500">
<i class="bi bi-exclamation-triangle-fill text-4xl"></i>
<p class="mt-2">{{ errorMessage }}</p>
</div>
<!-- Content -->
<div *ngIf="!isLoading && !hasError">
<p>Employee: {{ employeeName }}</p>
<p>Pay Period: {{ payPeriod }}</p>
<p>Net Pay: {{ netPay | currency }}</p>
</div>
</div>
</div>
/* Add any specific styles for the payroll widget here */
.card {
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DashboardStateService } from '../../services/dashboard-state.service';
import { BaseWidgetComponent } from '../base-widget.component';
@Component({
selector: 'app-payroll-widget',
standalone: true,
imports: [CommonModule],
templateUrl: './payroll-widget.component.html',
styleUrls: ['./payroll-widget.component.scss']
})
export class PayrollWidgetComponent extends BaseWidgetComponent {
public employeeName: string = '';
public payPeriod: string = '';
public netPay: number = 0;
constructor(protected override dashboardStateService: DashboardStateService) {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
const firstItem = data[0];
this.employeeName = firstItem[this.config.employeeNameField] || '';
this.payPeriod = firstItem[this.config.payPeriodField] || '';
this.netPay = firstItem[this.config.netPayField] || 0;
}
}
onReset(): void {
this.title = 'Payroll (Default)';
this.employeeName = 'N/A';
this.payPeriod = 'N/A';
this.netPay = 0;
}
}
......@@ -19,8 +19,13 @@ export class PieChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Pie Chart';
this.legendSettings = { visible: true };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
let transformedData = data;
if (this.config.aggregation === 'count') {
......
......@@ -16,6 +16,11 @@ export class QuickLinksWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Quick Links';
this.quickLinks = this.config.links || []; // Use links from config if available
}
onDataUpdate(data: any[]): void {
if (this.config.nameField && this.config.urlField) {
this.quickLinks = data.map(item => ({
......
......@@ -22,15 +22,20 @@ export class ScatterBubbleChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Scatter Chart';
this.type = this.config.type || 'Scatter';
this.primaryXAxis = { title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
if (this.type === 'Bubble') {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField], size: item[this.config.sizeField] }));
} else {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
}
this.primaryXAxis = { title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
}
onReset(): void {
......
......@@ -12,7 +12,7 @@ import { BaseWidgetComponent } from '../base-widget.component';
styleUrls: ['./simple-kpi-widget.component.scss']
})
export class SimpleKpiWidgetComponent extends BaseWidgetComponent {
public value: string = '0';
public value: string = '...';
public unit: string = '';
public trend: 'up' | 'down' | 'neutral' = 'neutral';
public trendValue: string = '';
......@@ -21,6 +21,14 @@ export class SimpleKpiWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'KPI';
this.unit = this.config.unit || '';
this.trend = this.config.trend || 'neutral';
this.trendValue = this.config.trendValue || '';
this.value = '...'; // Loading indicator
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
let kpiValue = 0;
......@@ -33,9 +41,6 @@ export class SimpleKpiWidgetComponent extends BaseWidgetComponent {
kpiValue = data[0][this.config.valueField];
}
this.value = kpiValue.toLocaleString();
this.unit = this.config.unit || '';
this.trend = this.config.trend || 'neutral';
this.trendValue = this.config.trendValue || '';
}
}
......
......@@ -19,17 +19,20 @@ export class SimpleTableWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Table';
this.headers = this.config.columns ? this.config.columns.map((col: any) => col.headerText) : [];
this.data = [];
}
onDataUpdate(data: any[]): void {
if (data && data.length > 0 && this.config?.columns) {
this.headers = this.config.columns.map((col: any) => col.headerText);
this.data = data.map(row => this.config.columns.map((col: any) => row[col.field]));
} else {
this.onReset();
}
}
onReset(): void {
// Display placeholder data or an empty state
this.title = 'Table (Default)';
this.headers = ['ID', 'Name', 'Status'];
this.data = [
[1, 'Item A', 'Active'],
......
......@@ -20,6 +20,12 @@ export class SlicerWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Slicer';
this.options = ['All'];
this.selectedValue = 'All';
}
onDataUpdate(data: any[]): void {
if (this.config.optionsField) {
const uniqueOptions = [...new Set(data.map((item: any) => item[this.config.optionsField]))];
......@@ -35,8 +41,6 @@ export class SlicerWidgetComponent extends BaseWidgetComponent {
}
onSelectionChange(): void {
// Note: In a real scenario, this should probably update the global state
// via DashboardStateService so other widgets can react to the filter.
this.selectionChange.emit(this.selectedValue);
}
}
......@@ -22,11 +22,16 @@ export class SyncfusionChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Syncfusion Chart';
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.chartData = new DataManager([]);
}
onDataUpdate(data: any[]): void {
const dm = new DataManager(data);
this.chartData = new DataManager(dm.executeLocal(new Query()).map((item: any) => ({ x: item[this.config.xField], y: item[this.config.yField] })));
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
}
onReset(): void {
......
......@@ -21,6 +21,12 @@ export class SyncfusionDatagridWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || 'Data Grid';
this.columns = this.config.columns || [];
this.data = new DataManager([]);
}
onDataUpdate(data: any[]): void {
this.data = new DataManager(data); // Initialize DataManager with the data
if (this.config.columns && this.config.columns.length > 0) {
......
......@@ -33,9 +33,10 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: IDataSet[]): void {
applyInitialConfig(): void {
this.title = this.config.title || 'Pivot Table';
this.dataSourceSettings = {
dataSource: new DataManager(data), // Initialize DataManager with the data
dataSource: new DataManager([]),
expandAll: this.config.expandAll || false,
rows: this.config.rows || [],
columns: this.config.columns || [],
......@@ -44,6 +45,10 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent {
};
}
onDataUpdate(data: IDataSet[]): void {
this.dataSourceSettings.dataSource = new DataManager(data);
}
onReset(): void {
this.title = 'Pivot Table (Default)';
this.dataSourceSettings = {
......
<div class="card h-100">
<div class="card-header">
<h5 class="card-title">{{ title }}</h5>
</div>
<div class="card-body">
<!-- Loading State -->
<div *ngIf="isLoading" class="flex justify-center items-center h-full">
<div class="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-blue-500"></div>
</div>
<!-- Error State -->
<div *ngIf="hasError" class="flex flex-col justify-center items-center h-full text-red-500">
<i class="bi bi-exclamation-triangle-fill text-4xl"></i>
<p class="mt-2">{{ errorMessage }}</p>
</div>
<!-- Content -->
<div *ngIf="!isLoading && !hasError" class="flex flex-col justify-center items-center h-full">
<p class="text-xl font-semibold">Status: {{ status }}</p>
<p class="text-lg">Hours Today: {{ hours }}</p>
</div>
</div>
</div>
/* Add any specific styles for the time tracking widget here */
.card {
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DashboardStateService } from '../../services/dashboard-state.service';
import { BaseWidgetComponent } from '../base-widget.component';
@Component({
selector: 'app-time-tracking-widget',
standalone: true,
imports: [CommonModule],
templateUrl: './time-tracking-widget.component.html',
styleUrls: ['./time-tracking-widget.component.scss']
})
export class TimeTrackingWidgetComponent extends BaseWidgetComponent {
public status: string = '';
public hours: string = '';
constructor(protected override dashboardStateService: DashboardStateService) {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
if (data.length > 0) {
// Assuming time tracking data is for a single user, so take the first item
const timeEntry = data[0];
this.status = this.config.statusField ? timeEntry[this.config.statusField] : 'N/A';
this.hours = this.config.hoursField ? timeEntry[this.config.hoursField] : 'N/A';
} else {
this.onReset();
}
}
onReset(): void {
this.title = 'Time Tracking (Default)';
this.status = 'Clocked In';
this.hours = '8.0';
}
}
......@@ -20,13 +20,18 @@ export class TreemapWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
this.dataSource = data;
applyInitialConfig(): void {
this.title = this.config.title || 'Treemap';
this.weightValuePath = this.config.valueField;
this.leafItemSettings = {
labelPath: this.config.groupField,
showLabels: true
};
this.dataSource = [];
}
onDataUpdate(data: any[]): void {
this.dataSource = data;
}
onReset(): void {
......
......@@ -20,10 +20,15 @@ export class WaterfallChartWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
applyInitialConfig(): void {
this.title = this.config.title || 'Waterfall Chart';
this.primaryXAxis = { valueType: 'Category', title: this.config.xAxisTitle || '' };
this.primaryYAxis = { title: this.config.yAxisTitle || '' };
this.chartData = [];
}
onDataUpdate(data: any[]): void {
this.chartData = data.map(item => ({ x: item[this.config.xField], y: item[this.config.yField] }));
}
onReset(): void {
......
......@@ -16,11 +16,14 @@ export class WelcomeWidgetComponent extends BaseWidgetComponent {
super(dashboardStateService);
}
applyInitialConfig(): void {
this.title = this.config.title || '';
this.welcomeMessage = this.config.message || '...';
}
onDataUpdate(data: any[]): void {
if (data.length > 0 && this.config.messageField) {
this.welcomeMessage = data[0][this.config.messageField];
} else {
this.onReset();
}
}
......
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