Commit 01ab61b4 by Ooh-Ao

linker

parent 0e1eb15e
......@@ -64,13 +64,31 @@
</div>
</div>
<div *ngIf="widgetToPreview">
<div class="mb-4 p-4 border rounded-lg">
<h3 class="text-md font-bold mb-2">{{ widgetToPreview.widget.thName }}</h3>
<p class="text-sm text-gray-600">{{ widgetToPreview.widget.component }}</p>
<!-- Dynamic Widget Rendering Area -->
<div class="p-4 border rounded-lg mb-4">
<div *ngIf="!previewPanel" class="text-center text-red-500">
Preview not available for this widget type.
</div>
<ng-container *ngIf="previewPanel" [ngComponentOutlet]="previewPanel.componentType" [ngComponentOutletInputs]="previewPanel.componentInputs"></ng-container>
</div>
<!-- Editable Configuration Form -->
<div class="p-4 border rounded-lg bg-gray-50">
<h3 class="text-md font-bold mb-2">Configuration</h3>
<pre class="bg-gray-900 text-white p-2 rounded-md text-xs">{{ widgetToPreview.config | json }}</pre>
<form #configForm="ngForm" (ngSubmit)="saveConfiguration()">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div *ngFor="let key of getObjectKeys(configAsObject)" class="flex flex-col">
<label [for]="key" class="text-sm font-medium text-gray-600 mb-1 capitalize">{{ key }}</label>
<input type="text" [id]="key" [name]="key" [(ngModel)]="configAsObject[key]" class="p-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500">
</div>
</div>
<div *ngIf="getObjectKeys(configAsObject).length === 0" class="text-center text-gray-500">
This widget has no configurable properties.
</div>
<div class="mt-4 flex justify-end" *ngIf="getObjectKeys(configAsObject).length > 0">
<button ejs-button type="submit" cssClass="e-primary">Save Configuration</button>
</div>
</form>
</div>
</div>
</div>
......
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnInit, ViewChild, Type } from '@angular/core';
import { CommonModule, JsonPipe } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
......@@ -7,7 +7,7 @@ import { MatDialog } from '@angular/material/dialog';
import { DropDownListModule } from '@syncfusion/ej2-angular-dropdowns';
import { DialogComponent, DialogModule } from '@syncfusion/ej2-angular-popups';
import { GridComponent, GridModule, PageService, SelectionService } from '@syncfusion/ej2-angular-grids';
import { ButtonComponent, ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { ButtonModule } from '@syncfusion/ej2-angular-buttons';
import { NotificationService } from '../../shared/services/notification.service';
import { WidgetService } from '../services/widgets.service';
......@@ -19,17 +19,54 @@ import { WidgetConfigComponent } from '../dashboard-management/widget-config/wid
import { take } from 'rxjs/operators';
import { DashboardStateService } from '../services/dashboard-state.service';
// --- Copied from DashboardViewerComponent for dynamic rendering ---
import { NgComponentOutlet } from '@angular/common';
import { PanelModel } from '@syncfusion/ej2-angular-layouts';
// 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';
import { PayrollSummaryWidgetComponent } from '../widgets/payroll-summary-widget.component';
import { EmployeeDirectoryWidgetComponent } from '../widgets/employee-directory-widget.component';
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';
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 { 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';
import { ScatterBubbleChartWidgetComponent } from '../widgets/scatter-bubble-chart-widget/scatter-bubble-chart-widget.component';
import { MultiRowCardWidgetComponent } from '../widgets/multi-row-card-widget/multi-row-card-widget.component';
import { ComboChartWidgetComponent } from '../widgets/combo-chart-widget/combo-chart-widget.component';
import { DoughnutChartWidgetComponent } from '../widgets/doughnut-chart-widget/doughnut-chart-widget.component';
import { FunnelChartWidgetComponent } from '../widgets/funnel-chart-widget/funnel-chart-widget.component';
import { GaugeChartWidgetComponent } from '../widgets/gauge-chart-widget/gauge-chart-widget.component';
import { SimpleKpiWidgetComponent } from '../widgets/simple-kpi-widget/simple-kpi-widget.component';
import { FilledMapWidgetComponent } from '../widgets/filled-map-widget/filled-map-widget.component';
import { MatrixWidgetComponent } from '../widgets/matrix-widget/matrix-widget.component';
import { SlicerWidgetComponent } from '../widgets/slicer-widget/slicer-widget.component';
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';
// Interface for the panel object used by ngComponentOutlet
export interface DashboardPanel extends PanelModel {
componentType: Type<any>;
componentInputs?: { [key: string]: any };
}
// ----------------------------------------------------------------
@Component({
selector: 'app-dataset-widget-linker',
standalone: true,
imports: [
CommonModule,
FormsModule,
JsonPipe,
DropDownListModule,
DialogModule,
GridModule,
ButtonModule
CommonModule, FormsModule, JsonPipe, DropDownListModule, DialogModule, GridModule, ButtonModule, 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
],
providers: [PageService, SelectionService],
templateUrl: './dataset-widget-linker.component.html',
......@@ -37,20 +74,54 @@ import { DashboardStateService } from '../services/dashboard-state.service';
})
export class DatasetWidgetLinkerComponent implements OnInit {
// Syncfusion Component References
@ViewChild('addWidgetDialog') addWidgetDialog!: DialogComponent;
@ViewChild('grid') grid!: GridComponent;
// Data lists
public datasets: DatasetModel[] = [];
public masterWidgets: WidgetModel[] = [];
public linkedWidgets: MenuItemsWidget[] = [];
// UI State
public selectedDatasetId: string | null = null;
public widgetToPreview: MenuItemsWidget | null = null;
public isModalVisible = false;
// --- State for the right panel ---
public widgetToPreview: MenuItemsWidget | null = null;
public configAsObject: any = {};
public previewPanel: DashboardPanel | null = null;
// --------------------------------
private widgetComponentMap: { [key: string]: Type<any> } = {
'CompanyInfoWidgetComponent': CompanyInfoWidgetComponent,
'HeadcountWidgetComponent': HeadcountWidgetComponent,
'AttendanceOverviewWidgetComponent': AttendanceOverviewWidgetComponent,
'PayrollSummaryWidgetComponent': PayrollSummaryWidgetComponent,
'EmployeeDirectoryWidgetComponent': EmployeeDirectoryWidgetComponent,
'KpiWidgetComponent': KpiWidgetComponent,
'WelcomeWidgetComponent': WelcomeWidgetComponent,
'ChartWidgetComponent': ChartWidgetComponent,
'QuickLinksWidgetComponent': QuickLinksWidgetComponent,
'SyncfusionDatagridWidgetComponent': SyncfusionDatagridWidgetComponent,
'SyncfusionPivotWidgetComponent': SyncfusionPivotWidgetComponent,
'SyncfusionChartWidgetComponent': SyncfusionChartWidgetComponent,
'NewDataTableWidget': DataTableWidgetComponent,
'AreaChartWidgetComponent': AreaChartWidgetComponent,
'BarChartWidgetComponent': BarChartWidgetComponent,
'PieChartWidgetComponent': PieChartWidgetComponent,
'ScatterBubbleChartWidgetComponent': ScatterBubbleChartWidgetComponent,
'MultiRowCardWidgetComponent': MultiRowCardWidgetComponent,
'ComboChartWidgetComponent': ComboChartWidgetComponent,
'DoughnutChartWidgetComponent': DoughnutChartWidgetComponent,
'FunnelChartWidgetComponent': FunnelChartWidgetComponent,
'GaugeChartWidgetComponent': GaugeChartWidgetComponent,
'SimpleKpiWidgetComponent': SimpleKpiWidgetComponent,
'FilledMapWidgetComponent': FilledMapWidgetComponent,
'MatrixWidgetComponent': MatrixWidgetComponent,
'SlicerWidgetComponent': SlicerWidgetComponent,
'SimpleTableWidgetComponent': SimpleTableWidgetComponent,
'WaterfallChartWidgetComponent': WaterfallChartWidgetComponent,
'TreemapWidgetComponent': TreemapWidgetComponent,
};
constructor(
private widgetService: WidgetService,
private mMenuitemsWidgetService: MMenuitemsWidgetService,
......@@ -61,17 +132,16 @@ export class DatasetWidgetLinkerComponent implements OnInit {
) { }
ngOnInit(): void {
this.datasetService.getDatasets().subscribe(datasets => {
this.datasets = datasets;
});
this.datasetService.getDatasets().subscribe(datasets => { this.datasets = datasets; });
this.widgetService.getListWidgets().subscribe(widgets => { this.masterWidgets = widgets; });
}
this.widgetService.getListWidgets().subscribe(widgets => {
this.masterWidgets = widgets;
});
getObjectKeys(obj: any): string[] {
return Object.keys(obj);
}
onDatasetChange(): void {
this.widgetToPreview = null;
this.clearPreview();
if (this.selectedDatasetId) {
this.loadLinkedWidgetsForDataset(this.selectedDatasetId);
this.dashboardStateService.selectDataset(this.selectedDatasetId);
......@@ -82,22 +152,50 @@ export class DatasetWidgetLinkerComponent implements OnInit {
}
loadLinkedWidgetsForDataset(datasetId: string): void {
this.mMenuitemsWidgetService.getWidgetsForDataset(datasetId).subscribe(linked => {
this.linkedWidgets = linked;
});
this.mMenuitemsWidgetService.getWidgetsForDataset(datasetId).subscribe(linked => { this.linkedWidgets = linked; });
}
viewWidget(widget: MenuItemsWidget): void {
this.widgetToPreview = widget;
try {
this.configAsObject = JSON.parse(widget.config || '{}');
} catch (e) {
this.notificationService.error('Error', 'Failed to parse widget config.');
this.configAsObject = {};
}
const componentType = this.widgetComponentMap[widget.widget.component];
if (componentType) {
this.previewPanel = {
id: widget.widget.widgetId,
componentType: componentType,
componentInputs: { config: this.configAsObject },
row: 0, col: 0, sizeX: 1, sizeY: 1 // Dummy values, not used for layout here
};
} else {
this.previewPanel = null;
this.notificationService.error('Error', `Preview not available for widget type: ${widget.widget.component}`);
}
}
saveConfiguration(): void {
if (!this.widgetToPreview) return;
this.widgetToPreview.config = JSON.stringify(this.configAsObject);
this.mMenuitemsWidgetService.saveLinkedWidget(this.widgetToPreview).subscribe(() => {
this.notificationService.success('Success', 'Configuration saved successfully!');
// Refresh the preview to apply the new config
this.viewWidget(this.widgetToPreview!);
});
}
removeWidget(widget: MenuItemsWidget, event: MouseEvent): void {
event.stopPropagation(); // Prevent row selection when clicking the button
event.stopPropagation();
if (confirm('Are you sure you want to unlink this widget?')) {
this.mMenuitemsWidgetService.deleteLinkedWidget(widget.itemId).subscribe(() => {
this.notificationService.success('Success', 'Widget unlinked successfully!');
if (this.widgetToPreview?.itemId === widget.itemId) {
this.widgetToPreview = null;
this.clearPreview();
}
this.loadLinkedWidgetsForDataset(this.selectedDatasetId!);
});
......@@ -112,19 +210,19 @@ export class DatasetWidgetLinkerComponent implements OnInit {
addSelectedWidgets(): void {
const selectedWidgets = this.grid.getSelectedRecords() as WidgetModel[];
if (selectedWidgets.length > 0) {
selectedWidgets.forEach(widgetModel => {
this.linkWidget(widgetModel);
});
selectedWidgets.forEach(widgetModel => { this.linkWidget(widgetModel); });
}
this.addWidgetDialog.hide();
}
private linkWidget(widget: WidgetModel): void {
if (!this.selectedDatasetId) {
this.notificationService.warning('Warning', 'Something went wrong. No dataset selected.');
return;
private clearPreview(): void {
this.widgetToPreview = null;
this.previewPanel = null;
this.configAsObject = {};
}
private linkWidget(widget: WidgetModel): void {
if (!this.selectedDatasetId) return;
if (this.linkedWidgets.some(lw => lw.widget.widgetId === widget.widgetId)) {
this.notificationService.info('Info', `'${widget.thName}' is already linked.`);
return;
......@@ -140,14 +238,9 @@ export class DatasetWidgetLinkerComponent implements OnInit {
dialogRef.afterClosed().subscribe(resultConfig => {
if (resultConfig) {
const newLinkedWidget: MenuItemsWidget = {
companyId: 'DEMO', // Placeholder
itemId: this.selectedDatasetId!,
widget: widget,
config: JSON.stringify(resultConfig),
data: '',
perspective: ''
companyId: 'DEMO', itemId: this.selectedDatasetId!, widget: widget,
config: JSON.stringify(resultConfig), data: '', perspective: ''
};
this.mMenuitemsWidgetService.saveLinkedWidget(newLinkedWidget).subscribe(() => {
this.notificationService.success('Success', `'${widget.thName}' linked successfully!`);
this.loadLinkedWidgetsForDataset(this.selectedDatasetId!);
......
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