diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.html new file mode 100644 index 0000000..6ede91b --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.html @@ -0,0 +1,222 @@ +
+
+

+ + Dynamic Fields for {{ chartType?.name || 'Chart Type' }} +

+
+ + +
+ +
+ {{ errorMessage }} +
+
+ +
+ +
+ {{ successMessage }} +
+
+ + +
+
+

Add New Dynamic Field

+
+
+
+ + + + Enter a unique name for the dynamic field (e.g., "chart-title", "x-axis-label") + + + + + + User-friendly label shown in the configuration form + + + + + + Type of the field (e.g., "string", "number", "boolean") + + + + + + JSON options for the field (for select fields, etc.) + + + + + + Order in which fields appear in the form + + + + + + + + + Mark as required if this field must be filled + + + + + + + + + Uncheck to hide this field in the configuration form + + +
+ + +
+
+
+
+ + +
+
+
+
+

Dynamic Fields

+
+
+ +
+
+
+ +
+ + Field Name + Field Label + Field Type + Required + Visible + Sort Order + Actions + + + {{dynamicField.fieldName}} + {{dynamicField.fieldLabel}} + {{dynamicField.fieldType}} + + + {{dynamicField.isRequired ? 'Yes' : 'No'}} + + + + + {{dynamicField.showInUi ? 'Yes' : 'No'}} + + + {{dynamicField.sortOrder}} + + + + + + + + {{dynamicFields.length}} dynamic field(s) + + +
+
+ + +
+
+

Edit Dynamic Field

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+

About Dynamic Fields

+

Dynamic fields define the configurable parameters for a chart type. Each field represents:

+ +

Dynamic fields allow you to create flexible chart configurations that can be customized per instance.

+
+
\ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.scss new file mode 100644 index 0000000..16e28cf --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.scss @@ -0,0 +1,128 @@ +.chart-type-fields-page { + padding: 20px; + max-width: 1200px; + margin: 0 auto; + + .header { + margin-bottom: 20px; + display: flex; + align-items: center; + + h2 { + color: #0079b8; + font-weight: 300; + display: flex; + align-items: center; + gap: 10px; + } + + .back-button { + padding: 0; + cds-icon { + width: 24px; + height: 24px; + } + } + } + + .card { + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + .card-block { + padding: 20px; + } + + .card-header { + h3 { + margin: 0; + color: #0079b8; + } + } + } + + .form-actions { + margin-top: 20px; + display: flex; + gap: 10px; + } + + .label { + padding: 4px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: bold; + + &.label-success { + background-color: #3d9970; + color: white; + } + + &.label-danger { + background-color: #d32f2f; + color: white; + } + } + + clr-datagrid { + margin-top: 10px; + + clr-dg-cell { + &:first-child { + font-weight: 500; + } + } + } + + .btn-icon { + margin-right: 5px; + } + + .info-section { + background-color: #f6f6f6; + border-left: 4px solid #0079b8; + padding: 15px; + border-radius: 4px; + + h4 { + margin-top: 0; + color: #0079b8; + } + + ul { + padding-left: 20px; + + li { + margin-bottom: 8px; + } + } + + p { + margin: 10px 0; + } + } + + @media (max-width: 768px) { + padding: 10px; + + .form-actions { + flex-direction: column; + + button { + width: 100%; + margin-bottom: 10px; + } + } + + .card-header { + .clr-row { + flex-direction: column; + + .clr-col { + text-align: left !important; + margin-bottom: 10px; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.ts new file mode 100644 index 0000000..03258b8 --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-fields.component.ts @@ -0,0 +1,180 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ClrLoadingState } from '@clr/angular'; +import { ChartType, ChartTypeService } from './chart-type.service'; +import { DynamicField } from '../chart-config/chart-config-manager.component'; +import { DynamicFieldService } from '../chart-config/dynamic-field.service'; + +@Component({ + selector: 'app-chart-type-fields', + templateUrl: './chart-type-fields.component.html', + styleUrls: ['./chart-type-fields.component.scss'] +}) +export class ChartTypeFieldsComponent implements OnInit { + chartType: ChartType | null = null; + dynamicFields: DynamicField[] = []; + newDynamicField: Partial = { + isRequired: false, + showInUi: true + }; + selectedDynamicField: DynamicField | null = null; + showAddForm = false; + + loadingState: ClrLoadingState = ClrLoadingState.DEFAULT; + errorMessage: string | null = null; + successMessage: string | null = null; + + // Make ClrLoadingState available to template + readonly ClrLoadingState = ClrLoadingState; + + constructor( + private chartTypeService: ChartTypeService, + private dynamicFieldService: DynamicFieldService, + private route: ActivatedRoute, + private router: Router + ) { } + + ngOnInit(): void { + const chartTypeId = Number(this.route.snapshot.paramMap.get('id')); + if (chartTypeId) { + this.loadChartType(chartTypeId); + this.loadDynamicFields(chartTypeId); + } else { + this.showError('Invalid chart type ID'); + } + } + + // 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); + } + + loadChartType(id: number): void { + this.chartTypeService.getChartTypeById(id).subscribe({ + next: (data) => { + this.chartType = data; + }, + error: (error) => { + console.error('Error loading chart type:', error); + this.showError('Error loading chart type: ' + (error.error?.message || error.message || 'Unknown error')); + } + }); + } + + loadDynamicFields(chartTypeId: number): void { + this.loadingState = ClrLoadingState.LOADING; + this.dynamicFieldService.getDynamicFieldsByChartType(chartTypeId).subscribe({ + next: (data) => { + this.dynamicFields = data; + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + createDynamicField(): void { + if (!this.chartType || !this.newDynamicField.fieldName) { + this.showError('Field name is required'); + return; + } + + // Create a copy without the chartType property + const fieldData: Partial = { + fieldName: this.newDynamicField.fieldName, + fieldLabel: this.newDynamicField.fieldLabel, + fieldType: this.newDynamicField.fieldType, + fieldOptions: this.newDynamicField.fieldOptions, + isRequired: this.newDynamicField.isRequired, + showInUi: this.newDynamicField.showInUi, + sortOrder: this.newDynamicField.sortOrder + }; + + this.loadingState = ClrLoadingState.LOADING; + this.dynamicFieldService.createDynamicField(fieldData).subscribe({ + next: (data) => { + this.dynamicFields.push(data); + this.newDynamicField = { isRequired: false, showInUi: true }; + this.showAddForm = false; + this.showSuccess('Dynamic field created successfully'); + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + updateDynamicField(): void { + if (!this.selectedDynamicField || !this.selectedDynamicField.fieldName) { + this.showError('Field name is required'); + return; + } + + this.loadingState = 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.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + deleteDynamicField(id: number): void { + if (!confirm('Are you sure you want to delete this dynamic field?')) { + return; + } + + this.loadingState = ClrLoadingState.LOADING; + this.dynamicFieldService.deleteDynamicField(id).subscribe({ + next: () => { + this.dynamicFields = this.dynamicFields.filter(df => df.id !== id); + this.showSuccess('Dynamic field deleted successfully'); + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + selectDynamicFieldForEdit(dynamicField: DynamicField): void { + this.selectedDynamicField = { ...dynamicField }; + } + + goBack(): void { + if (this.chartType) { + this.router.navigate(['/cns-portal/dashboardbuilder/chart-types/edit', this.chartType.id]); + } else { + this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']); + } + } +} \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-manager.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-manager.component.html index 406c963..50e56aa 100644 --- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-manager.component.html +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-manager.component.html @@ -54,8 +54,8 @@ {{chartType.isActive ? 'Active' : 'Inactive'}} - {{chartType.createdAt | date:'short'}} - {{chartType.updatedAt | date:'short'}} + {{chartType.createdAt ? (chartType.createdAt | date:'short') : 'N/A'}} + {{chartType.updatedAt ? (chartType.updatedAt | date:'short') : 'N/A'}} + Chart Templates for {{ chartType?.name || 'Chart Type' }} + + + + +
+ +
+ {{ errorMessage }} +
+
+ +
+ +
+ {{ successMessage }} +
+
+ + +
+
+

Add New Chart Template

+
+
+
+ + + + Enter a unique name for the chart template + + + + + + HTML structure for rendering the chart + + + + + + CSS styling for the chart template + + + + + + + + + Mark as default template for this chart type + + +
+ + +
+
+
+
+ + +
+
+
+
+

Chart Templates

+
+
+ +
+
+
+ +
+ + Template Name + Default + Created At + Updated At + Actions + + + {{chartTemplate.templateName}} + + + {{chartTemplate.isDefault ? 'Yes' : 'No'}} + + + {{chartTemplate.createdAt | date:'short'}} + {{chartTemplate.updatedAt | date:'short'}} + + + + + + + + {{chartTemplates.length}} chart template(s) + + +
+
+ + +
+
+

Edit Chart Template

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+
+
+ +
+

About Chart Templates

+

Chart templates define how a chart of this type is rendered. Each template includes:

+
    +
  • HTML structure that defines the chart layout
  • +
  • CSS styling that controls the appearance
  • +
  • A default flag to indicate the primary template
  • +
+

Templates allow you to have multiple visual representations for the same chart type.

+
+ \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.scss new file mode 100644 index 0000000..53c34d7 --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.scss @@ -0,0 +1,128 @@ +.chart-type-templates-page { + padding: 20px; + max-width: 1200px; + margin: 0 auto; + + .header { + margin-bottom: 20px; + display: flex; + align-items: center; + + h2 { + color: #0079b8; + font-weight: 300; + display: flex; + align-items: center; + gap: 10px; + } + + .back-button { + padding: 0; + cds-icon { + width: 24px; + height: 24px; + } + } + } + + .card { + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + .card-block { + padding: 20px; + } + + .card-header { + h3 { + margin: 0; + color: #0079b8; + } + } + } + + .form-actions { + margin-top: 20px; + display: flex; + gap: 10px; + } + + .label { + padding: 4px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: bold; + + &.label-success { + background-color: #3d9970; + color: white; + } + + &.label-danger { + background-color: #d32f2f; + color: white; + } + } + + clr-datagrid { + margin-top: 10px; + + clr-dg-cell { + &:first-child { + font-weight: 500; + } + } + } + + .btn-icon { + margin-right: 5px; + } + + .info-section { + background-color: #f6f6f6; + border-left: 4px solid #0079b8; + padding: 15px; + border-radius: 4px; + + h4 { + margin-top: 0; + color: #0079b8; + } + + ul { + padding-left: 20px; + + li { + margin-bottom: 8px; + } + } + + p { + margin: 10px 0; + } + } + + @media (max-width: 768px) { + padding: 10px; + + .form-actions { + flex-direction: column; + + button { + width: 100%; + margin-bottom: 10px; + } + } + + .card-header { + .clr-row { + flex-direction: column; + + .clr-col { + text-align: left !important; + margin-bottom: 10px; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.ts new file mode 100644 index 0000000..de8ad0c --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-templates.component.ts @@ -0,0 +1,176 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ClrLoadingState } from '@clr/angular'; +import { ChartType, ChartTypeService } from './chart-type.service'; +import { ChartTemplateService } from '../chart-config/chart-template.service'; +import { ChartTemplate } from '../chart-config/chart-config-manager.component'; + +@Component({ + selector: 'app-chart-type-templates', + templateUrl: './chart-type-templates.component.html', + styleUrls: ['./chart-type-templates.component.scss'] +}) +export class ChartTypeTemplatesComponent implements OnInit { + chartType: ChartType | null = null; + chartTemplates: ChartTemplate[] = []; + newChartTemplate: Partial = { + isDefault: false + }; + selectedChartTemplate: ChartTemplate | null = null; + showAddForm = false; + + loadingState: ClrLoadingState = ClrLoadingState.DEFAULT; + errorMessage: string | null = null; + successMessage: string | null = null; + + // Make ClrLoadingState available to template + readonly ClrLoadingState = ClrLoadingState; + + constructor( + private chartTypeService: ChartTypeService, + private chartTemplateService: ChartTemplateService, + private route: ActivatedRoute, + private router: Router + ) { } + + ngOnInit(): void { + const chartTypeId = Number(this.route.snapshot.paramMap.get('id')); + if (chartTypeId) { + this.loadChartType(chartTypeId); + this.loadChartTemplates(chartTypeId); + } else { + this.showError('Invalid chart type ID'); + } + } + + // 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); + } + + loadChartType(id: number): void { + this.chartTypeService.getChartTypeById(id).subscribe({ + next: (data) => { + this.chartType = data; + }, + error: (error) => { + console.error('Error loading chart type:', error); + this.showError('Error loading chart type: ' + (error.error?.message || error.message || 'Unknown error')); + } + }); + } + + loadChartTemplates(chartTypeId: number): void { + this.loadingState = ClrLoadingState.LOADING; + this.chartTemplateService.getChartTemplatesByChartType(chartTypeId).subscribe({ + next: (data) => { + this.chartTemplates = data; + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + createChartTemplate(): void { + if (!this.chartType || !this.newChartTemplate.templateName) { + this.showError('Template name is required'); + return; + } + + // Create a copy without the chartType property + const templateData: Partial = { + templateName: this.newChartTemplate.templateName, + templateHtml: this.newChartTemplate.templateHtml, + templateCss: this.newChartTemplate.templateCss, + isDefault: this.newChartTemplate.isDefault + }; + + this.loadingState = ClrLoadingState.LOADING; + this.chartTemplateService.createChartTemplate(templateData).subscribe({ + next: (data) => { + this.chartTemplates.push(data); + this.newChartTemplate = { isDefault: false }; + this.showAddForm = false; + this.showSuccess('Chart template created successfully'); + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + updateChartTemplate(): void { + if (!this.selectedChartTemplate || !this.selectedChartTemplate.templateName) { + this.showError('Template name is required'); + return; + } + + this.loadingState = 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.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + deleteChartTemplate(id: number): void { + if (!confirm('Are you sure you want to delete this chart template?')) { + return; + } + + this.loadingState = ClrLoadingState.LOADING; + this.chartTemplateService.deleteChartTemplate(id).subscribe({ + next: () => { + this.chartTemplates = this.chartTemplates.filter(ct => ct.id !== id); + this.showSuccess('Chart template deleted successfully'); + this.loadingState = 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.loadingState = ClrLoadingState.ERROR; + } + }); + } + + selectChartTemplateForEdit(chartTemplate: ChartTemplate): void { + this.selectedChartTemplate = { ...chartTemplate }; + } + + goBack(): void { + if (this.chartType) { + this.router.navigate(['/cns-portal/dashboardbuilder/chart-types/edit', this.chartType.id]); + } else { + this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']); + } + } +} \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.scss b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.scss new file mode 100644 index 0000000..75317d7 --- /dev/null +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.scss @@ -0,0 +1,128 @@ +.chart-type-ui-components-page { + padding: 20px; + max-width: 1200px; + margin: 0 auto; + + .header { + margin-bottom: 20px; + display: flex; + align-items: center; + + h2 { + color: #0079b8; + font-weight: 300; + display: flex; + align-items: center; + gap: 10px; + } + + .back-button { + padding: 0; + cds-icon { + width: 24px; + height: 24px; + } + } + } + + .card { + margin-bottom: 20px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + .card-block { + padding: 20px; + } + + .card-header { + h3 { + margin: 0; + color: #0079b8; + } + } + } + + .form-actions { + margin-top: 20px; + display: flex; + gap: 10px; + } + + .label { + padding: 4px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: bold; + + &.label-success { + background-color: #3d9970; + color: white; + } + + &.label-danger { + background-color: #d32f2f; + color: white; + } + } + + clr-datagrid { + margin-top: 10px; + + clr-dg-cell { + &:first-child { + font-weight: 500; + } + } + } + + .btn-icon { + margin-right: 5px; + } + + .info-section { + background-color: #f6f6f6; + border-left: 4px solid #0079b8; + padding: 15px; + border-radius: 4px; + + h4 { + margin-top: 0; + color: #0079b8; + } + + ul { + padding-left: 20px; + + li { + margin-bottom: 8px; + } + } + + p { + margin: 10px 0; + } + } + + @media (max-width: 768px) { + padding: 10px; + + .form-actions { + flex-direction: column; + + button { + width: 100%; + margin-bottom: 10px; + } + } + + .card-header { + .clr-row { + flex-direction: column; + + .clr-col { + text-align: left !important; + margin-bottom: 10px; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.ts index 562508a..f15f885 100644 --- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.ts +++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/chart-type-manager/chart-type-ui-components.component.ts @@ -2,7 +2,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { ClrLoadingState } from '@clr/angular'; import { ChartType, ChartTypeService } from './chart-type.service'; -import { UiComponent, UiComponentService } from '../../chart-config/ui-component.service'; +import { UiComponentService } from '../chart-config/ui-component.service'; +import { UiComponent } from '../chart-config/chart-config-manager.component'; @Component({ selector: 'app-chart-type-ui-components', @@ -91,12 +92,24 @@ export class ChartTypeUiComponentsComponent implements OnInit { return; } - const componentData = { - ...this.newUiComponent, - chartType: { id: this.chartType.id } + this.loadingState = ClrLoadingState.LOADING; + + // Create a complete chartType object with only the ID (following the pattern in chart-config-manager) + const chartTypeWithId = { + id: this.chartType.id, + name: '', + displayName: '', + description: '', + isActive: true, + createdAt: '', + updatedAt: '' }; - this.loadingState = ClrLoadingState.LOADING; + const componentData = { + ...this.newUiComponent, + chartType: chartTypeWithId + }; + this.uiComponentService.createUiComponent(componentData).subscribe({ next: (data) => { this.uiComponents.push(data);