Commit 5cca44a4 by Ooh-Ao

perspective

parent de6dece3
......@@ -26,426 +26,820 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
BaseConfigComponent
],
template: `
<app-base-config>
<!-- Basic Configuration Tab -->
<div class="config-section">
<h3 class="text-blue-600">Basic Configuration</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
<input matInput [(ngModel)]="currentConfig.title" name="title" aria-label="Widget title">
<mat-hint>Widget title displayed in header</mat-hint>
</mat-form-field>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Page Size</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.pageSize" name="pageSize" min="5" max="100">
<mat-hint>Number of rows per page</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Size (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.fontSize" name="fontSize" min="10" max="20">
<mat-hint>Font size for grid content</mat-hint>
</mat-form-field>
</div>
<!-- Size Configuration -->
<div class="config-section">
<h3 class="text-blue-600">Size Configuration</h3>
<div class="size-config">
<div
*ngFor="let option of sizeOptions"
class="size-option"
[class.selected]="currentConfig.sizeOption === option.id"
(click)="setSizeOption(option.id)">
<h4>{{ option.label }}</h4>
<p>{{ option.description }}</p>
<div class="config-container">
<mat-tab-group class="config-tabs" dynamicHeight>
<!-- Basic Configuration Tab -->
<mat-tab label="Basic">
<div class="config-section">
<h3 class="section-title text-blue-600">Basic Configuration</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
<input matInput [(ngModel)]="currentConfig.title" name="title" aria-label="Widget title">
<mat-hint>Widget title displayed in header</mat-hint>
</mat-form-field>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Page Size</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.pageSize" name="pageSize" min="5" max="100">
<mat-hint>Number of rows per page</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Size (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.fontSize" name="fontSize" min="10" max="20">
<mat-hint>Font size for grid content</mat-hint>
</mat-form-field>
</div>
</div>
<div *ngIf="currentConfig.sizeOption === 'custom'" class="grid grid-cols-2 gap-4 mt-4">
<mat-form-field appearance="fill">
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="currentConfig.width" name="width" placeholder="e.g., 100%, 800px">
<mat-hint>Grid width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Height</mat-label>
<input matInput [(ngModel)]="currentConfig.height" name="height" placeholder="e.g., 100%, 400px">
<mat-hint>Grid height</mat-hint>
</mat-form-field>
</div>
</div>
</div>
<!-- Columns Tab -->
<div class="config-section">
<h3 class="text-blue-600">Column Configuration</h3>
<div class="flex items-center justify-between mb-4">
<h4>Available Columns</h4>
<button mat-raised-button color="primary" (click)="addColumn()">
<mat-icon>add</mat-icon>
Add Column
</button>
</div>
<div *ngFor="let column of currentConfig.columns; let i = index" class="column-config-item p-4 mb-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Field Name</mat-label>
<mat-select [(ngModel)]="column.field" name="columnField{{i}}">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
</mat-form-field>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Data Source</mat-label>
<mat-select [(ngModel)]="currentConfig.dataSource" name="dataSource">
<mat-option value="static">Static Data</mat-option>
<mat-option value="api">API Endpoint</mat-option>
<mat-option value="dataset">Dataset</mat-option>
</mat-select>
<mat-hint>Source of the data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Header Text</mat-label>
<input matInput [(ngModel)]="column.headerText" name="columnHeader{{i}}" placeholder="Column header">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>API Endpoint</mat-label>
<input matInput [(ngModel)]="currentConfig.apiEndpoint" name="apiEndpoint" placeholder="https://api.example.com/data">
<mat-hint>API endpoint URL</mat-hint>
</mat-form-field>
</div>
<mat-form-field appearance="fill">
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="column.width" name="columnWidth{{i}}" placeholder="e.g., 100px, 20%">
</mat-form-field>
<!-- Size Configuration -->
<div class="config-section">
<h3 class="section-title text-blue-600">Size Configuration</h3>
<div class="size-config">
<div
*ngFor="let option of sizeOptions"
class="size-option"
[class.selected]="currentConfig.sizeOption === option.id"
(click)="setSizeOption(option.id)">
<h4>{{ option.label }}</h4>
<p>{{ option.description }}</p>
</div>
</div>
<div *ngIf="currentConfig.sizeOption === 'custom'" class="grid grid-cols-2 gap-4 mt-4">
<mat-form-field appearance="fill">
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="currentConfig.width" name="width" placeholder="e.g., 100%, 800px">
<mat-hint>Grid width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Height</mat-label>
<input matInput [(ngModel)]="currentConfig.height" name="height" placeholder="e.g., 100%, 400px">
<mat-hint>Grid height</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Columns Tab -->
<mat-tab label="Columns">
<div class="config-section">
<h3 class="section-title text-green-600">Column Configuration</h3>
<div class="flex items-center justify-between mb-4">
<h4>Available Columns</h4>
<button mat-raised-button color="primary" (click)="addColumn()">
<mat-icon>add</mat-icon>
Add Column
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Text Align</mat-label>
<mat-select [(ngModel)]="column.textAlign" name="columnAlign{{i}}">
<mat-option value="left">Left</mat-option>
<mat-option value="center">Center</mat-option>
<mat-option value="right">Right</mat-option>
</mat-select>
</mat-form-field>
<div *ngFor="let column of currentConfig.columns; let i = index" class="column-config-item p-4 mb-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Field Name</mat-label>
<mat-select [(ngModel)]="column.field" name="columnField{{i}}">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Header Text</mat-label>
<input matInput [(ngModel)]="column.headerText" name="columnHeader{{i}}" placeholder="Column header">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="column.width" name="columnWidth{{i}}" placeholder="e.g., 100px, 20%">
</mat-form-field>
</div>
<mat-form-field appearance="fill">
<mat-label>Format</mat-label>
<mat-select [(ngModel)]="column.format" name="columnFormat{{i}}">
<mat-option value="none">None</mat-option>
<mat-option value="number">Number</mat-option>
<mat-option value="currency">Currency</mat-option>
<mat-option value="percentage">Percentage</mat-option>
<mat-option value="date">Date</mat-option>
<mat-option value="datetime">Date Time</mat-option>
</mat-select>
</mat-form-field>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Text Align</mat-label>
<mat-select [(ngModel)]="column.textAlign" name="columnAlign{{i}}">
<mat-option value="left">Left</mat-option>
<mat-option value="center">Center</mat-option>
<mat-option value="right">Right</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Format</mat-label>
<mat-select [(ngModel)]="column.format" name="columnFormat{{i}}">
<mat-option value="none">None</mat-option>
<mat-option value="number">Number</mat-option>
<mat-option value="currency">Currency</mat-option>
<mat-option value="percentage">Percentage</mat-option>
<mat-option value="date">Date</mat-option>
<mat-option value="datetime">Date Time</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="column.visible" name="columnVisible{{i}}">
Visible
</mat-checkbox>
<mat-checkbox [(ngModel)]="column.sortable" name="columnSortable{{i}}">
Sortable
</mat-checkbox>
<mat-checkbox [(ngModel)]="column.filterable" name="columnFilterable{{i}}">
Filterable
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removeColumn(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
</mat-tab>
<!-- Rows Tab -->
<mat-tab label="Rows">
<div class="config-section">
<h3 class="section-title text-purple-600">Row Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Row Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rowHeight" name="rowHeight" min="20" max="100">
<mat-hint>Height of each row</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Alternate Row Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.alternateRowColor" name="alternateRowColor">
<mat-hint>Color for alternate rows</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Header Row Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.headerRowHeight" name="headerRowHeight" min="20" max="100">
<mat-hint>Height of header row</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Header Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.headerBackgroundColor" name="headerBackgroundColor">
<mat-hint>Background color for header</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="column.visible" name="columnVisible{{i}}">
Visible
<mat-checkbox [(ngModel)]="currentConfig.showAlternateRows" name="showAlternateRows">
Show Alternate Row Colors
</mat-checkbox>
<mat-checkbox [(ngModel)]="column.sortable" name="columnSortable{{i}}">
Sortable
<mat-checkbox [(ngModel)]="currentConfig.allowRowSelection" name="allowRowSelection">
Allow Row Selection
</mat-checkbox>
<mat-checkbox [(ngModel)]="column.filterable" name="columnFilterable{{i}}">
Filterable
</div>
</div>
</mat-tab>
<!-- Style Tab -->
<mat-tab label="Style">
<div class="config-section">
<h3 class="section-title text-orange-600">Style Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.backgroundColor" name="backgroundColor">
<mat-hint>Grid background color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Text Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.textColor" name="textColor">
<mat-hint>Text color</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Border Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.borderColor" name="borderColor">
<mat-hint>Grid border color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Border Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.borderWidth" name="borderWidth" min="0" max="5">
<mat-hint>Border thickness</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Border Radius (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.borderRadius" name="borderRadius" min="0" max="20">
<mat-hint>Corner roundness</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Shadow</mat-label>
<mat-select [(ngModel)]="currentConfig.shadow" name="shadow">
<mat-option value="none">None</mat-option>
<mat-option value="small">Small</mat-option>
<mat-option value="medium">Medium</mat-option>
<mat-option value="large">Large</mat-option>
</mat-select>
<mat-hint>Drop shadow effect</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
<!-- Filter Tab -->
<mat-tab label="Filter">
<div class="config-section">
<h3 class="section-title text-teal-600">Filter Configuration</h3>
<div class="flex items-center space-x-4 mb-4">
<mat-checkbox [(ngModel)]="currentConfig.allowFiltering" name="allowFiltering">
Enable Filtering
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showFilterBar" name="showFilterBar">
Show Filter Bar
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removeColumn(i)">
<mat-icon>delete</mat-icon>
</button>
<div *ngIf="currentConfig.allowFiltering" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Filter Type</mat-label>
<mat-select [(ngModel)]="currentConfig.filterType" name="filterType">
<mat-option value="menu">Menu</mat-option>
<mat-option value="checkbox">Checkbox</mat-option>
<mat-option value="excel">Excel</mat-option>
</mat-select>
<mat-hint>Type of filter interface</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Filter Bar Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.filterBarHeight" name="filterBarHeight" min="30" max="100">
<mat-hint>Height of filter bar</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</div>
<!-- Rows Tab -->
<div class="config-section">
<h3 class="text-blue-600">Row Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Row Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rowHeight" name="rowHeight" min="20" max="100">
<mat-hint>Height of each row</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Alternate Row Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.alternateRowColor" name="alternateRowColor">
<mat-hint>Color for alternate rows</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Header Row Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.headerRowHeight" name="headerRowHeight" min="20" max="100">
<mat-hint>Height of header row</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Header Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.headerBackgroundColor" name="headerBackgroundColor">
<mat-hint>Background color for header</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="currentConfig.showAlternateRows" name="showAlternateRows">
Show Alternate Row Colors
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowRowSelection" name="allowRowSelection">
Allow Row Selection
</mat-checkbox>
</div>
</div>
<!-- Style Tab -->
<div class="config-section">
<h3 class="text-blue-600">Style Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.backgroundColor" name="backgroundColor">
<mat-hint>Grid background color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Text Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.textColor" name="textColor">
<mat-hint>Text color</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Border Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.borderColor" name="borderColor">
<mat-hint>Grid border color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Border Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.borderWidth" name="borderWidth" min="0" max="5">
<mat-hint>Border thickness</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Border Radius (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.borderRadius" name="borderRadius" min="0" max="20">
<mat-hint>Corner roundness</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Shadow</mat-label>
<mat-select [(ngModel)]="currentConfig.shadow" name="shadow">
<mat-option value="none">None</mat-option>
<mat-option value="small">Small</mat-option>
<mat-option value="medium">Medium</mat-option>
<mat-option value="large">Large</mat-option>
</mat-select>
<mat-hint>Drop shadow effect</mat-hint>
</mat-form-field>
</div>
</div>
<!-- Filter Tab -->
<div class="config-section">
<h3 class="text-blue-600">Filter Configuration</h3>
<div class="flex items-center space-x-4 mb-4">
<mat-checkbox [(ngModel)]="currentConfig.allowFiltering" name="allowFiltering">
Enable Filtering
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showFilterBar" name="showFilterBar">
Show Filter Bar
</mat-checkbox>
</div>
<div *ngIf="currentConfig.allowFiltering" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Filter Type</mat-label>
<mat-select [(ngModel)]="currentConfig.filterType" name="filterType">
<mat-option value="menu">Menu</mat-option>
<mat-option value="checkbox">Checkbox</mat-option>
<mat-option value="excel">Excel</mat-option>
</mat-select>
<mat-hint>Type of filter interface</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Filter Bar Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.filterBarHeight" name="filterBarHeight" min="30" max="100">
<mat-hint>Height of filter bar</mat-hint>
</mat-form-field>
</div>
</div>
<!-- Aggregate Tab -->
<div class="config-section">
<h3 class="text-blue-600">Aggregate Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.showAggregate" name="showAggregate">
Show Aggregate Row
</mat-checkbox>
</div>
<div *ngIf="currentConfig.showAggregate">
<div class="flex items-center justify-between mb-4">
<h4>Aggregate Columns</h4>
<button mat-raised-button color="primary" (click)="addAggregateColumn()">
<mat-icon>add</mat-icon>
Add Aggregate
</button>
</mat-tab>
<!-- Aggregate Tab -->
<mat-tab label="Aggregate">
<div class="config-section">
<h3 class="section-title text-red-600">Aggregate Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.showAggregate" name="showAggregate">
Show Aggregate Row
</mat-checkbox>
</div>
<div *ngIf="currentConfig.showAggregate">
<div class="flex items-center justify-between mb-4">
<h4>Aggregate Columns</h4>
<button mat-raised-button color="primary" (click)="addAggregateColumn()">
<mat-icon>add</mat-icon>
Add Aggregate
</button>
</div>
<div *ngFor="let agg of currentConfig.aggregateColumns; let i = index" class="column-config-item p-4 mb-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Field Name</mat-label>
<mat-select [(ngModel)]="agg.field" name="aggField{{i}}">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Aggregate Type</mat-label>
<mat-select [(ngModel)]="agg.type" name="aggType{{i}}">
<mat-option value="sum">Sum</mat-option>
<mat-option value="count">Count</mat-option>
<mat-option value="average">Average</mat-option>
<mat-option value="min">Min</mat-option>
<mat-option value="max">Max</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Format</mat-label>
<mat-select [(ngModel)]="agg.format" name="aggFormat{{i}}">
<mat-option value="none">None</mat-option>
<mat-option value="number">Number</mat-option>
<mat-option value="currency">Currency</mat-option>
<mat-option value="percentage">Percentage</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="agg.visible" name="aggVisible{{i}}">
Visible
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removeAggregateColumn(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
</div>
</mat-tab>
<!-- Export Tab -->
<mat-tab label="Export">
<div class="config-section">
<h3 class="section-title text-indigo-600">Export Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableExport" name="enableExport">
Enable Export
</mat-checkbox>
</div>
<div *ngFor="let agg of currentConfig.aggregateColumns; let i = index" class="column-config-item p-4 mb-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div *ngIf="currentConfig.enableExport" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Field Name</mat-label>
<mat-select [(ngModel)]="agg.field" name="aggField{{i}}">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
<mat-label>Export Formats</mat-label>
<mat-select [(ngModel)]="currentConfig.exportFormats" name="exportFormats" multiple>
<mat-option value="excel">Excel (.xlsx)</mat-option>
<mat-option value="csv">CSV (.csv)</mat-option>
<mat-option value="pdf">PDF (.pdf)</mat-option>
<mat-option value="json">JSON (.json)</mat-option>
</mat-select>
<mat-hint>Available export formats</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Aggregate Type</mat-label>
<mat-select [(ngModel)]="agg.type" name="aggType{{i}}">
<mat-option value="sum">Sum</mat-option>
<mat-option value="count">Count</mat-option>
<mat-option value="average">Average</mat-option>
<mat-option value="min">Min</mat-option>
<mat-option value="max">Max</mat-option>
<mat-label>Export Filename</mat-label>
<input matInput [(ngModel)]="currentConfig.exportFilename" name="exportFilename" placeholder="data-export">
<mat-hint>Default filename for exports</mat-hint>
</mat-form-field>
</div>
<div *ngIf="currentConfig.enableExport" class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="currentConfig.includeHeaders" name="includeHeaders">
Include Headers in Export
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.includeFilters" name="includeFilters">
Include Applied Filters
</mat-checkbox>
</div>
</div>
</mat-tab>
<!-- Features Tab -->
<mat-tab label="Features">
<div class="config-section">
<h3 class="section-title text-cyan-600">Grid Features</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Paging & Navigation</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowPaging" name="allowPaging">
Enable Paging
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowPageSize" name="allowPageSize">
Allow Page Size Selection
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showPageInfo" name="showPageInfo">
Show Page Info
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowPageNavigation" name="allowPageNavigation">
Allow Page Navigation
</mat-checkbox>
</div>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Sorting & Filtering</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowSorting" name="allowSorting">
Enable Sorting
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowMultiSorting" name="allowMultiSorting">
Allow Multi-Sorting
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowFiltering" name="allowFiltering">
Enable Filtering
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowAdvancedFiltering" name="allowAdvancedFiltering">
Enable Advanced Filtering
</mat-checkbox>
</div>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Grouping & Searching</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowGrouping" name="allowGrouping">
Enable Grouping
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowReordering" name="allowReordering">
Allow Column Reordering
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowResizing" name="allowResizing">
Allow Column Resizing
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowSearching" name="allowSearching">
Enable Global Search
</mat-checkbox>
</div>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Selection & Editing</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowSelection" name="allowSelection">
Enable Row Selection
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowMultiSelection" name="allowMultiSelection">
Allow Multi-Selection
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowEditing" name="allowEditing">
Enable Inline Editing
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowAdding" name="allowAdding">
Allow Adding Rows
</mat-checkbox>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
<mat-form-field appearance="fill">
<mat-label>Selection Mode</mat-label>
<mat-select [(ngModel)]="currentConfig.selectionMode" name="selectionMode">
<mat-option value="none">None</mat-option>
<mat-option value="single">Single</mat-option>
<mat-option value="multiple">Multiple</mat-option>
</mat-select>
<mat-hint>Row selection mode</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Format</mat-label>
<mat-select [(ngModel)]="agg.format" name="aggFormat{{i}}">
<mat-label>Edit Mode</mat-label>
<mat-select [(ngModel)]="currentConfig.editMode" name="editMode">
<mat-option value="none">None</mat-option>
<mat-option value="number">Number</mat-option>
<mat-option value="currency">Currency</mat-option>
<mat-option value="percentage">Percentage</mat-option>
<mat-option value="inline">Inline</mat-option>
<mat-option value="dialog">Dialog</mat-option>
<mat-option value="batch">Batch</mat-option>
</mat-select>
<mat-hint>Row editing mode</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="agg.visible" name="aggVisible{{i}}">
Visible
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removeAggregateColumn(i)">
<mat-icon>delete</mat-icon>
</button>
<!-- Data Management Tab -->
<mat-tab label="Data">
<div class="config-section">
<h3 class="section-title text-emerald-600">Data Management</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Data Source Type</mat-label>
<mat-select [(ngModel)]="currentConfig.dataSourceType" name="dataSourceType">
<mat-option value="local">Local Data</mat-option>
<mat-option value="remote">Remote Data</mat-option>
<mat-option value="odata">OData Service</mat-option>
<mat-option value="webapi">Web API</mat-option>
</mat-select>
<mat-hint>Type of data source</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>API Endpoint</mat-label>
<input matInput [(ngModel)]="currentConfig.apiEndpoint" name="apiEndpoint" placeholder="https://api.example.com/data">
<mat-hint>API endpoint URL</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Refresh Interval (ms)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.refreshInterval" name="refreshInterval" min="0" step="1000">
<mat-hint>0 = No auto-refresh</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Cache Duration (seconds)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.cacheDuration" name="cacheDuration" min="0" max="3600">
<mat-hint>Data cache duration</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center space-x-4 mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableVirtualization" name="enableVirtualization">
Enable Virtual Scrolling
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableInfiniteScroll" name="enableInfiniteScroll">
Enable Infinite Scroll
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableLazyLoad" name="enableLazyLoad">
Enable Lazy Loading
</mat-checkbox>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Data Transform Function</mat-label>
<textarea matInput [(ngModel)]="currentConfig.dataTransform" name="dataTransform" rows="3"
placeholder="data => data.map(item => ({ ...item, formattedValue: formatCurrency(item.value) }))"></textarea>
<mat-hint>JavaScript function to transform data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Error Message</mat-label>
<input matInput [(ngModel)]="currentConfig.errorMessage" name="errorMessage" placeholder="Failed to load data">
<mat-hint>Error message to display</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</div>
<!-- Export Tab -->
<div class="config-section">
<h3 class="text-blue-600">Export Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableExport" name="enableExport">
Enable Export
</mat-checkbox>
</div>
<div *ngIf="currentConfig.enableExport" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Export Formats</mat-label>
<mat-select [(ngModel)]="currentConfig.exportFormats" name="exportFormats" multiple>
<mat-option value="excel">Excel (.xlsx)</mat-option>
<mat-option value="csv">CSV (.csv)</mat-option>
<mat-option value="pdf">PDF (.pdf)</mat-option>
<mat-option value="json">JSON (.json)</mat-option>
</mat-select>
<mat-hint>Available export formats</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Export Filename</mat-label>
<input matInput [(ngModel)]="currentConfig.exportFilename" name="exportFilename" placeholder="data-export">
<mat-hint>Default filename for exports</mat-hint>
</mat-form-field>
</div>
<div *ngIf="currentConfig.enableExport" class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="currentConfig.includeHeaders" name="includeHeaders">
Include Headers in Export
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.includeFilters" name="includeFilters">
Include Applied Filters
</mat-checkbox>
</div>
</div>
<!-- Security Tab -->
<div class="config-section">
<h3 class="text-blue-600">Security Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.requireAuth" name="requireAuth">
Require Authentication
</mat-checkbox>
</div>
<div *ngIf="currentConfig.requireAuth" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Allowed Roles</mat-label>
<input matInput [(ngModel)]="currentConfig.allowedRoles" name="allowedRoles" placeholder="admin,user,manager">
<mat-hint>Comma-separated list of allowed roles</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Permission Level</mat-label>
<mat-select [(ngModel)]="currentConfig.permissionLevel" name="permissionLevel">
<mat-option value="read">Read Only</mat-option>
<mat-option value="write">Read/Write</mat-option>
<mat-option value="admin">Full Access</mat-option>
</mat-select>
<mat-hint>Required permission level</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="currentConfig.dataEncryption" name="dataEncryption">
Enable Data Encryption
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.auditLog" name="auditLog">
Enable Audit Logging
</mat-checkbox>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Rate Limit (requests/hour)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rateLimit" name="rateLimit" min="0" max="10000">
<mat-hint>Maximum requests per hour per user</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Session Timeout (minutes)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.sessionTimeout" name="sessionTimeout" min="5" max="480">
<mat-hint>Session timeout in minutes</mat-hint>
</mat-form-field>
</div>
</div>
</app-base-config>
</mat-tab>
<!-- Security Tab -->
<mat-tab label="Security">
<div class="config-section">
<h3 class="section-title text-gray-600">Security Configuration</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.requireAuth" name="requireAuth">
Require Authentication
</mat-checkbox>
</div>
<div *ngIf="currentConfig.requireAuth" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Allowed Roles</mat-label>
<input matInput [(ngModel)]="currentConfig.allowedRoles" name="allowedRoles" placeholder="admin,user,manager">
<mat-hint>Comma-separated list of allowed roles</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Permission Level</mat-label>
<mat-select [(ngModel)]="currentConfig.permissionLevel" name="permissionLevel">
<mat-option value="read">Read Only</mat-option>
<mat-option value="write">Read/Write</mat-option>
<mat-option value="admin">Full Access</mat-option>
</mat-select>
<mat-hint>Required permission level</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="currentConfig.dataEncryption" name="dataEncryption">
Enable Data Encryption
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.auditLog" name="auditLog">
Enable Audit Logging
</mat-checkbox>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Rate Limit (requests/hour)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rateLimit" name="rateLimit" min="0" max="10000">
<mat-hint>Maximum requests per hour per user</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Session Timeout (minutes)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.sessionTimeout" name="sessionTimeout" min="5" max="480">
<mat-hint>Session timeout in minutes</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
</mat-tab-group>
</div>
`,
styles: [`
.config-container {
padding: 20px;
background: #f8fafc;
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.config-section {
margin-bottom: 24px;
margin-bottom: 32px;
padding: 24px;
background: white;
border-radius: 8px;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 20px;
padding-bottom: 8px;
border-bottom: 2px solid #e2e8f0;
}
.config-tabs {
margin-top: 0;
}
.config-tabs .mat-tab-body-content {
padding: 20px 0;
}
.config-tabs .mat-tab-header {
background: white;
border-radius: 8px 8px 0 0;
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
}
.config-tabs .mat-tab-label {
min-width: 120px;
font-weight: 500;
}
.config-tabs .mat-tab-label-active {
color: #3b82f6;
}
.mat-form-field {
margin-bottom: 8px;
}
.grid {
display: grid;
gap: 16px;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (min-width: 768px) {
.md\\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.md\\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
.w-full {
width: 100%;
}
.flex {
display: flex;
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.space-x-4 > * + * {
margin-left: 16px;
}
.mb-4 {
margin-bottom: 16px;
}
.mt-4 {
margin-top: 16px;
}
.p-4 {
padding: 16px;
}
.column-config-item {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 8px;
margin-bottom: 16px;
}
.size-config {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 20px;
}
.size-option {
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
background: white;
}
.size-option:hover {
border-color: #3b82f6;
background: #f0f9ff;
}
.size-option.selected {
border-color: #3b82f6;
background: #dbeafe;
}
.size-option h4 {
margin: 0 0 8px 0;
font-size: 1rem;
font-weight: 600;
color: #374151;
}
.size-option p {
margin: 0;
font-size: 0.875rem;
color: #6b7280;
}
.feature-group {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
}
.space-y-2 > * + * {
margin-top: 8px;
}
.text-sm {
font-size: 0.875rem;
}
.font-semibold {
font-weight: 600;
}
.text-gray-700 {
color: #374151;
}
.mb-3 {
margin-bottom: 12px;
}
.mt-6 {
margin-top: 24px;
}
.text-blue-600 { color: #2563eb; }
.text-green-600 { color: #16a34a; }
.text-purple-600 { color: #9333ea; }
.text-orange-600 { color: #ea580c; }
.text-teal-600 { color: #0d9488; }
.text-red-600 { color: #dc2626; }
.text-indigo-600 { color: #4f46e5; }
.text-gray-600 { color: #4b5563; }
.text-cyan-600 { color: #0891b2; }
.text-emerald-600 { color: #059669; }
`]
})
export class SyncfusionDatagridConfigComponent extends BaseConfigComponent implements OnInit {
......@@ -455,6 +849,76 @@ export class SyncfusionDatagridConfigComponent extends BaseConfigComponent imple
this.initializeColorDefaults();
}
override initializeDefaultConfig() {
// Basic Configuration
if (!this.currentConfig.title) this.currentConfig.title = 'Data Grid Widget';
if (!this.currentConfig.pageSize) this.currentConfig.pageSize = 10;
if (!this.currentConfig.fontSize) this.currentConfig.fontSize = 14;
if (!this.currentConfig.dataSource) this.currentConfig.dataSource = 'static';
if (!this.currentConfig.apiEndpoint) this.currentConfig.apiEndpoint = '';
// Row Configuration
if (!this.currentConfig.rowHeight) this.currentConfig.rowHeight = 40;
if (!this.currentConfig.headerRowHeight) this.currentConfig.headerRowHeight = 40;
if (!this.currentConfig.showAlternateRows) this.currentConfig.showAlternateRows = false;
if (!this.currentConfig.allowRowSelection) this.currentConfig.allowRowSelection = false;
// Filter Configuration
if (!this.currentConfig.allowFiltering) this.currentConfig.allowFiltering = true;
if (!this.currentConfig.showFilterBar) this.currentConfig.showFilterBar = false;
if (!this.currentConfig.filterType) this.currentConfig.filterType = 'menu';
if (!this.currentConfig.filterBarHeight) this.currentConfig.filterBarHeight = 40;
// Aggregate Configuration
if (!this.currentConfig.showAggregate) this.currentConfig.showAggregate = false;
if (!this.currentConfig.aggregateColumns) this.currentConfig.aggregateColumns = [];
// Export Configuration
if (!this.currentConfig.enableExport) this.currentConfig.enableExport = false;
if (!this.currentConfig.exportFormats) this.currentConfig.exportFormats = ['excel'];
if (!this.currentConfig.exportFilename) this.currentConfig.exportFilename = 'data-export';
if (!this.currentConfig.includeHeaders) this.currentConfig.includeHeaders = true;
if (!this.currentConfig.includeFilters) this.currentConfig.includeFilters = false;
// Features Configuration
if (!this.currentConfig.allowPaging) this.currentConfig.allowPaging = true;
if (!this.currentConfig.allowPageSize) this.currentConfig.allowPageSize = true;
if (!this.currentConfig.showPageInfo) this.currentConfig.showPageInfo = true;
if (!this.currentConfig.allowPageNavigation) this.currentConfig.allowPageNavigation = true;
if (!this.currentConfig.allowSorting) this.currentConfig.allowSorting = true;
if (!this.currentConfig.allowMultiSorting) this.currentConfig.allowMultiSorting = false;
if (!this.currentConfig.allowAdvancedFiltering) this.currentConfig.allowAdvancedFiltering = false;
if (!this.currentConfig.allowGrouping) this.currentConfig.allowGrouping = false;
if (!this.currentConfig.allowReordering) this.currentConfig.allowReordering = true;
if (!this.currentConfig.allowResizing) this.currentConfig.allowResizing = true;
if (!this.currentConfig.allowSearching) this.currentConfig.allowSearching = false;
if (!this.currentConfig.allowSelection) this.currentConfig.allowSelection = false;
if (!this.currentConfig.allowMultiSelection) this.currentConfig.allowMultiSelection = false;
if (!this.currentConfig.allowEditing) this.currentConfig.allowEditing = false;
if (!this.currentConfig.allowAdding) this.currentConfig.allowAdding = false;
if (!this.currentConfig.selectionMode) this.currentConfig.selectionMode = 'none';
if (!this.currentConfig.editMode) this.currentConfig.editMode = 'none';
// Data Management Configuration
if (!this.currentConfig.dataSourceType) this.currentConfig.dataSourceType = 'local';
if (!this.currentConfig.refreshInterval) this.currentConfig.refreshInterval = 0;
if (!this.currentConfig.cacheDuration) this.currentConfig.cacheDuration = 300;
if (!this.currentConfig.enableVirtualization) this.currentConfig.enableVirtualization = false;
if (!this.currentConfig.enableInfiniteScroll) this.currentConfig.enableInfiniteScroll = false;
if (!this.currentConfig.enableLazyLoad) this.currentConfig.enableLazyLoad = false;
if (!this.currentConfig.dataTransform) this.currentConfig.dataTransform = '';
if (!this.currentConfig.errorMessage) this.currentConfig.errorMessage = 'Failed to load data';
// Security Configuration
if (!this.currentConfig.requireAuth) this.currentConfig.requireAuth = false;
if (!this.currentConfig.allowedRoles) this.currentConfig.allowedRoles = '';
if (!this.currentConfig.permissionLevel) this.currentConfig.permissionLevel = 'read';
if (!this.currentConfig.dataEncryption) this.currentConfig.dataEncryption = false;
if (!this.currentConfig.auditLog) this.currentConfig.auditLog = false;
if (!this.currentConfig.rateLimit) this.currentConfig.rateLimit = 0;
if (!this.currentConfig.sessionTimeout) this.currentConfig.sessionTimeout = 30;
}
private initializeColorDefaults() {
if (!this.currentConfig.backgroundColor) this.currentConfig.backgroundColor = '#FFFFFF';
if (!this.currentConfig.textColor) this.currentConfig.textColor = '#374151';
......
......@@ -7,6 +7,7 @@ import { MatSelectModule } from '@angular/material/select';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatTabsModule } from '@angular/material/tabs';
import { BaseConfigComponent } from '../../../widget-config/base-config/base-config.component';
@Component({
......@@ -21,228 +22,747 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
MatCheckboxModule,
MatButtonModule,
MatIconModule,
MatTabsModule,
BaseConfigComponent
],
template: `
<app-base-config>
<!-- Basic Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-blue-600">Basic Configuration</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
<input matInput [(ngModel)]="currentConfig.title" name="title" aria-label="Widget title">
<mat-hint>Widget title displayed in header</mat-hint>
</mat-form-field>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Display As</mat-label>
<mat-select [(ngModel)]="currentConfig.displayOptionView" name="displayOptionView">
<mat-option value="Both">Both (Grid & Chart)</mat-option>
<mat-option value="Grid">Grid Only</mat-option>
<mat-option value="Chart">Chart Only</mat-option>
</mat-select>
<mat-hint>What to display</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Chart Type</mat-label>
<mat-select [(ngModel)]="currentConfig.chartType" name="chartType">
<mat-option value="Column">Column</mat-option>
<mat-option value="Bar">Bar</mat-option>
<mat-option value="Line">Line</mat-option>
<mat-option value="Area">Area</mat-option>
<mat-option value="Pie">Pie</mat-option>
<mat-option value="Doughnut">Doughnut</mat-option>
</mat-select>
<mat-hint>Chart type when displaying chart</mat-hint>
</mat-form-field>
</div>
</div>
<!-- Pivot Functionality -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-green-600">Pivot Functionality</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.showFieldList" name="showFieldList" class="mr-2">
Show Field List
</mat-checkbox>
</div>
<div class="config-container">
<mat-tab-group class="config-tabs" dynamicHeight>
<!-- Basic Configuration Tab -->
<mat-tab label="Basic">
<div class="config-section">
<h3 class="section-title text-blue-600">Basic Configuration</h3>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.showToolbar" name="showToolbar" class="mr-2">
Show Toolbar
</mat-checkbox>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
<input matInput [(ngModel)]="currentConfig.title" name="title" aria-label="Widget title">
<mat-hint>Widget title displayed in header</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.showGroupingBar" name="showGroupingBar" class="mr-2">
Show Grouping Bar
</mat-checkbox>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Display As</mat-label>
<mat-select [(ngModel)]="currentConfig.displayOptionView" name="displayOptionView">
<mat-option value="Both">Both (Grid & Chart)</mat-option>
<mat-option value="Grid">Grid Only</mat-option>
<mat-option value="Chart">Chart Only</mat-option>
</mat-select>
<mat-hint>What to display</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowCalculatedField" name="allowCalculatedField" class="mr-2">
Allow Calculated Fields
</mat-checkbox>
</div>
<mat-form-field appearance="fill">
<mat-label>Chart Type</mat-label>
<mat-select [(ngModel)]="currentConfig.chartType" name="chartType">
<mat-option value="Column">Column</mat-option>
<mat-option value="Bar">Bar</mat-option>
<mat-option value="Line">Line</mat-option>
<mat-option value="Area">Area</mat-option>
<mat-option value="Pie">Pie</mat-option>
<mat-option value="Doughnut">Doughnut</mat-option>
</mat-select>
<mat-hint>Chart type when displaying chart</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowConditionalFormatting" name="allowConditionalFormatting" class="mr-2">
Allow Conditional Formatting
</mat-checkbox>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Data Source</mat-label>
<mat-select [(ngModel)]="currentConfig.dataSource" name="dataSource">
<mat-option value="static">Static Data</mat-option>
<mat-option value="api">API Endpoint</mat-option>
<mat-option value="dataset">Dataset</mat-option>
</mat-select>
<mat-hint>Source of the data</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowNumberFormatting" name="allowNumberFormatting" class="mr-2">
Allow Number Formatting
</mat-checkbox>
<mat-form-field appearance="fill">
<mat-label>API Endpoint</mat-label>
<input matInput [(ngModel)]="currentConfig.apiEndpoint" name="apiEndpoint" placeholder="https://api.example.com/data">
<mat-hint>API endpoint URL</mat-hint>
</mat-form-field>
</div>
<!-- Size Configuration -->
<div class="config-section">
<h3 class="section-title text-blue-600">Size Configuration</h3>
<div class="size-config">
<div
*ngFor="let option of sizeOptions"
class="size-option"
[class.selected]="currentConfig.sizeOption === option.id"
(click)="setSizeOption(option.id)">
<h4>{{ option.label }}</h4>
<p>{{ option.description }}</p>
</div>
</div>
<div *ngIf="currentConfig.sizeOption === 'custom'" class="grid grid-cols-2 gap-4 mt-4">
<mat-form-field appearance="fill">
<mat-label>Width</mat-label>
<input matInput [(ngModel)]="currentConfig.width" name="width" placeholder="e.g., 100%, 800px">
<mat-hint>Pivot width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Height</mat-label>
<input matInput [(ngModel)]="currentConfig.height" name="height" placeholder="e.g., 100%, 400px">
<mat-hint>Pivot height</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
<!-- Pivot Functionality Tab -->
<mat-tab label="Features">
<div class="config-section">
<h3 class="section-title text-green-600">Pivot Functionality</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Display Options</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.showFieldList" name="showFieldList">
Show Field List
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showToolbar" name="showToolbar">
Show Toolbar
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showGroupingBar" name="showGroupingBar">
Show Grouping Bar
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.showPager" name="showPager">
Show Pager
</mat-checkbox>
</div>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Field Management</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowCalculatedField" name="allowCalculatedField">
Allow Calculated Fields
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowConditionalFormatting" name="allowConditionalFormatting">
Allow Conditional Formatting
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowNumberFormatting" name="allowNumberFormatting">
Allow Number Formatting
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowFieldDragDrop" name="allowFieldDragDrop">
Allow Field Drag & Drop
</mat-checkbox>
</div>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowSubTotal" name="allowSubTotal" class="mr-2">
Allow Sub Total
</mat-checkbox>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Totals & Aggregation</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowSubTotal" name="allowSubTotal">
Allow Sub Total
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowGrandTotal" name="allowGrandTotal">
Allow Grand Total
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowDrillThrough" name="allowDrillThrough">
Allow Drill Through
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowSorting" name="allowSorting">
Allow Sorting
</mat-checkbox>
</div>
</div>
<div class="feature-group">
<h4 class="text-sm font-semibold text-gray-700 mb-3">Export & Interaction</h4>
<div class="space-y-2">
<mat-checkbox [(ngModel)]="currentConfig.allowExcelExport" name="allowExcelExport">
Allow Excel Export
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowPdfExport" name="allowPdfExport">
Allow PDF Export
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowCsvExport" name="allowCsvExport">
Allow CSV Export
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.allowPrint" name="allowPrint">
Allow Print
</mat-checkbox>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mt-6">
<mat-form-field appearance="fill">
<mat-label>Aggregation Type</mat-label>
<mat-select [(ngModel)]="currentConfig.aggregationType" name="aggregationType">
<mat-option value="sum">Sum</mat-option>
<mat-option value="count">Count</mat-option>
<mat-option value="average">Average</mat-option>
<mat-option value="min">Min</mat-option>
<mat-option value="max">Max</mat-option>
</mat-select>
<mat-hint>Default aggregation type</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Number Format</mat-label>
<mat-select [(ngModel)]="currentConfig.numberFormat" name="numberFormat">
<mat-option value="N">Number</mat-option>
<mat-option value="C">Currency</mat-option>
<mat-option value="P">Percentage</mat-option>
<mat-option value="D">Date</mat-option>
</mat-select>
<mat-hint>Number formatting</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
<!-- Pivot Fields Tab -->
<mat-tab label="Fields">
<div class="config-section">
<h3 class="section-title text-purple-600">Pivot Fields Configuration</h3>
<!-- Pivot Rows -->
<div class="field-section">
<div class="flex items-center justify-between mb-4">
<h4 class="text-lg font-semibold">Rows</h4>
<button mat-raised-button color="primary" (click)="addPivotRow()">
<mat-icon>add</mat-icon> Add Row
</button>
</div>
<div *ngFor="let row of currentConfig.rows; let i = index" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Row Field</mat-label>
<mat-select [(ngModel)]="row.name" [name]="'row_name_' + i">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Caption</mat-label>
<input matInput [(ngModel)]="row.caption" [name]="'row_caption_' + i" placeholder="Row caption">
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="row.visible" [name]="'row_visible_' + i">
Visible
</mat-checkbox>
<mat-checkbox [(ngModel)]="row.expanded" [name]="'row_expanded_' + i">
Expanded
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removePivotRow(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowGrandTotal" name="allowGrandTotal" class="mr-2">
Allow Grand Total
</mat-checkbox>
<!-- Pivot Columns -->
<div class="field-section">
<div class="flex items-center justify-between mb-4">
<h4 class="text-lg font-semibold">Columns</h4>
<button mat-raised-button color="primary" (click)="addPivotColumn()">
<mat-icon>add</mat-icon> Add Column
</button>
</div>
<div *ngFor="let col of currentConfig.columns; let i = index" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Column Field</mat-label>
<mat-select [(ngModel)]="col.name" [name]="'col_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Caption</mat-label>
<input matInput [(ngModel)]="col.caption" [name]="'col_caption_' + i" placeholder="Column caption">
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="col.visible" [name]="'col_visible_' + i">
Visible
</mat-checkbox>
<mat-checkbox [(ngModel)]="col.expanded" [name]="'col_expanded_' + i">
Expanded
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removePivotColumn(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
<!-- Pivot Values -->
<div class="field-section">
<div class="flex items-center justify-between mb-4">
<h4 class="text-lg font-semibold">Values</h4>
<button mat-raised-button color="primary" (click)="addPivotValue()">
<mat-icon>add</mat-icon> Add Value
</button>
</div>
<div *ngFor="let val of currentConfig.values; let i = index" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Value Field</mat-label>
<mat-select [(ngModel)]="val.name" [name]="'val_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Caption</mat-label>
<input matInput [(ngModel)]="val.caption" [name]="'val_caption_' + i" placeholder="Value caption">
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Aggregation</mat-label>
<mat-select [(ngModel)]="val.aggregation" [name]="'val_aggregation_' + i">
<mat-option value="sum">Sum</mat-option>
<mat-option value="count">Count</mat-option>
<mat-option value="average">Average</mat-option>
<mat-option value="min">Min</mat-option>
<mat-option value="max">Max</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="val.visible" [name]="'val_visible_' + i">
Visible
</mat-checkbox>
<mat-checkbox [(ngModel)]="val.showSubTotals" [name]="'val_showSubTotals_' + i">
Show Sub Totals
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removePivotValue(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
<!-- Pivot Filters -->
<div class="field-section">
<div class="flex items-center justify-between mb-4">
<h4 class="text-lg font-semibold">Filters</h4>
<button mat-raised-button color="primary" (click)="addPivotFilter()">
<mat-icon>add</mat-icon> Add Filter
</button>
</div>
<div *ngFor="let fil of currentConfig.filters; let i = index" class="field-config-item">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Filter Field</mat-label>
<mat-select [(ngModel)]="fil.name" [name]="'fil_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Filter Type</mat-label>
<mat-select [(ngModel)]="fil.type" [name]="'fil_type_' + i">
<mat-option value="exclude">Exclude</mat-option>
<mat-option value="include">Include</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="flex items-center justify-between mt-4">
<div class="flex items-center space-x-4">
<mat-checkbox [(ngModel)]="fil.visible" [name]="'fil_visible_' + i">
Visible
</mat-checkbox>
</div>
<button mat-icon-button color="warn" (click)="removePivotFilter(i)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
</div>
</mat-tab>
<!-- Style Tab -->
<mat-tab label="Style">
<div class="config-section">
<h3 class="section-title text-orange-600">Style Configuration</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.backgroundColor" name="backgroundColor">
<mat-hint>Pivot background color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Text Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.textColor" name="textColor">
<mat-hint>Text color</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowExcelExport" name="allowExcelExport" class="mr-2">
Allow Excel Export
</mat-checkbox>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Header Background Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.headerBackgroundColor" name="headerBackgroundColor">
<mat-hint>Header background color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Header Text Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.headerTextColor" name="headerTextColor">
<mat-hint>Header text color</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Border Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.borderColor" name="borderColor">
<mat-hint>Border color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Border Radius (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.borderRadius" name="borderRadius" min="0" max="20">
<mat-hint>Corner roundness</mat-hint>
</mat-form-field>
</div>
</div>
</mat-tab>
<!-- Data Tab -->
<mat-tab label="Data">
<div class="config-section">
<h3 class="section-title text-emerald-600">Data Management</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Refresh Interval (ms)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.refreshInterval" name="refreshInterval" min="0" step="1000">
<mat-hint>0 = No auto-refresh</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.allowPdfExport" name="allowPdfExport" class="mr-2">
Allow PDF Export
</mat-checkbox>
<mat-form-field appearance="fill">
<mat-label>Cache Duration (seconds)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.cacheDuration" name="cacheDuration" min="0" max="3600">
<mat-hint>Data cache duration</mat-hint>
</mat-form-field>
</div>
<div class="flex items-center space-x-4 mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableVirtualization" name="enableVirtualization">
Enable Virtual Scrolling
</mat-checkbox>
<mat-checkbox [(ngModel)]="currentConfig.enableLazyLoad" name="enableLazyLoad">
Enable Lazy Loading
</mat-checkbox>
</div>
<div class="grid grid-cols-1 gap-4">
<mat-form-field appearance="fill">
<mat-label>Data Transform Function</mat-label>
<textarea matInput [(ngModel)]="currentConfig.dataTransform" name="dataTransform" rows="3"
placeholder="data => data.map(item => ({ ...item, formattedValue: formatCurrency(item.value) }))"></textarea>
<mat-hint>JavaScript function to transform data</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</div>
<!-- Pivot Rows -->
<div class="config-section border p-3 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-2">Rows</h3>
<div *ngFor="let row of currentConfig.rows; let i = index" class="flex items-center gap-2 mb-2">
<mat-form-field appearance="fill" class="flex-grow">
<mat-label>Row Field</mat-label>
<mat-select [(ngModel)]="row.name" [name]="'row_name_' + i">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
</mat-form-field>
<button mat-icon-button color="warn" (click)="removePivotRow(i)" type="button"><mat-icon>delete</mat-icon></button>
</div>
<button mat-stroked-button color="primary" (click)="addPivotRow()" type="button"><mat-icon>add</mat-icon> Add Row</button>
</div>
<!-- Pivot Columns -->
<div class="config-section border p-3 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-2">Columns</h3>
<div *ngFor="let col of currentConfig.columns; let i = index" class="flex items-center gap-2 mb-2">
<mat-form-field appearance="fill" class="flex-grow">
<mat-label>Column Field</mat-label>
<mat-select [(ngModel)]="col.name" [name]="'col_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<button mat-icon-button color="warn" (click)="removePivotColumn(i)" type="button"><mat-icon>delete</mat-icon></button>
</div>
<button mat-stroked-button color="primary" (click)="addPivotColumn()" type="button"><mat-icon>add</mat-icon> Add Column</button>
</div>
<!-- Pivot Values -->
<div class="config-section border p-3 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-2">Values</h3>
<div *ngFor="let val of currentConfig.values; let i = index" class="flex items-center gap-2 mb-2">
<mat-form-field appearance="fill" class="flex-grow">
<mat-label>Value Field</mat-label>
<mat-select [(ngModel)]="val.name" [name]="'val_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="fill" class="flex-grow">
<mat-label>Caption</mat-label>
<input matInput [(ngModel)]="val.caption" [name]="'val_caption_' + i">
</mat-form-field>
<button mat-icon-button color="warn" (click)="removePivotValue(i)" type="button"><mat-icon>delete</mat-icon></button>
</div>
<button mat-stroked-button color="primary" (click)="addPivotValue()" type="button"><mat-icon>add</mat-icon> Add Value</button>
</div>
<!-- Pivot Filters -->
<div class="config-section border p-3 rounded-lg">
<h3 class="text-lg font-semibold mb-2">Filters</h3>
<div *ngFor="let fil of currentConfig.filters; let i = index" class="flex items-center gap-2 mb-2">
<mat-form-field appearance="fill" class="flex-grow">
<mat-label>Filter Field</mat-label>
<mat-select [(ngModel)]="fil.name" [name]="'fil_name_' + i">
<mat-option *ngFor="let c of availableColumns" [value]="c">{{ c }}</mat-option>
</mat-select>
</mat-form-field>
<button mat-icon-button color="warn" (click)="removePivotFilter(i)" type="button"><mat-icon>delete</mat-icon></button>
</div>
<button mat-stroked-button color="primary" (click)="addPivotFilter()" type="button"><mat-icon>add</mat-icon> Add Filter</button>
</div>
</app-base-config>
`
</mat-tab>
</mat-tab-group>
</div>
`,
styles: [`
.config-container {
padding: 20px;
background: #f8fafc;
border-radius: 12px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.config-section {
margin-bottom: 32px;
padding: 24px;
background: white;
border-radius: 8px;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}
.section-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 20px;
padding-bottom: 8px;
border-bottom: 2px solid #e2e8f0;
}
.config-tabs {
margin-top: 0;
}
.config-tabs .mat-tab-body-content {
padding: 20px 0;
}
.config-tabs .mat-tab-header {
background: white;
border-radius: 8px 8px 0 0;
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.1);
}
.config-tabs .mat-tab-label {
min-width: 120px;
font-weight: 500;
}
.config-tabs .mat-tab-label-active {
color: #3b82f6;
}
.mat-form-field {
margin-bottom: 8px;
}
.grid {
display: grid;
gap: 16px;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (min-width: 768px) {
.md\\:grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.md\\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
.w-full {
width: 100%;
}
.flex {
display: flex;
}
.items-center {
align-items: center;
}
.justify-between {
justify-content: space-between;
}
.space-x-4 > * + * {
margin-left: 16px;
}
.mb-4 {
margin-bottom: 16px;
}
.mt-4 {
margin-top: 16px;
}
.field-section {
margin-bottom: 24px;
}
.field-config-item {
background: #f9fafb;
border: 1px solid #e5e7eb;
border-radius: 8px;
margin-bottom: 16px;
padding: 16px;
}
.feature-group {
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px;
}
.space-y-2 > * + * {
margin-top: 8px;
}
.text-sm {
font-size: 0.875rem;
}
.font-semibold {
font-weight: 600;
}
.text-gray-700 {
color: #374151;
}
.mb-3 {
margin-bottom: 12px;
}
.mt-6 {
margin-top: 24px;
}
.size-config {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 16px;
margin-bottom: 20px;
}
.size-option {
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
background: white;
}
.size-option:hover {
border-color: #3b82f6;
background: #f0f9ff;
}
.size-option.selected {
border-color: #3b82f6;
background: #dbeafe;
}
.size-option h4 {
margin: 0 0 8px 0;
font-size: 1rem;
font-weight: 600;
color: #374151;
}
.size-option p {
margin: 0;
font-size: 0.875rem;
color: #6b7280;
}
.text-blue-600 { color: #2563eb; }
.text-green-600 { color: #16a34a; }
.text-purple-600 { color: #9333ea; }
.text-orange-600 { color: #ea580c; }
.text-emerald-600 { color: #059669; }
`]
})
export class SyncfusionPivotConfigComponent extends BaseConfigComponent implements OnInit {
override ngOnInit(): void {
// Initialize default values for pivot widget
this.initializeDefaultConfig();
this.initializeColorDefaults();
}
override initializeDefaultConfig(): void {
// Basic Configuration
if (!this.currentConfig.title) this.currentConfig.title = 'Pivot Grid Widget';
if (!this.currentConfig.displayOptionView) this.currentConfig.displayOptionView = 'Both';
if (!this.currentConfig.chartType) this.currentConfig.chartType = 'Column';
if (!this.currentConfig.dataSource) this.currentConfig.dataSource = 'static';
if (!this.currentConfig.apiEndpoint) this.currentConfig.apiEndpoint = '';
// Features Configuration
if (this.currentConfig.showFieldList === undefined) this.currentConfig.showFieldList = true;
if (this.currentConfig.showToolbar === undefined) this.currentConfig.showToolbar = true;
if (this.currentConfig.showGroupingBar === undefined) this.currentConfig.showGroupingBar = true;
if (this.currentConfig.showPager === undefined) this.currentConfig.showPager = true;
if (this.currentConfig.allowCalculatedField === undefined) this.currentConfig.allowCalculatedField = false;
if (this.currentConfig.allowConditionalFormatting === undefined) this.currentConfig.allowConditionalFormatting = false;
if (this.currentConfig.allowNumberFormatting === undefined) this.currentConfig.allowNumberFormatting = true;
if (this.currentConfig.allowFieldDragDrop === undefined) this.currentConfig.allowFieldDragDrop = true;
if (this.currentConfig.allowSubTotal === undefined) this.currentConfig.allowSubTotal = true;
if (this.currentConfig.allowGrandTotal === undefined) this.currentConfig.allowGrandTotal = true;
if (this.currentConfig.allowDrillThrough === undefined) this.currentConfig.allowDrillThrough = false;
if (this.currentConfig.allowSorting === undefined) this.currentConfig.allowSorting = true;
if (this.currentConfig.allowExcelExport === undefined) this.currentConfig.allowExcelExport = true;
if (this.currentConfig.allowPdfExport === undefined) this.currentConfig.allowPdfExport = true;
if (this.currentConfig.allowCsvExport === undefined) this.currentConfig.allowCsvExport = true;
if (this.currentConfig.allowPrint === undefined) this.currentConfig.allowPrint = true;
// Aggregation and Formatting
if (!this.currentConfig.aggregationType) this.currentConfig.aggregationType = 'sum';
if (!this.currentConfig.numberFormat) this.currentConfig.numberFormat = 'N';
// Style Configuration
if (!this.currentConfig.backgroundColor) this.currentConfig.backgroundColor = '#FFFFFF';
if (!this.currentConfig.textColor) this.currentConfig.textColor = '#374151';
if (!this.currentConfig.headerBackgroundColor) this.currentConfig.headerBackgroundColor = '#F9FAFB';
if (!this.currentConfig.headerTextColor) this.currentConfig.headerTextColor = '#374151';
if (!this.currentConfig.borderColor) this.currentConfig.borderColor = '#E5E7EB';
if (!this.currentConfig.borderRadius) this.currentConfig.borderRadius = 8;
// Data Configuration
if (!this.currentConfig.refreshInterval) this.currentConfig.refreshInterval = 0;
if (!this.currentConfig.cacheDuration) this.currentConfig.cacheDuration = 300;
if (this.currentConfig.enableVirtualization === undefined) this.currentConfig.enableVirtualization = false;
if (this.currentConfig.enableLazyLoad === undefined) this.currentConfig.enableLazyLoad = false;
if (!this.currentConfig.dataTransform) this.currentConfig.dataTransform = '';
// Initialize arrays
if (!this.currentConfig.rows) this.currentConfig.rows = [];
if (!this.currentConfig.columns) this.currentConfig.columns = [];
if (!this.currentConfig.values) this.currentConfig.values = [];
if (!this.currentConfig.filters) this.currentConfig.filters = [];
if (!this.currentConfig.displayOptionView) this.currentConfig.displayOptionView = 'Both';
if (this.currentConfig.showToolbar === undefined) this.currentConfig.showToolbar = true;
if (!this.currentConfig.chartType) this.currentConfig.chartType = 'Column';
}
private initializeColorDefaults() {
if (!this.currentConfig.backgroundColor) this.currentConfig.backgroundColor = '#FFFFFF';
if (!this.currentConfig.textColor) this.currentConfig.textColor = '#374151';
if (!this.currentConfig.headerBackgroundColor) this.currentConfig.headerBackgroundColor = '#F9FAFB';
if (!this.currentConfig.headerTextColor) this.currentConfig.headerTextColor = '#374151';
if (!this.currentConfig.borderColor) this.currentConfig.borderColor = '#E5E7EB';
}
addPivotRow() {
this.currentConfig.rows.push({ name: '' });
this.configChange.emit(this.currentConfig);
this.addArrayItem('rows', { name: '', caption: '', visible: true, expanded: false });
}
removePivotRow(index: number) {
this.currentConfig.rows.splice(index, 1);
this.configChange.emit(this.currentConfig);
this.removeArrayItem('rows', index);
}
addPivotColumn() {
this.currentConfig.columns.push({ name: '' });
this.configChange.emit(this.currentConfig);
this.addArrayItem('columns', { name: '', caption: '', visible: true, expanded: false });
}
removePivotColumn(index: number) {
this.currentConfig.columns.splice(index, 1);
this.configChange.emit(this.currentConfig);
this.removeArrayItem('columns', index);
}
addPivotValue() {
this.currentConfig.values.push({ name: '', caption: '' });
this.configChange.emit(this.currentConfig);
this.addArrayItem('values', { name: '', caption: '', aggregation: 'sum', visible: true, showSubTotals: true });
}
removePivotValue(index: number) {
this.currentConfig.values.splice(index, 1);
this.configChange.emit(this.currentConfig);
this.removeArrayItem('values', index);
}
addPivotFilter() {
this.currentConfig.filters.push({ name: '' });
this.configChange.emit(this.currentConfig);
this.addArrayItem('filters', { name: '', type: 'exclude', visible: true });
}
removePivotFilter(index: number) {
this.currentConfig.filters.splice(index, 1);
this.configChange.emit(this.currentConfig);
this.removeArrayItem('filters', index);
}
}
......@@ -135,12 +135,7 @@ export class SyncfusionDatagridWidgetComponent extends BaseWidgetComponent imple
public cacheDuration: number = 300;
public dataTransform: string = '';
// Security properties
public requireAuth: boolean = false;
public allowedRoles: string = '';
public dataEncryption: boolean = false;
public auditLog: boolean = false;
public rateLimit: number = 0;
// Security properties (moved to new configuration section)
// Grid-specific properties
public enablePaging: boolean = true;
......@@ -164,6 +159,47 @@ export class SyncfusionDatagridWidgetComponent extends BaseWidgetComponent imple
public selectedRowColor: string = '#DBEAFE';
public hoverRowColor: string = '#F3F4F6';
// New configuration properties from SyncfusionDatagridConfigComponent
public allowPaging: boolean = true;
public allowPageSize: boolean = true;
public showPageInfo: boolean = true;
public allowPageNavigation: boolean = true;
public allowSorting: boolean = true;
public allowAdvancedFiltering: boolean = false;
public allowGrouping: boolean = false;
public allowResizing: boolean = true;
public allowSearching: boolean = false;
public allowSelection: boolean = false;
public allowMultiSelection: boolean = false;
public allowEditing: boolean = false;
public allowAdding: boolean = false;
public selectionMode: string = 'none';
public editMode: string = 'none';
public dataSourceType: string = 'local';
public enableVirtualization: boolean = false;
public enableInfiniteScroll: boolean = false;
public enableLazyLoad: boolean = false;
public rowHeight: number = 40;
public headerRowHeight: number = 40;
public showAlternateRows: boolean = false;
public allowRowSelection: boolean = false;
public showFilterBar: boolean = false;
public filterType: string = 'menu';
public filterBarHeight: number = 40;
public showAggregate: boolean = false;
public aggregateColumns: any[] = [];
public exportFormats: string[] = ['excel'];
public exportFilename: string = 'data-export';
public includeHeaders: boolean = true;
public includeFilters: boolean = false;
public requireAuth: boolean = false;
public allowedRoles: string = '';
public permissionLevel: string = 'read';
public dataEncryption: boolean = false;
public auditLog: boolean = false;
public rateLimit: number = 0;
public sessionTimeout: number = 30;
constructor(
protected override dashboardStateService: DashboardStateService,
private widgetStateService: WidgetStateService // Inject WidgetStateService
......@@ -306,6 +342,50 @@ export class SyncfusionDatagridWidgetComponent extends BaseWidgetComponent imple
this.selectedRowColor = this.configObj.selectedRowColor || '#DBEAFE';
this.hoverRowColor = this.configObj.hoverRowColor || '#F3F4F6';
// New configuration properties
this.allowPaging = this.configObj.allowPaging !== undefined ? this.configObj.allowPaging : true;
this.allowPageSize = this.configObj.allowPageSize !== undefined ? this.configObj.allowPageSize : true;
this.showPageInfo = this.configObj.showPageInfo !== undefined ? this.configObj.showPageInfo : true;
this.allowPageNavigation = this.configObj.allowPageNavigation !== undefined ? this.configObj.allowPageNavigation : true;
this.allowSorting = this.configObj.allowSorting !== undefined ? this.configObj.allowSorting : true;
this.allowMultiSorting = this.configObj.allowMultiSorting !== undefined ? this.configObj.allowMultiSorting : false;
this.allowAdvancedFiltering = this.configObj.allowAdvancedFiltering !== undefined ? this.configObj.allowAdvancedFiltering : false;
this.allowGrouping = this.configObj.allowGrouping !== undefined ? this.configObj.allowGrouping : false;
this.allowReordering = this.configObj.allowReordering !== undefined ? this.configObj.allowReordering : true;
this.allowResizing = this.configObj.allowResizing !== undefined ? this.configObj.allowResizing : true;
this.allowSearching = this.configObj.allowSearching !== undefined ? this.configObj.allowSearching : false;
this.allowSelection = this.configObj.allowSelection !== undefined ? this.configObj.allowSelection : false;
this.allowMultiSelection = this.configObj.allowMultiSelection !== undefined ? this.configObj.allowMultiSelection : false;
this.allowEditing = this.configObj.allowEditing !== undefined ? this.configObj.allowEditing : false;
this.allowAdding = this.configObj.allowAdding !== undefined ? this.configObj.allowAdding : false;
this.selectionMode = this.configObj.selectionMode || 'none';
this.editMode = this.configObj.editMode || 'none';
this.dataSourceType = this.configObj.dataSourceType || 'local';
this.enableVirtualization = this.configObj.enableVirtualization !== undefined ? this.configObj.enableVirtualization : false;
this.enableInfiniteScroll = this.configObj.enableInfiniteScroll !== undefined ? this.configObj.enableInfiniteScroll : false;
this.enableLazyLoad = this.configObj.enableLazyLoad !== undefined ? this.configObj.enableLazyLoad : false;
this.errorMessage = this.configObj.errorMessage || 'Failed to load data';
this.rowHeight = this.configObj.rowHeight || 40;
this.headerRowHeight = this.configObj.headerRowHeight || 40;
this.showAlternateRows = this.configObj.showAlternateRows !== undefined ? this.configObj.showAlternateRows : false;
this.allowRowSelection = this.configObj.allowRowSelection !== undefined ? this.configObj.allowRowSelection : false;
this.showFilterBar = this.configObj.showFilterBar !== undefined ? this.configObj.showFilterBar : false;
this.filterType = this.configObj.filterType || 'menu';
this.filterBarHeight = this.configObj.filterBarHeight || 40;
this.showAggregate = this.configObj.showAggregate !== undefined ? this.configObj.showAggregate : false;
this.aggregateColumns = this.configObj.aggregateColumns || [];
this.exportFormats = this.configObj.exportFormats || ['excel'];
this.exportFilename = this.configObj.exportFilename || 'data-export';
this.includeHeaders = this.configObj.includeHeaders !== undefined ? this.configObj.includeHeaders : true;
this.includeFilters = this.configObj.includeFilters !== undefined ? this.configObj.includeFilters : false;
this.requireAuth = this.configObj.requireAuth !== undefined ? this.configObj.requireAuth : false;
this.allowedRoles = this.configObj.allowedRoles || '';
this.permissionLevel = this.configObj.permissionLevel || 'read';
this.dataEncryption = this.configObj.dataEncryption !== undefined ? this.configObj.dataEncryption : false;
this.auditLog = this.configObj.auditLog !== undefined ? this.configObj.auditLog : false;
this.rateLimit = this.configObj.rateLimit || 0;
this.sessionTimeout = this.configObj.sessionTimeout || 30;
// Update page settings with configured page size
this.pageSettings = { pageSize: this.pageSize, pageSizes: this.pageSizes };
}
......
......@@ -99,26 +99,35 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
public auditLog: boolean = false;
public rateLimit: number = 0;
// Pivot-specific properties
// Pivot-specific properties from SyncfusionPivotConfigComponent
public displayOptionView: string = 'Both';
public chartType: string = 'Column';
public showFieldList: boolean = true;
public showToolbar: boolean = true;
public showGroupingBar: boolean = true;
public allowCalculatedField: boolean = true;
public allowConditionalFormatting: boolean = true;
public showPager: boolean = true;
public allowCalculatedField: boolean = false;
public allowConditionalFormatting: boolean = false;
public allowNumberFormatting: boolean = true;
public allowFieldDragDrop: boolean = true;
public allowSubTotal: boolean = true;
public allowGrandTotal: boolean = true;
public allowDrillThrough: boolean = false;
public allowSorting: boolean = true;
public allowExcelExport: boolean = true;
public allowPdfExport: boolean = true;
public allowCsvExport: boolean = true;
public allowPrint: boolean = true;
public aggregationType: string = 'sum';
public numberFormat: string = 'N';
public enableVirtualization: boolean = false;
public enableLazyLoad: boolean = false;
// Pivot-specific properties (moved to above section)
public showChart: boolean = true;
public showGrid: boolean = true;
public displayOptionView: string = 'Both';
public chartType: string = 'Column';
public enableDrillThrough: boolean = true;
public enableSorting: boolean = true;
public enableFiltering: boolean = true;
public enableGrouping: boolean = true;
public allowFiltering: boolean = true;
constructor(
protected override dashboardStateService: DashboardStateService,
......@@ -151,6 +160,8 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
applyInitialConfig(): void {
// Basic configuration
this.title = this.configObj.title || 'Pivot Table';
this.displayOptionView = this.configObj.displayOptionView || 'Both';
this.chartType = this.configObj.chartType || 'Column';
this.chartSettings = this.configObj.chartSettings || {
chartSeries: { type: this.chartType }
};
......@@ -164,6 +175,26 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
chartSettings: this.chartSettings,
};
// Pivot features configuration
this.showFieldList = this.configObj.showFieldList !== undefined ? this.configObj.showFieldList : true;
this.showToolbar = this.configObj.showToolbar !== undefined ? this.configObj.showToolbar : true;
this.showGroupingBar = this.configObj.showGroupingBar !== undefined ? this.configObj.showGroupingBar : true;
this.showPager = this.configObj.showPager !== undefined ? this.configObj.showPager : true;
this.allowCalculatedField = this.configObj.allowCalculatedField !== undefined ? this.configObj.allowCalculatedField : false;
this.allowConditionalFormatting = this.configObj.allowConditionalFormatting !== undefined ? this.configObj.allowConditionalFormatting : false;
this.allowNumberFormatting = this.configObj.allowNumberFormatting !== undefined ? this.configObj.allowNumberFormatting : true;
this.allowFieldDragDrop = this.configObj.allowFieldDragDrop !== undefined ? this.configObj.allowFieldDragDrop : true;
this.allowSubTotal = this.configObj.allowSubTotal !== undefined ? this.configObj.allowSubTotal : true;
this.allowGrandTotal = this.configObj.allowGrandTotal !== undefined ? this.configObj.allowGrandTotal : true;
this.allowDrillThrough = this.configObj.allowDrillThrough !== undefined ? this.configObj.allowDrillThrough : false;
this.allowSorting = this.configObj.allowSorting !== undefined ? this.configObj.allowSorting : true;
this.allowExcelExport = this.configObj.allowExcelExport !== undefined ? this.configObj.allowExcelExport : true;
this.allowPdfExport = this.configObj.allowPdfExport !== undefined ? this.configObj.allowPdfExport : true;
this.allowCsvExport = this.configObj.allowCsvExport !== undefined ? this.configObj.allowCsvExport : true;
this.allowPrint = this.configObj.allowPrint !== undefined ? this.configObj.allowPrint : true;
this.aggregationType = this.configObj.aggregationType || 'sum';
this.numberFormat = this.configObj.numberFormat || 'N';
// Style configuration
this.backgroundColor = this.configObj.backgroundColor || '#FFFFFF';
this.borderColor = this.configObj.borderColor || '#E5E7EB';
......@@ -238,9 +269,9 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
this.showGrid = this.configObj.showGrid !== undefined ? this.configObj.showGrid : true;
this.displayOptionView = this.configObj.displayOptionView || 'Both';
this.chartType = this.configObj.chartType || 'Column';
this.enableDrillThrough = this.configObj.enableDrillThrough !== undefined ? this.configObj.enableDrillThrough : true;
this.enableSorting = this.configObj.enableSorting !== undefined ? this.configObj.enableSorting : true;
this.enableFiltering = this.configObj.enableFiltering !== undefined ? this.configObj.enableFiltering : true;
this.allowDrillThrough = this.configObj.allowDrillThrough !== undefined ? this.configObj.allowDrillThrough : true;
this.allowSorting = this.configObj.allowSorting !== undefined ? this.configObj.allowSorting : true;
this.allowFiltering = this.configObj.allowFiltering !== undefined ? this.configObj.allowFiltering : true;
this.enableGrouping = this.configObj.enableGrouping !== undefined ? this.configObj.enableGrouping : true;
// Update toolbar and display options based on configuration
......@@ -400,9 +431,9 @@ export class SyncfusionPivotWidgetComponent extends BaseWidgetComponent implemen
this.showGrid = true;
this.displayOptionView = 'Both';
this.chartType = 'Column';
this.enableDrillThrough = true;
this.enableSorting = true;
this.enableFiltering = true;
this.allowDrillThrough = true;
this.allowSorting = true;
this.allowFiltering = true;
this.enableGrouping = true;
// Update toolbar and display options
......
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