Commit 49e784c7 by Ooh-Ao

config

parent 7ff59ecb
......@@ -605,423 +605,7 @@
</mat-form-field>
</div>
<div *ngIf="widgetType === 'SimpleKpiWidgetComponent'">
<!-- 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>Value Field</mat-label>
<mat-select [(ngModel)]="currentConfig.valueField" name="valueField">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
<mat-hint>Field containing the KPI value</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Label Field</mat-label>
<mat-select [(ngModel)]="currentConfig.labelField" name="labelField">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
<mat-hint>Field containing the KPI label</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>Aggregation</mat-label>
<mat-select [(ngModel)]="currentConfig.aggregation" name="aggregation">
<mat-option value="count">Count</mat-option>
<mat-option value="sum">Sum</mat-option>
<mat-option value="average">Average</mat-option>
<mat-option value="max">Maximum</mat-option>
<mat-option value="min">Minimum</mat-option>
</mat-select>
<mat-hint>How to aggregate the data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Unit</mat-label>
<input matInput [(ngModel)]="currentConfig.unit" name="unit" placeholder="e.g., $, %, items" aria-label="Unit">
<mat-hint>Unit to display after the value</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>Icon (Bootstrap Icons)</mat-label>
<input matInput [(ngModel)]="currentConfig.icon" name="icon" placeholder="e.g., person-fill, building" aria-label="Icon">
<mat-hint>Find icons at icons.getbootstrap.com</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Decimal Places</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.decimalPlaces" name="decimalPlaces" min="0" max="10" aria-label="Decimal places">
<mat-hint>Number of decimal places to show</mat-hint>
</mat-form-field>
</div>
</div>
<!-- Trend Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-green-600">Trend Settings</h3>
<div class="flex items-center mb-3">
<mat-checkbox [(ngModel)]="currentConfig.showTrend" name="showTrend" class="mr-2">
Show Trend Indicator
</mat-checkbox>
</div>
<div *ngIf="currentConfig.showTrend" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Trend Field</mat-label>
<mat-select [(ngModel)]="currentConfig.trendField" name="trendField">
<mat-option *ngFor="let col of availableColumns" [value]="col">{{ col }}</mat-option>
</mat-select>
<mat-hint>Field containing trend data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Trend Type</mat-label>
<mat-select [(ngModel)]="currentConfig.trendType" name="trendType">
<mat-option value="percentage">Percentage Change</mat-option>
<mat-option value="absolute">Absolute Change</mat-option>
<mat-option value="ratio">Ratio</mat-option>
</mat-select>
<mat-hint>How to calculate trend</mat-hint>
</mat-form-field>
</div>
</div>
<!-- Style Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-purple-600">Style & Colors</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 [(ngModel)]="currentConfig.backgroundColor" name="backgroundColor" placeholder="#FF0000 or linear-gradient(...)" aria-label="Background color">
<mat-hint>Header 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" class="h-[40px]" aria-label="Text color">
<mat-hint>Text color for labels</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>Accent Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.accentColor" name="accentColor" class="h-[40px]" aria-label="Accent color">
<mat-hint>Color for the main KPI value</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Border Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.borderColor" name="borderColor" class="h-[40px]" aria-label="Border color">
<mat-hint>Card border 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>Icon Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.iconColor" name="iconColor" class="h-[40px]" aria-label="Icon color">
<mat-hint>Icon 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="50" aria-label="Border radius">
<mat-hint>Roundness of widget corners</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Padding (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.padding" name="padding" min="0" max="100" aria-label="Padding">
<mat-hint>Internal spacing</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="48" aria-label="Font size">
<mat-hint>Font size for values</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Weight</mat-label>
<mat-select [(ngModel)]="currentConfig.fontWeight" name="fontWeight">
<mat-option value="normal">Normal</mat-option>
<mat-option value="bold">Bold</mat-option>
<mat-option value="lighter">Lighter</mat-option>
<mat-option value="bolder">Bolder</mat-option>
</mat-select>
<mat-hint>Font weight</mat-hint>
</mat-form-field>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Font Family</mat-label>
<mat-select [(ngModel)]="currentConfig.fontFamily" name="fontFamily">
<mat-option value="system-ui, -apple-system, sans-serif">System Font</mat-option>
<mat-option value="Arial, sans-serif">Arial</mat-option>
<mat-option value="Helvetica, sans-serif">Helvetica</mat-option>
<mat-option value="Georgia, serif">Georgia</mat-option>
<mat-option value="Times New Roman, serif">Times New Roman</mat-option>
<mat-option value="Courier New, monospace">Courier New</mat-option>
</mat-select>
<mat-hint>Font family for the widget</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Custom CSS</mat-label>
<textarea matInput [(ngModel)]="currentConfig.customCSS" name="customCSS" rows="4"
placeholder="/* Add custom CSS rules here */&#10;.simple-kpi-widget:hover {&#10; transform: translateY(-4px);&#10;}"></textarea>
<mat-hint>Add custom CSS for advanced styling</mat-hint>
</mat-form-field>
</div>
<!-- Animation Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-orange-600">Animation Settings</h3>
<div class="flex items-center mb-3">
<mat-checkbox [(ngModel)]="currentConfig.enableAnimations" name="enableAnimations" class="mr-2">
Enable Animations
</mat-checkbox>
</div>
<div *ngIf="currentConfig.enableAnimations" class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Animation Type</mat-label>
<mat-select [(ngModel)]="currentConfig.animationType" name="animationType">
<mat-option value="fade">Fade</mat-option>
<mat-option value="slide">Slide</mat-option>
<mat-option value="bounce">Bounce</mat-option>
<mat-option value="pulse">Pulse</mat-option>
<mat-option value="none">None</mat-option>
</mat-select>
<mat-hint>Animation effect type</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Animation Duration (ms)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.animationDuration" name="animationDuration" min="100" max="2000" step="100" aria-label="Animation duration">
<mat-hint>Duration of animation</mat-hint>
</mat-form-field>
</div>
<div *ngIf="currentConfig.enableAnimations" class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.hoverEffects" name="hoverEffects" class="mr-2">
Enable Hover Effects
</mat-checkbox>
</div>
</div>
<!-- Interaction Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-indigo-600">Interaction Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableTooltip" name="enableTooltip" class="mr-2">
Enable Tooltips
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableClick" name="enableClick" class="mr-2">
Enable Click Events
</mat-checkbox>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableHover" name="enableHover" class="mr-2">
Enable Hover Effects
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableExport" name="enableExport" class="mr-2">
Enable Export
</mat-checkbox>
</div>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Click Action</mat-label>
<mat-select [(ngModel)]="currentConfig.clickAction" name="clickAction">
<mat-option value="none">None</mat-option>
<mat-option value="drill_down">Drill Down</mat-option>
<mat-option value="open_modal">Open Modal</mat-option>
<mat-option value="navigate">Navigate</mat-option>
<mat-option value="custom">Custom</mat-option>
</mat-select>
<mat-hint>Action when widget is clicked</mat-hint>
</mat-form-field>
<mat-form-field *ngIf="currentConfig.clickAction === 'custom'" appearance="fill" class="w-full">
<mat-label>Custom Click Handler</mat-label>
<textarea matInput [(ngModel)]="currentConfig.customClickHandler" name="customClickHandler" rows="3"
placeholder="function(event) {&#10; console.log('Widget clicked:', event);&#10;}"></textarea>
<mat-hint>Custom JavaScript function for click events</mat-hint>
</mat-form-field>
</div>
<!-- Layout Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-teal-600">Layout Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.width" name="width" min="100" max="800" aria-label="Widget width">
<mat-hint>Widget width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.height" name="height" min="100" max="600" aria-label="Widget height">
<mat-hint>Widget height</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>Minimum Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.minWidth" name="minWidth" min="50" max="400" aria-label="Minimum width">
<mat-hint>Minimum widget width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Minimum Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.minHeight" name="minHeight" min="50" max="300" aria-label="Minimum height">
<mat-hint>Minimum widget height</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>Aspect Ratio</mat-label>
<mat-select [(ngModel)]="currentConfig.aspectRatio" name="aspectRatio">
<mat-option value="auto">Auto</mat-option>
<mat-option value="16:9">16:9</mat-option>
<mat-option value="4:3">4:3</mat-option>
<mat-option value="1:1">1:1 (Square)</mat-option>
<mat-option value="3:2">3:2</mat-option>
</mat-select>
<mat-hint>Widget aspect ratio</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.responsive" name="responsive" class="mr-2">
Responsive Layout
</mat-checkbox>
</div>
</div>
</div>
<!-- Data Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-red-600">Data Settings</h3>
<mat-form-field appearance="fill" class="w-full">
<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="websocket">WebSocket</mat-option>
<mat-option value="file">File Upload</mat-option>
</mat-select>
<mat-hint>Data source type</mat-hint>
</mat-form-field>
<mat-form-field *ngIf="currentConfig.dataSource === 'api'" appearance="fill" class="w-full">
<mat-label>API Endpoint</mat-label>
<input matInput [(ngModel)]="currentConfig.apiEndpoint" name="apiEndpoint" placeholder="/api/kpi-data" aria-label="API endpoint">
<mat-hint>API endpoint URL</mat-hint>
</mat-form-field>
<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" aria-label="Refresh interval">
<mat-hint>0 = No auto-refresh</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.cacheEnabled" name="cacheEnabled" class="mr-2">
Enable Data Caching
</mat-checkbox>
</div>
</div>
<mat-form-field *ngIf="currentConfig.cacheEnabled" appearance="fill" class="w-full">
<mat-label>Cache Duration (seconds)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.cacheDuration" name="cacheDuration" min="1" max="3600" aria-label="Cache duration">
<mat-hint>How long to cache data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="w-full">
<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>
<!-- Security Configuration -->
<div class="config-section border p-4 rounded-lg mb-4">
<h3 class="text-lg font-semibold mb-3 text-gray-600">Security Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.requireAuth" name="requireAuth" class="mr-2">
Require Authentication
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.dataEncryption" name="dataEncryption" class="mr-2">
Enable Data Encryption
</mat-checkbox>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.auditLog" name="auditLog" class="mr-2">
Enable Audit Logging
</mat-checkbox>
</div>
<mat-form-field appearance="fill">
<mat-label>Rate Limit (requests/min)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rateLimit" name="rateLimit" min="0" aria-label="Rate limit">
<mat-hint>0 = No limit</mat-hint>
</mat-form-field>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Allowed Roles (comma-separated)</mat-label>
<input matInput [(ngModel)]="currentConfig.allowedRoles" name="allowedRoles" placeholder="admin, analyst, manager" aria-label="Allowed roles">
<mat-hint>Roles that can access this widget</mat-hint>
</mat-form-field>
</div>
</div>
<div *ngIf="widgetType === 'PieChartWidgetComponent' || widgetType === 'BarChartWidgetComponent' || widgetType === 'AreaChartWidgetComponent' || widgetType === 'DoughnutChartWidgetComponent' || widgetType === 'FunnelChartWidgetComponent'">
<mat-form-field appearance="fill">
......
......@@ -26,11 +26,11 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
],
template: `
<div class="config-container">
<mat-tab-group class="config-tabs">
<mat-tab-group class="config-tabs" dynamicHeight>
<!-- Basic Configuration Tab -->
<mat-tab label="Basic">
<div class="config-section">
<h3 class="text-blue-600">Basic Configuration</h3>
<h3 class="section-title text-blue-600">Basic Configuration</h3>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Title</mat-label>
......@@ -77,6 +77,25 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Icon (Bootstrap Icons)</mat-label>
<input matInput [(ngModel)]="currentConfig.icon" name="icon" placeholder="e.g., person-fill, building">
<mat-hint>Find icons at icons.getbootstrap.com</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Icon Position</mat-label>
<mat-select [(ngModel)]="currentConfig.iconPosition" name="iconPosition">
<mat-option value="left">Left</mat-option>
<mat-option value="right">Right</mat-option>
<mat-option value="top">Top</mat-option>
<mat-option value="bottom">Bottom</mat-option>
</mat-select>
<mat-hint>Position of the icon</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>Aggregation</mat-label>
<mat-select [(ngModel)]="currentConfig.aggregation" name="aggregation">
<mat-option value="sum">Sum</mat-option>
......@@ -148,7 +167,7 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<!-- Style Tab -->
<mat-tab label="Style">
<div class="config-section">
<h3 class="text-blue-600">Style Configuration</h3>
<h3 class="section-title text-purple-600">Style & Colors</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
......@@ -166,19 +185,33 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Accent Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.accentColor" name="accentColor" class="color-picker">
<mat-hint>Color for the main KPI value</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Value Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.valueColor" name="valueColor">
<mat-hint>KPI value 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>Label Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.labelColor" name="labelColor">
<mat-hint>KPI label color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Icon Color</mat-label>
<input matInput type="color" [(ngModel)]="currentConfig.iconColor" name="iconColor" class="color-picker">
<mat-hint>Icon color</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Font Size (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.fontSize" name="fontSize" min="10" max="48">
......@@ -190,13 +223,19 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<input matInput type="number" [(ngModel)]="currentConfig.valueFontSize" name="valueFontSize" min="10" max="72">
<mat-hint>KPI value font size</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Padding (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.padding" name="padding" min="0" max="100">
<mat-hint>Internal spacing</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>
<input matInput type="number" [(ngModel)]="currentConfig.borderRadius" name="borderRadius" min="0" max="50">
<mat-hint>Roundness of widget corners</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
......@@ -209,8 +248,8 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<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>
<input matInput type="color" [(ngModel)]="currentConfig.borderColor" name="borderColor" class="color-picker">
<mat-hint>Card border color</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
......@@ -224,6 +263,45 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
<mat-hint>Drop shadow effect</mat-hint>
</mat-form-field>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<mat-form-field appearance="fill">
<mat-label>Font Weight</mat-label>
<mat-select [(ngModel)]="currentConfig.fontWeight" name="fontWeight">
<mat-option value="normal">Normal</mat-option>
<mat-option value="bold">Bold</mat-option>
<mat-option value="lighter">Lighter</mat-option>
<mat-option value="bolder">Bolder</mat-option>
</mat-select>
<mat-hint>Font weight</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Font Family</mat-label>
<mat-select [(ngModel)]="currentConfig.fontFamily" name="fontFamily">
<mat-option value="system-ui, -apple-system, sans-serif">System Font</mat-option>
<mat-option value="Arial, sans-serif">Arial</mat-option>
<mat-option value="Helvetica, sans-serif">Helvetica</mat-option>
<mat-option value="Georgia, serif">Georgia</mat-option>
<mat-option value="Times New Roman, serif">Times New Roman</mat-option>
<mat-option value="Courier New, monospace">Courier New</mat-option>
</mat-select>
<mat-hint>Font family for the widget</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Icon Size (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.iconSize" name="iconSize" min="16" max="64">
<mat-hint>Icon size in pixels</mat-hint>
</mat-form-field>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Custom CSS</mat-label>
<textarea matInput [(ngModel)]="currentConfig.customCSS" name="customCSS" rows="4"
placeholder="/* Add custom CSS rules here */&#10;.simple-kpi-widget:hover {&#10; transform: translateY(-4px);&#10;}"></textarea>
<mat-hint>Add custom CSS for advanced styling</mat-hint>
</mat-form-field>
</div>
</mat-tab>
......@@ -450,10 +528,211 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
</div>
</mat-tab>
<!-- Layout Tab -->
<mat-tab label="Layout">
<div class="config-section">
<h3 class="section-title text-teal-600">Layout Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<mat-form-field appearance="fill">
<mat-label>Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.width" name="width" min="100" max="800">
<mat-hint>Widget width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.height" name="height" min="100" max="600">
<mat-hint>Widget height</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>Minimum Width (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.minWidth" name="minWidth" min="50" max="400">
<mat-hint>Minimum widget width</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill">
<mat-label>Minimum Height (px)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.minHeight" name="minHeight" min="50" max="300">
<mat-hint>Minimum widget height</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>Aspect Ratio</mat-label>
<mat-select [(ngModel)]="currentConfig.aspectRatio" name="aspectRatio">
<mat-option value="auto">Auto</mat-option>
<mat-option value="16:9">16:9</mat-option>
<mat-option value="4:3">4:3</mat-option>
<mat-option value="1:1">1:1 (Square)</mat-option>
<mat-option value="3:2">3:2</mat-option>
</mat-select>
<mat-hint>Widget aspect ratio</mat-hint>
</mat-form-field>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.responsive" name="responsive" class="mr-2">
Responsive Layout
</mat-checkbox>
</div>
</div>
</div>
</mat-tab>
<!-- Data Tab -->
<mat-tab label="Data">
<div class="config-section">
<h3 class="section-title text-red-600">Data Settings</h3>
<mat-form-field appearance="fill" class="w-full">
<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="websocket">WebSocket</mat-option>
<mat-option value="file">File Upload</mat-option>
</mat-select>
<mat-hint>Data source type</mat-hint>
</mat-form-field>
<mat-form-field *ngIf="currentConfig.dataSource === 'api'" appearance="fill" class="w-full">
<mat-label>API Endpoint</mat-label>
<input matInput [(ngModel)]="currentConfig.apiEndpoint" name="apiEndpoint" placeholder="/api/kpi-data">
<mat-hint>API endpoint URL</mat-hint>
</mat-form-field>
<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.cacheEnabled" name="cacheEnabled" class="mr-2">
Enable Data Caching
</mat-checkbox>
</div>
</div>
<mat-form-field *ngIf="currentConfig.cacheEnabled" appearance="fill" class="w-full">
<mat-label>Cache Duration (seconds)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.cacheDuration" name="cacheDuration" min="1" max="3600">
<mat-hint>How long to cache data</mat-hint>
</mat-form-field>
<mat-form-field appearance="fill" class="w-full">
<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>
</mat-tab>
<!-- Interaction Tab -->
<mat-tab label="Interaction">
<div class="config-section">
<h3 class="section-title text-indigo-600">Interaction Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableTooltip" name="enableTooltip" class="mr-2">
Enable Tooltips
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableClick" name="enableClick" class="mr-2">
Enable Click Events
</mat-checkbox>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableHover" name="enableHover" class="mr-2">
Enable Hover Effects
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.enableExport" name="enableExport" class="mr-2">
Enable Export
</mat-checkbox>
</div>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Click Action</mat-label>
<mat-select [(ngModel)]="currentConfig.clickAction" name="clickAction">
<mat-option value="none">None</mat-option>
<mat-option value="drill_down">Drill Down</mat-option>
<mat-option value="open_modal">Open Modal</mat-option>
<mat-option value="navigate">Navigate</mat-option>
<mat-option value="custom">Custom</mat-option>
</mat-select>
<mat-hint>Action when widget is clicked</mat-hint>
</mat-form-field>
<mat-form-field *ngIf="currentConfig.clickAction === 'custom'" appearance="fill" class="w-full">
<mat-label>Custom Click Handler</mat-label>
<textarea matInput [(ngModel)]="currentConfig.customClickHandler" name="customClickHandler" rows="3"
placeholder="function(event) {&#10; console.log('Widget clicked:', event);&#10;}"></textarea>
<mat-hint>Custom JavaScript function for click events</mat-hint>
</mat-form-field>
</div>
</mat-tab>
<!-- Security Tab -->
<mat-tab label="Security">
<div class="config-section">
<h3 class="section-title text-gray-600">Security Settings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.requireAuth" name="requireAuth" class="mr-2">
Require Authentication
</mat-checkbox>
</div>
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.dataEncryption" name="dataEncryption" class="mr-2">
Enable Data Encryption
</mat-checkbox>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="flex items-center">
<mat-checkbox [(ngModel)]="currentConfig.auditLog" name="auditLog" class="mr-2">
Enable Audit Logging
</mat-checkbox>
</div>
<mat-form-field appearance="fill">
<mat-label>Rate Limit (requests/min)</mat-label>
<input matInput type="number" [(ngModel)]="currentConfig.rateLimit" name="rateLimit" min="0">
<mat-hint>0 = No limit</mat-hint>
</mat-form-field>
</div>
<mat-form-field appearance="fill" class="w-full">
<mat-label>Allowed Roles (comma-separated)</mat-label>
<input matInput [(ngModel)]="currentConfig.allowedRoles" name="allowedRoles" placeholder="admin, analyst, manager">
<mat-hint>Roles that can access this widget</mat-hint>
</mat-form-field>
</div>
</mat-tab>
<!-- Condition Tab -->
<mat-tab label="Condition">
<div class="config-section">
<h3 class="text-blue-600">Conditional Formatting</h3>
<h3 class="section-title text-blue-600">Conditional Formatting</h3>
<div class="flex items-center mb-4">
<mat-checkbox [(ngModel)]="currentConfig.enableConditionalFormatting" name="enableConditionalFormatting">
......@@ -512,17 +791,114 @@ import { BaseConfigComponent } from '../../../widget-config/base-config/base-con
`,
styles: [`
.config-container {
padding: 16px;
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: 16px;
margin-top: 0;
}
.config-tabs .mat-tab-body-content {
padding: 16px 0;
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;
}
.mat-form-field.color-picker {
height: 40px;
}
.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;
}
.mr-2 {
margin-right: 8px;
}
.mb-4 {
margin-bottom: 16px;
}
.text-blue-600 { color: #2563eb; }
.text-purple-600 { color: #9333ea; }
.text-green-600 { color: #16a34a; }
.text-orange-600 { color: #ea580c; }
.text-indigo-600 { color: #4f46e5; }
.text-teal-600 { color: #0d9488; }
.text-red-600 { color: #dc2626; }
.text-gray-600 { color: #4b5563; }
`]
})
export class SimpleKpiConfigComponent extends BaseConfigComponent implements OnInit {
......@@ -558,6 +934,7 @@ export class SimpleKpiConfigComponent extends BaseConfigComponent implements OnI
if (!this.currentConfig.labelColor) this.currentConfig.labelColor = '#FFFFFF';
if (!this.currentConfig.iconColor) this.currentConfig.iconColor = '#FFFFFF';
if (!this.currentConfig.borderColor) this.currentConfig.borderColor = '#FFFFFF';
if (!this.currentConfig.accentColor) this.currentConfig.accentColor = '#3B82F6';
if (!this.currentConfig.trueColor) this.currentConfig.trueColor = '#10B981';
if (!this.currentConfig.falseColor) this.currentConfig.falseColor = '#EF4444';
......@@ -583,6 +960,31 @@ export class SimpleKpiConfigComponent extends BaseConfigComponent implements OnI
if (!this.currentConfig.conditionField) this.currentConfig.conditionField = '';
if (!this.currentConfig.conditionOperator) this.currentConfig.conditionOperator = 'greater_than';
if (!this.currentConfig.conditionValue) this.currentConfig.conditionValue = '';
// Initialize additional fields
if (!this.currentConfig.padding) this.currentConfig.padding = 16;
if (!this.currentConfig.fontWeight) this.currentConfig.fontWeight = 'normal';
if (!this.currentConfig.fontFamily) this.currentConfig.fontFamily = 'system-ui, -apple-system, sans-serif';
if (!this.currentConfig.customCSS) this.currentConfig.customCSS = '';
if (!this.currentConfig.minWidth) this.currentConfig.minWidth = 200;
if (!this.currentConfig.minHeight) this.currentConfig.minHeight = 150;
if (!this.currentConfig.aspectRatio) this.currentConfig.aspectRatio = 'auto';
if (!this.currentConfig.responsive) this.currentConfig.responsive = true;
if (!this.currentConfig.refreshInterval) this.currentConfig.refreshInterval = 0;
if (!this.currentConfig.cacheEnabled) this.currentConfig.cacheEnabled = false;
if (!this.currentConfig.cacheDuration) this.currentConfig.cacheDuration = 300;
if (!this.currentConfig.dataTransform) this.currentConfig.dataTransform = '';
if (!this.currentConfig.enableTooltip) this.currentConfig.enableTooltip = false;
if (!this.currentConfig.enableClick) this.currentConfig.enableClick = false;
if (!this.currentConfig.enableHover) this.currentConfig.enableHover = true;
if (!this.currentConfig.enableExport) this.currentConfig.enableExport = false;
if (!this.currentConfig.clickAction) this.currentConfig.clickAction = 'none';
if (!this.currentConfig.customClickHandler) this.currentConfig.customClickHandler = '';
if (!this.currentConfig.requireAuth) this.currentConfig.requireAuth = false;
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.allowedRoles) this.currentConfig.allowedRoles = '';
}
override setSizeOption(optionId: string) {
......
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