diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.html
new file mode 100644
index 0000000..bb36ba8
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.html
@@ -0,0 +1,481 @@
+
+
Chart Configuration Manager
+
+
+
+
+
+ {{ errorMessage }}
+
+
+
+
+
+
+ {{ successMessage }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Name
+ Display Name
+ Description
+ Status
+ Created At
+ Updated At
+ Actions
+
+
+ {{chartType.name}}
+ {{chartType.displayName}}
+ {{chartType.description}}
+
+
+ {{chartType.isActive ? 'Active' : 'Inactive'}}
+
+
+ {{chartType.createdAt | date:'short'}}
+ {{chartType.updatedAt | date:'short'}}
+
+
+
+
+
+
+
+
+ {{chartTypes.length}} chart type(s)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Component Name
+ Component Type
+ Display Label
+ Placeholder
+ Required
+ Sort Order
+ Created At
+ Updated At
+ Actions
+
+
+ {{uiComponent.componentName}}
+ {{uiComponent.componentType}}
+ {{uiComponent.displayLabel}}
+ {{uiComponent.placeholder}}
+
+
+ {{uiComponent.isRequired ? 'Yes' : 'No'}}
+
+
+ {{uiComponent.sortOrder}}
+ {{uiComponent.createdAt | date:'short'}}
+ {{uiComponent.updatedAt | date:'short'}}
+
+
+
+
+
+
+
+ {{uiComponents.length}} UI component(s)
+
+
+
+
+
+
+
Edit UI Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Property Name
+ Property Value
+ Property Type
+ Created At
+ Updated At
+ Actions
+
+
+ {{property.propertyName}}
+ {{property.propertyValue}}
+ {{property.propertyType}}
+ {{property.createdAt | date:'short'}}
+ {{property.updatedAt | date:'short'}}
+
+
+
+
+
+
+
+ {{componentProperties.length}} propertie(s)
+
+
+
+
+
+
+
Edit Component Property
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Template Name
+ Is Default
+ Created At
+ Updated At
+ Actions
+
+
+ {{template.templateName}}
+
+
+ {{template.isDefault ? 'Yes' : 'No'}}
+
+
+ {{template.createdAt | date:'short'}}
+ {{template.updatedAt | date:'short'}}
+
+
+
+
+
+
+
+ {{chartTemplates.length}} template(s)
+
+
+
+
+
+
+
Edit Chart Template
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Field Name
+ Field Label
+ Field Type
+ Required
+ Show in UI
+ Sort Order
+ Created At
+ Updated At
+ Actions
+
+
+ {{field.fieldName}}
+ {{field.fieldLabel}}
+ {{field.fieldType}}
+
+
+ {{field.isRequired ? 'Yes' : 'No'}}
+
+
+
+
+ {{field.showInUi ? 'Yes' : 'No'}}
+
+
+ {{field.sortOrder}}
+ {{field.createdAt | date:'short'}}
+ {{field.updatedAt | date:'short'}}
+
+
+
+
+
+
+
+ {{dynamicFields.length}} field(s)
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.scss
new file mode 100644
index 0000000..29f401d
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.scss
@@ -0,0 +1,64 @@
+.chart-config-manager {
+ padding: 20px;
+
+ .card {
+ margin-bottom: 20px;
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ h3 {
+ margin: 0;
+ }
+ }
+
+ .card-block {
+ padding: 15px;
+
+ form {
+ margin-bottom: 20px;
+ }
+ }
+ }
+
+ .form-actions {
+ display: flex;
+ gap: 10px;
+ margin-top: 15px;
+ }
+
+ clr-datagrid {
+ min-height: 200px;
+ }
+
+ .label {
+ padding: 4px 8px;
+ border-radius: 3px;
+ font-size: 12px;
+ font-weight: bold;
+ }
+
+ .label-success {
+ background-color: #318700;
+ color: white;
+ }
+
+ .label-danger {
+ background-color: #e62200;
+ color: white;
+ }
+
+ .required {
+ color: red;
+ }
+
+ .alert {
+ margin-bottom: 20px;
+ }
+
+ clr-tab-content {
+ padding: 15px 0;
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.ts
new file mode 100644
index 0000000..e506df4
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-config-manager.component.ts
@@ -0,0 +1,726 @@
+import { Component, OnInit } from '@angular/core';
+import { ClrLoadingState } from '@clr/angular';
+import { ChartTypeService } from '../chart-type-manager/chart-type.service';
+import { UiComponentService } from './ui-component.service';
+import { ComponentPropertyService } from './component-property.service';
+import { ChartTemplateService } from './chart-template.service';
+import { DynamicFieldService } from './dynamic-field.service';
+
+export interface ChartType {
+ id: number;
+ name: string;
+ displayName: string;
+ description: string;
+ isActive: boolean;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface UiComponent {
+ id: number;
+ chartType: ChartType;
+ componentName: string;
+ componentType: string;
+ displayLabel: string;
+ placeholder: string;
+ isRequired: boolean;
+ sortOrder: number;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface ComponentProperty {
+ id: number;
+ component: UiComponent;
+ propertyName: string;
+ propertyValue: string;
+ propertyType: string;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface ChartTemplate {
+ id: number;
+ chartType: ChartType;
+ templateName: string;
+ templateHtml: string;
+ templateCss: string;
+ isDefault: boolean;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface DynamicField {
+ id: number;
+ chartType: ChartType;
+ fieldName: string;
+ fieldLabel: string;
+ fieldType: string;
+ fieldOptions: string;
+ isRequired: boolean;
+ showInUi: boolean;
+ sortOrder: number;
+ createdAt: string;
+ updatedAt: string;
+}
+
+@Component({
+ selector: 'app-chart-config-manager',
+ templateUrl: './chart-config-manager.component.html',
+ styleUrls: ['./chart-config-manager.component.scss']
+})
+export class ChartConfigManagerComponent implements OnInit {
+ // Chart Types
+ chartTypes: ChartType[] = [];
+ selectedChartType: ChartType | null = null;
+ newChartType: Partial = {};
+ showAddChartTypeForm = false;
+ chartTypeLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
+
+ // UI Components
+ uiComponents: UiComponent[] = [];
+ selectedUiComponent: UiComponent | null = null;
+ newUiComponent: Partial = {};
+ showAddUiComponentForm = false;
+ uiComponentLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
+
+ // Component Properties
+ componentProperties: ComponentProperty[] = [];
+ selectedComponentProperty: ComponentProperty | null = null;
+ newComponentProperty: Partial = {};
+ showAddComponentPropertyForm = false;
+ componentPropertyLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
+
+ // Chart Templates
+ chartTemplates: ChartTemplate[] = [];
+ selectedChartTemplate: ChartTemplate | null = null;
+ newChartTemplate: Partial = {};
+ showAddChartTemplateForm = false;
+ chartTemplateLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
+
+ // Dynamic Fields
+ dynamicFields: DynamicField[] = [];
+ selectedDynamicField: DynamicField | null = null;
+ newDynamicField: Partial = {};
+ showAddDynamicFieldForm = false;
+ dynamicFieldLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
+
+ // Make ClrLoadingState available to template
+ readonly ClrLoadingState = ClrLoadingState;
+
+ // Error handling
+ errorMessage: string | null = null;
+ successMessage: string | null = null;
+
+ constructor(
+ private chartTypeService: ChartTypeService,
+ private uiComponentService: UiComponentService,
+ private componentPropertyService: ComponentPropertyService,
+ private chartTemplateService: ChartTemplateService,
+ private dynamicFieldService: DynamicFieldService
+ ) { }
+
+ ngOnInit(): void {
+ this.loadChartTypes();
+ }
+
+ // Show error message
+ private showError(message: string): void {
+ this.errorMessage = message;
+ setTimeout(() => {
+ this.errorMessage = null;
+ }, 5000);
+ }
+
+ // Show success message
+ private showSuccess(message: string): void {
+ this.successMessage = message;
+ setTimeout(() => {
+ this.successMessage = null;
+ }, 3000);
+ }
+
+ // Chart Type Methods
+ loadChartTypes(): void {
+ this.chartTypeLoadingState = ClrLoadingState.LOADING;
+ this.chartTypeService.getAllChartTypes().subscribe({
+ next: (data) => {
+ this.chartTypes = data;
+ this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error loading chart types:', error);
+ this.showError('Error loading chart types: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTypeLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ createChartType(): void {
+ if (!this.newChartType.name) {
+ this.showError('Chart type name is required');
+ return;
+ }
+
+ this.chartTypeLoadingState = ClrLoadingState.LOADING;
+ this.chartTypeService.createChartType(this.newChartType).subscribe({
+ next: (data) => {
+ this.chartTypes.push(data);
+ this.newChartType = {};
+ this.showAddChartTypeForm = false;
+ this.showSuccess('Chart type created successfully');
+ this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error creating chart type:', error);
+ this.showError('Error creating chart type: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTypeLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ updateChartType(): void {
+ if (!this.selectedChartType || !this.selectedChartType.name) {
+ this.showError('Chart type name is required');
+ return;
+ }
+
+ this.chartTypeLoadingState = ClrLoadingState.LOADING;
+ this.chartTypeService.updateChartType(this.selectedChartType.id, this.selectedChartType).subscribe({
+ next: (data) => {
+ const index = this.chartTypes.findIndex(ct => ct.id === data.id);
+ if (index !== -1) {
+ this.chartTypes[index] = data;
+ }
+ this.selectedChartType = null;
+ this.showSuccess('Chart type updated successfully');
+ this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error updating chart type:', error);
+ this.showError('Error updating chart type: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTypeLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ deleteChartType(id: number): void {
+ if (!confirm('Are you sure you want to delete this chart type? This will also delete all related UI components, templates, and fields.')) {
+ return;
+ }
+
+ this.chartTypeLoadingState = ClrLoadingState.LOADING;
+ this.chartTypeService.deleteChartType(id).subscribe({
+ next: () => {
+ this.chartTypes = this.chartTypes.filter(ct => ct.id !== id);
+ // Clear related data if the deleted chart type was selected
+ if (this.selectedChartType && this.selectedChartType.id === id) {
+ this.selectedChartType = null;
+ this.uiComponents = [];
+ this.chartTemplates = [];
+ this.dynamicFields = [];
+ }
+ this.showSuccess('Chart type deleted successfully');
+ this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error deleting chart type:', error);
+ this.showError('Error deleting chart type: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTypeLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ selectChartTypeForEdit(chartType: ChartType): void {
+ this.selectedChartType = { ...chartType };
+ }
+
+ // UI Component Methods
+ loadUiComponents(chartTypeId: number): void {
+ if (!chartTypeId) {
+ this.uiComponents = [];
+ return;
+ }
+
+ this.uiComponentLoadingState = ClrLoadingState.LOADING;
+ this.uiComponentService.getUiComponentsByChartType(chartTypeId).subscribe({
+ next: (data) => {
+ this.uiComponents = data;
+ this.uiComponentLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error loading UI components:', error);
+ this.showError('Error loading UI components: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.uiComponentLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ createUiComponent(): void {
+ if (!this.selectedChartType) {
+ this.showError('Please select a chart type first');
+ return;
+ }
+
+ if (!this.newUiComponent.componentName) {
+ this.showError('Component name is required');
+ return;
+ }
+
+ this.uiComponentLoadingState = ClrLoadingState.LOADING;
+
+ // Create a complete chartType object with only the ID
+ const chartTypeWithId = {
+ id: this.selectedChartType.id,
+ name: '',
+ displayName: '',
+ description: '',
+ isActive: true,
+ createdAt: '',
+ updatedAt: ''
+ };
+
+ const uiComponentData = {
+ ...this.newUiComponent,
+ chartType: chartTypeWithId
+ };
+
+ this.uiComponentService.createUiComponent(uiComponentData).subscribe({
+ next: (data) => {
+ this.uiComponents.push(data);
+ this.newUiComponent = {};
+ this.showAddUiComponentForm = false;
+ this.showSuccess('UI component created successfully');
+ this.uiComponentLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error creating UI component:', error);
+ this.showError('Error creating UI component: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.uiComponentLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ updateUiComponent(): void {
+ if (!this.selectedUiComponent || !this.selectedUiComponent.componentName) {
+ this.showError('Component name is required');
+ return;
+ }
+
+ this.uiComponentLoadingState = ClrLoadingState.LOADING;
+ this.uiComponentService.updateUiComponent(this.selectedUiComponent.id, this.selectedUiComponent).subscribe({
+ next: (data) => {
+ const index = this.uiComponents.findIndex(uc => uc.id === data.id);
+ if (index !== -1) {
+ this.uiComponents[index] = data;
+ }
+ this.selectedUiComponent = null;
+ this.showSuccess('UI component updated successfully');
+ this.uiComponentLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error updating UI component:', error);
+ this.showError('Error updating UI component: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.uiComponentLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ deleteUiComponent(id: number): void {
+ if (!confirm('Are you sure you want to delete this UI component?')) {
+ return;
+ }
+
+ this.uiComponentLoadingState = ClrLoadingState.LOADING;
+ this.uiComponentService.deleteUiComponent(id).subscribe({
+ next: () => {
+ this.uiComponents = this.uiComponents.filter(uc => uc.id !== id);
+ this.showSuccess('UI component deleted successfully');
+ this.uiComponentLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error deleting UI component:', error);
+ this.showError('Error deleting UI component: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.uiComponentLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ selectUiComponentForEdit(uiComponent: UiComponent): void {
+ this.selectedUiComponent = { ...uiComponent };
+ }
+
+ // Component Property Methods
+ loadComponentProperties(componentId: number): void {
+ if (!componentId) {
+ this.componentProperties = [];
+ return;
+ }
+
+ this.componentPropertyLoadingState = ClrLoadingState.LOADING;
+ this.componentPropertyService.getComponentPropertiesByComponent(componentId).subscribe({
+ next: (data) => {
+ this.componentProperties = data;
+ this.componentPropertyLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error loading component properties:', error);
+ this.showError('Error loading component properties: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.componentPropertyLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ createComponentProperty(): void {
+ if (!this.selectedUiComponent) {
+ this.showError('Please select a UI component first');
+ return;
+ }
+
+ if (!this.newComponentProperty.propertyName) {
+ this.showError('Property name is required');
+ return;
+ }
+
+ this.componentPropertyLoadingState = ClrLoadingState.LOADING;
+
+ // Create a complete component object with only the ID
+ const componentWithId = {
+ id: this.selectedUiComponent.id,
+ chartType: { id: 0, name: '', displayName: '', description: '', isActive: true, createdAt: '', updatedAt: '' },
+ componentName: '',
+ componentType: '',
+ displayLabel: '',
+ placeholder: '',
+ isRequired: false,
+ sortOrder: 0,
+ createdAt: '',
+ updatedAt: ''
+ };
+
+ const componentPropertyData = {
+ ...this.newComponentProperty,
+ component: componentWithId
+ };
+
+ this.componentPropertyService.createComponentProperty(componentPropertyData).subscribe({
+ next: (data) => {
+ this.componentProperties.push(data);
+ this.newComponentProperty = {};
+ this.showAddComponentPropertyForm = false;
+ this.showSuccess('Component property created successfully');
+ this.componentPropertyLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error creating component property:', error);
+ this.showError('Error creating component property: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.componentPropertyLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ updateComponentProperty(): void {
+ if (!this.selectedComponentProperty || !this.selectedComponentProperty.propertyName) {
+ this.showError('Property name is required');
+ return;
+ }
+
+ this.componentPropertyLoadingState = ClrLoadingState.LOADING;
+ this.componentPropertyService.updateComponentProperty(this.selectedComponentProperty.id, this.selectedComponentProperty).subscribe({
+ next: (data) => {
+ const index = this.componentProperties.findIndex(cp => cp.id === data.id);
+ if (index !== -1) {
+ this.componentProperties[index] = data;
+ }
+ this.selectedComponentProperty = null;
+ this.showSuccess('Component property updated successfully');
+ this.componentPropertyLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error updating component property:', error);
+ this.showError('Error updating component property: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.componentPropertyLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ deleteComponentProperty(id: number): void {
+ if (!confirm('Are you sure you want to delete this component property?')) {
+ return;
+ }
+
+ this.componentPropertyLoadingState = ClrLoadingState.LOADING;
+ this.componentPropertyService.deleteComponentProperty(id).subscribe({
+ next: () => {
+ this.componentProperties = this.componentProperties.filter(cp => cp.id !== id);
+ this.showSuccess('Component property deleted successfully');
+ this.componentPropertyLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error deleting component property:', error);
+ this.showError('Error deleting component property: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.componentPropertyLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ selectComponentPropertyForEdit(componentProperty: ComponentProperty): void {
+ this.selectedComponentProperty = { ...componentProperty };
+ }
+
+ // Chart Template Methods
+ loadChartTemplates(chartTypeId: number): void {
+ if (!chartTypeId) {
+ this.chartTemplates = [];
+ return;
+ }
+
+ this.chartTemplateLoadingState = ClrLoadingState.LOADING;
+ this.chartTemplateService.getChartTemplatesByChartType(chartTypeId).subscribe({
+ next: (data) => {
+ this.chartTemplates = data;
+ this.chartTemplateLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error loading chart templates:', error);
+ this.showError('Error loading chart templates: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTemplateLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ createChartTemplate(): void {
+ if (!this.selectedChartType) {
+ this.showError('Please select a chart type first');
+ return;
+ }
+
+ if (!this.newChartTemplate.templateName) {
+ this.showError('Template name is required');
+ return;
+ }
+
+ this.chartTemplateLoadingState = ClrLoadingState.LOADING;
+
+ // Create a complete chartType object with only the ID
+ const chartTypeWithId = {
+ id: this.selectedChartType.id,
+ name: '',
+ displayName: '',
+ description: '',
+ isActive: true,
+ createdAt: '',
+ updatedAt: ''
+ };
+
+ const chartTemplateData = {
+ ...this.newChartTemplate,
+ chartType: chartTypeWithId
+ };
+
+ this.chartTemplateService.createChartTemplate(chartTemplateData).subscribe({
+ next: (data) => {
+ this.chartTemplates.push(data);
+ this.newChartTemplate = {};
+ this.showAddChartTemplateForm = false;
+ this.showSuccess('Chart template created successfully');
+ this.chartTemplateLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error creating chart template:', error);
+ this.showError('Error creating chart template: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTemplateLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ updateChartTemplate(): void {
+ if (!this.selectedChartTemplate || !this.selectedChartTemplate.templateName) {
+ this.showError('Template name is required');
+ return;
+ }
+
+ this.chartTemplateLoadingState = ClrLoadingState.LOADING;
+ this.chartTemplateService.updateChartTemplate(this.selectedChartTemplate.id, this.selectedChartTemplate).subscribe({
+ next: (data) => {
+ const index = this.chartTemplates.findIndex(ct => ct.id === data.id);
+ if (index !== -1) {
+ this.chartTemplates[index] = data;
+ }
+ this.selectedChartTemplate = null;
+ this.showSuccess('Chart template updated successfully');
+ this.chartTemplateLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error updating chart template:', error);
+ this.showError('Error updating chart template: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTemplateLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ deleteChartTemplate(id: number): void {
+ if (!confirm('Are you sure you want to delete this chart template?')) {
+ return;
+ }
+
+ this.chartTemplateLoadingState = ClrLoadingState.LOADING;
+ this.chartTemplateService.deleteChartTemplate(id).subscribe({
+ next: () => {
+ this.chartTemplates = this.chartTemplates.filter(ct => ct.id !== id);
+ this.showSuccess('Chart template deleted successfully');
+ this.chartTemplateLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error deleting chart template:', error);
+ this.showError('Error deleting chart template: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.chartTemplateLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ selectChartTemplateForEdit(chartTemplate: ChartTemplate): void {
+ this.selectedChartTemplate = { ...chartTemplate };
+ }
+
+ // Dynamic Field Methods
+ loadDynamicFields(chartTypeId: number): void {
+ if (!chartTypeId) {
+ this.dynamicFields = [];
+ return;
+ }
+
+ this.dynamicFieldLoadingState = ClrLoadingState.LOADING;
+ this.dynamicFieldService.getDynamicFieldsByChartType(chartTypeId).subscribe({
+ next: (data) => {
+ this.dynamicFields = data;
+ this.dynamicFieldLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error loading dynamic fields:', error);
+ this.showError('Error loading dynamic fields: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.dynamicFieldLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ createDynamicField(): void {
+ if (!this.selectedChartType) {
+ this.showError('Please select a chart type first');
+ return;
+ }
+
+ if (!this.newDynamicField.fieldName) {
+ this.showError('Field name is required');
+ return;
+ }
+
+ this.dynamicFieldLoadingState = ClrLoadingState.LOADING;
+
+ // Create a complete chartType object with only the ID
+ const chartTypeWithId = {
+ id: this.selectedChartType.id,
+ name: '',
+ displayName: '',
+ description: '',
+ isActive: true,
+ createdAt: '',
+ updatedAt: ''
+ };
+
+ const dynamicFieldData = {
+ ...this.newDynamicField,
+ chartType: chartTypeWithId
+ };
+
+ this.dynamicFieldService.createDynamicField(dynamicFieldData).subscribe({
+ next: (data) => {
+ this.dynamicFields.push(data);
+ this.newDynamicField = {};
+ this.showAddDynamicFieldForm = false;
+ this.showSuccess('Dynamic field created successfully');
+ this.dynamicFieldLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error creating dynamic field:', error);
+ this.showError('Error creating dynamic field: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.dynamicFieldLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ updateDynamicField(): void {
+ if (!this.selectedDynamicField || !this.selectedDynamicField.fieldName) {
+ this.showError('Field name is required');
+ return;
+ }
+
+ this.dynamicFieldLoadingState = ClrLoadingState.LOADING;
+ this.dynamicFieldService.updateDynamicField(this.selectedDynamicField.id, this.selectedDynamicField).subscribe({
+ next: (data) => {
+ const index = this.dynamicFields.findIndex(df => df.id === data.id);
+ if (index !== -1) {
+ this.dynamicFields[index] = data;
+ }
+ this.selectedDynamicField = null;
+ this.showSuccess('Dynamic field updated successfully');
+ this.dynamicFieldLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error updating dynamic field:', error);
+ this.showError('Error updating dynamic field: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.dynamicFieldLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ deleteDynamicField(id: number): void {
+ if (!confirm('Are you sure you want to delete this dynamic field?')) {
+ return;
+ }
+
+ this.dynamicFieldLoadingState = ClrLoadingState.LOADING;
+ this.dynamicFieldService.deleteDynamicField(id).subscribe({
+ next: () => {
+ this.dynamicFields = this.dynamicFields.filter(df => df.id !== id);
+ this.showSuccess('Dynamic field deleted successfully');
+ this.dynamicFieldLoadingState = ClrLoadingState.SUCCESS;
+ },
+ error: (error) => {
+ console.error('Error deleting dynamic field:', error);
+ this.showError('Error deleting dynamic field: ' + (error.error?.message || error.message || 'Unknown error'));
+ this.dynamicFieldLoadingState = ClrLoadingState.ERROR;
+ }
+ });
+ }
+
+ selectDynamicFieldForEdit(dynamicField: DynamicField): void {
+ this.selectedDynamicField = { ...dynamicField };
+ }
+
+ // Helper methods
+ onChartTypeSelect(chartType: ChartType): void {
+ this.selectedChartType = chartType;
+ this.loadUiComponents(chartType.id);
+ this.loadChartTemplates(chartType.id);
+ this.loadDynamicFields(chartType.id);
+ }
+
+ resetForms(): void {
+ this.newChartType = {};
+ this.newUiComponent = {};
+ this.newComponentProperty = {};
+ this.newChartTemplate = {};
+ this.newDynamicField = {};
+ this.showAddChartTypeForm = false;
+ this.showAddUiComponentForm = false;
+ this.showAddComponentPropertyForm = false;
+ this.showAddChartTemplateForm = false;
+ this.showAddDynamicFieldForm = false;
+ this.selectedChartType = null;
+ this.selectedUiComponent = null;
+ this.selectedComponentProperty = null;
+ this.selectedChartTemplate = null;
+ this.selectedDynamicField = null;
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-template.service.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-template.service.ts
new file mode 100644
index 0000000..2ffc12c
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/chart-template.service.ts
@@ -0,0 +1,43 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ApiRequestService } from 'src/app/services/api/api-request.service';
+import { ChartTemplate } from './chart-config-manager.component';
+
+@Injectable({
+ providedIn: 'root'
+}
+)
+export class ChartTemplateService {
+ private chartTemplatesUrl = 'chart-templates';
+
+ constructor(private apiRequest: ApiRequestService) { }
+
+ // Get all chart templates for a chart type
+ getChartTemplatesByChartType(chartTypeId: number): Observable {
+ const url = `${this.chartTemplatesUrl}/chart-type/${chartTypeId}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Get chart template by ID
+ getChartTemplateById(id: number): Observable {
+ const url = `${this.chartTemplatesUrl}/${id}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Create new chart template
+ createChartTemplate(chartTemplate: Partial): Observable {
+ return this.apiRequest.post(this.chartTemplatesUrl, chartTemplate);
+ }
+
+ // Update chart template
+ updateChartTemplate(id: number, chartTemplate: ChartTemplate): Observable {
+ const url = `${this.chartTemplatesUrl}/${id}`;
+ return this.apiRequest.put(url, chartTemplate);
+ }
+
+ // Delete chart template
+ deleteChartTemplate(id: number): Observable {
+ const url = `${this.chartTemplatesUrl}/${id}`;
+ return this.apiRequest.delete(url);
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/component-property.service.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/component-property.service.ts
new file mode 100644
index 0000000..5904618
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/component-property.service.ts
@@ -0,0 +1,42 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ApiRequestService } from 'src/app/services/api/api-request.service';
+import { ComponentProperty } from './chart-config-manager.component';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ComponentPropertyService {
+ private componentPropertiesUrl = 'component-properties';
+
+ constructor(private apiRequest: ApiRequestService) { }
+
+ // Get all component properties for a component
+ getComponentPropertiesByComponent(componentId: number): Observable {
+ const url = `${this.componentPropertiesUrl}/component/${componentId}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Get component property by ID
+ getComponentPropertyById(id: number): Observable {
+ const url = `${this.componentPropertiesUrl}/${id}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Create new component property
+ createComponentProperty(componentProperty: Partial): Observable {
+ return this.apiRequest.post(this.componentPropertiesUrl, componentProperty);
+ }
+
+ // Update component property
+ updateComponentProperty(id: number, componentProperty: ComponentProperty): Observable {
+ const url = `${this.componentPropertiesUrl}/${id}`;
+ return this.apiRequest.put(url, componentProperty);
+ }
+
+ // Delete component property
+ deleteComponentProperty(id: number): Observable {
+ const url = `${this.componentPropertiesUrl}/${id}`;
+ return this.apiRequest.delete(url);
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/dynamic-field.service.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/dynamic-field.service.ts
new file mode 100644
index 0000000..ae6cbfe
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/dynamic-field.service.ts
@@ -0,0 +1,42 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ApiRequestService } from 'src/app/services/api/api-request.service';
+import { DynamicField } from './chart-config-manager.component';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class DynamicFieldService {
+ private dynamicFieldsUrl = 'dynamic-fields';
+
+ constructor(private apiRequest: ApiRequestService) { }
+
+ // Get all dynamic fields for a chart type
+ getDynamicFieldsByChartType(chartTypeId: number): Observable {
+ const url = `${this.dynamicFieldsUrl}/chart-type/${chartTypeId}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Get dynamic field by ID
+ getDynamicFieldById(id: number): Observable {
+ const url = `${this.dynamicFieldsUrl}/${id}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Create new dynamic field
+ createDynamicField(dynamicField: Partial): Observable {
+ return this.apiRequest.post(this.dynamicFieldsUrl, dynamicField);
+ }
+
+ // Update dynamic field
+ updateDynamicField(id: number, dynamicField: DynamicField): Observable {
+ const url = `${this.dynamicFieldsUrl}/${id}`;
+ return this.apiRequest.put(url, dynamicField);
+ }
+
+ // Delete dynamic field
+ deleteDynamicField(id: number): Observable {
+ const url = `${this.dynamicFieldsUrl}/${id}`;
+ return this.apiRequest.delete(url);
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-template-form.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/chart-type-form.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/component-property-form.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/dynamic-field-form.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/forms/ui-component-form.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/ui-component.service.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/ui-component.service.ts
new file mode 100644
index 0000000..c804c14
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-config/ui-component.service.ts
@@ -0,0 +1,42 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { ApiRequestService } from 'src/app/services/api/api-request.service';
+import { UiComponent } from './chart-config-manager.component';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class UiComponentService {
+ private uiComponentsUrl = 'ui-components';
+
+ constructor(private apiRequest: ApiRequestService) { }
+
+ // Get all UI components for a chart type
+ getUiComponentsByChartType(chartTypeId: number): Observable {
+ const url = `${this.uiComponentsUrl}/chart-type/${chartTypeId}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Get UI component by ID
+ getUiComponentById(id: number): Observable {
+ const url = `${this.uiComponentsUrl}/${id}`;
+ return this.apiRequest.get(url);
+ }
+
+ // Create new UI component
+ createUiComponent(uiComponent: Partial): Observable {
+ return this.apiRequest.post(this.uiComponentsUrl, uiComponent);
+ }
+
+ // Update UI component
+ updateUiComponent(id: number, uiComponent: UiComponent): Observable {
+ const url = `${this.uiComponentsUrl}/${id}`;
+ return this.apiRequest.put(url, uiComponent);
+ }
+
+ // Delete UI component
+ deleteUiComponent(id: number): Observable {
+ const url = `${this.uiComponentsUrl}/${id}`;
+ return this.apiRequest.delete(url);
+ }
+}
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.html
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/chart-config-modal.component.ts
new file mode 100644
index 0000000..e69de29
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
index 1664180..3d0ac44 100644
--- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
@@ -30,6 +30,8 @@ import { CompactFilterComponent } from '../common-filter';
import { FilterService } from '../common-filter/filter.service';
// Add the UnifiedChartComponent import
import { UnifiedChartComponent } from '../gadgets/unified-chart';
+// Add the ChartConfigModalComponent import
+import { ChartConfigModalComponent } from './chart-config-modal.component';
function isNullArray(arr) {
return !Array.isArray(arr) || arr.length === 0;