config
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<div class="dg-wrapper">
|
<div class="dg-wrapper">
|
||||||
<div class="clr-row">
|
<div class="clr-row">
|
||||||
<div class="clr-col-8">
|
<div class="clr-col-8">x
|
||||||
<h3>{{ 'Dashboard_builder' | translate }}</h3>
|
<h3>{{ 'Dashboard_builder' | translate }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col-4" style="text-align: right;">
|
<div class="clr-col-4" style="text-align: right;">
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
<button id="add" class="btn btn-primary" (click)="gotorunner()">
|
<button id="add" class="btn btn-primary" (click)="gotorunner()">
|
||||||
<clr-icon shape="grid-view"></clr-icon>{{ 'Dashboard_runner' | translate }}
|
<clr-icon shape="grid-view"></clr-icon>{{ 'Dashboard_runner' | translate }}
|
||||||
</button>
|
</button>
|
||||||
|
<!-- Add Chart Config button -->
|
||||||
|
<button class="btn btn-primary" (click)="openChartConfig()">
|
||||||
|
<clr-icon shape="cog"></clr-icon> Chart Config
|
||||||
|
</button>
|
||||||
<button class="btn btn-outline" (click)="onExport()">
|
<button class="btn btn-outline" (click)="onExport()">
|
||||||
<clr-icon shape="export"></clr-icon> {{ 'EXPORT_XLSX' | translate }}
|
<clr-icon shape="export"></clr-icon> {{ 'EXPORT_XLSX' | translate }}
|
||||||
</button>
|
</button>
|
||||||
@@ -27,8 +31,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<clr-datagrid [clrDgLoading]="loading">
|
<clr-datagrid [clrDgLoading]="loading">
|
||||||
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{ 'Loading' | translate }} ...... </clr-spinner></ng-template>
|
<clr-dg-placeholder><ng-template #loadingSpinner><clr-spinner>{{ 'Loading' | translate }} ......
|
||||||
<div *ngIf="error;else loadingSpinner">{{error}}</div></clr-dg-placeholder>
|
</clr-spinner></ng-template>
|
||||||
|
<div *ngIf="error;else loadingSpinner">{{error}}</div>
|
||||||
|
</clr-dg-placeholder>
|
||||||
|
|
||||||
<clr-dg-column [clrDgField]="''">
|
<clr-dg-column [clrDgField]="''">
|
||||||
<ng-container *clrDgHideableColumn="{hidden: false}">
|
<ng-container *clrDgHideableColumn="{hidden: false}">
|
||||||
@@ -70,7 +76,8 @@
|
|||||||
</ng-container></clr-dg-column>
|
</ng-container></clr-dg-column>
|
||||||
|
|
||||||
<clr-dg-row *clrDgItems="let user of data?.slice()?.reverse();" [clrDgItem]="user">
|
<clr-dg-row *clrDgItems="let user of data?.slice()?.reverse();" [clrDgItem]="user">
|
||||||
<clr-dg-cell><span class="label label-light-blue" style="display: inline;margin-left: 10px; cursor: pointer;" (click)="goToEdit(user.id)"> {{ 'SET_UP' | translate }}</span></clr-dg-cell>
|
<clr-dg-cell><span class="label label-light-blue" style="display: inline;margin-left: 10px; cursor: pointer;"
|
||||||
|
(click)="goToEdit(user.id)"> {{ 'SET_UP' | translate }}</span></clr-dg-cell>
|
||||||
<clr-dg-cell>{{user.dashboard_name}}</clr-dg-cell>
|
<clr-dg-cell>{{user.dashboard_name}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{user.description}}</clr-dg-cell>
|
<clr-dg-cell>{{user.description}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{user.secuirity_profile}}</clr-dg-cell>
|
<clr-dg-cell>{{user.secuirity_profile}}</clr-dg-cell>
|
||||||
@@ -80,13 +87,16 @@
|
|||||||
<clr-dg-cell>{{user.testing}}</clr-dg-cell> -->
|
<clr-dg-cell>{{user.testing}}</clr-dg-cell> -->
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<!-- <span style="cursor: pointer; padding: 10px; "><clr-icon shape="form" (click)="goToEdit(user.id)" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span> -->
|
<!-- <span style="cursor: pointer; padding: 10px; "><clr-icon shape="form" (click)="goToEdit(user.id)" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span> -->
|
||||||
<a href="javascript:void(0)" style="padding-right: 10px;" role="tooltip" aria-haspopup="true" class="tooltip tooltip-sm tooltip-top-left">
|
<a href="javascript:void(0)" style="padding-right: 10px;" role="tooltip" aria-haspopup="true"
|
||||||
<span style="cursor: pointer;"><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error" style="color: red;"></clr-icon></span>
|
class="tooltip tooltip-sm tooltip-top-left">
|
||||||
|
<span style="cursor: pointer;"><clr-icon shape="trash" (click)="onDelete(user)" class="red is-error"
|
||||||
|
style="color: red;"></clr-icon></span>
|
||||||
<span class="tooltip-content">{{ 'Delete' | translate }}</span>
|
<span class="tooltip-content">{{ 'Delete' | translate }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<clr-signpost>
|
<clr-signpost>
|
||||||
<span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success" style="color: rgb(0, 130, 236);"></clr-icon></span>
|
<span style="cursor: pointer;" clrSignpostTrigger><clr-icon shape="help" class="success"
|
||||||
|
style="color: rgb(0, 130, 236);"></clr-icon></span>
|
||||||
<clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen>
|
<clr-signpost-content [clrPosition]="'left-middle'" *clrIfOpen>
|
||||||
<h5 style="margin-top: 0">{{ 'Who_Column' | translate }}</h5>
|
<h5 style="margin-top: 0">{{ 'Who_Column' | translate }}</h5>
|
||||||
<div>{{ 'Account_ID' | translate }}: <code class="clr-code">{{ user.accountId }}</code></div>
|
<div>{{ 'Account_ID' | translate }}: <code class="clr-code">{{ user.accountId }}</code></div>
|
||||||
@@ -99,7 +109,8 @@
|
|||||||
|
|
||||||
</clr-dg-cell>
|
</clr-dg-cell>
|
||||||
<clr-dg-action-overflow>
|
<clr-dg-action-overflow>
|
||||||
<button class="action-item" (click)="goToEditData(user.id)">{{ 'Edit' | translate }} <clr-icon shape="edit" class="is-error"></clr-icon></button>
|
<button class="action-item" (click)="goToEditData(user.id)">{{ 'Edit' | translate }} <clr-icon shape="edit"
|
||||||
|
class="is-error"></clr-icon></button>
|
||||||
<!-- <button class="action-item" (click)="onDelete(user)">Delete<clr-icon shape="trash" class="is-error"></clr-icon></button> -->
|
<!-- <button class="action-item" (click)="onDelete(user)">Delete<clr-icon shape="trash" class="is-error"></clr-icon></button> -->
|
||||||
</clr-dg-action-overflow>
|
</clr-dg-action-overflow>
|
||||||
</clr-dg-row>
|
</clr-dg-row>
|
||||||
|
|||||||
@@ -122,4 +122,9 @@ export class AllnewdashComponent implements OnInit {
|
|||||||
// this.router.navigate(['../editdashn'],{relativeTo:this.route});
|
// this.router.navigate(['../editdashn'],{relativeTo:this.route});
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Add method to open chart configuration manager
|
||||||
|
openChartConfig(): void {
|
||||||
|
this.router.navigate(['../chart-types'],{relativeTo:this.route});
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
<div class="chart-config-manager">
|
<div class="chart-config-manager">
|
||||||
<h2>Chart Configuration Manager</h2>
|
<h2>Chart Configuration Manager</h2>
|
||||||
|
|
||||||
|
<!-- Test message to verify component is loading -->
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">Chart Config Manager Component Loaded Successfully</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Error and Success Messages -->
|
<!-- Error and Success Messages -->
|
||||||
<div class="alert alert-danger" *ngIf="errorMessage">
|
<div class="alert alert-danger" *ngIf="errorMessage">
|
||||||
<button type="button" class="close" aria-label="Close" (click)="errorMessage = null">
|
<button type="button" class="close" aria-label="Close" (click)="errorMessage = null">
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export class ChartConfigManagerComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
console.log('ChartConfigManagerComponent initialized');
|
||||||
this.loadChartTypes();
|
this.loadChartTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,8 +144,10 @@ export class ChartConfigManagerComponent implements OnInit {
|
|||||||
// Chart Type Methods
|
// Chart Type Methods
|
||||||
loadChartTypes(): void {
|
loadChartTypes(): void {
|
||||||
this.chartTypeLoadingState = ClrLoadingState.LOADING;
|
this.chartTypeLoadingState = ClrLoadingState.LOADING;
|
||||||
|
console.log('Loading chart types...');
|
||||||
this.chartTypeService.getAllChartTypes().subscribe({
|
this.chartTypeService.getAllChartTypes().subscribe({
|
||||||
next: (data) => {
|
next: (data) => {
|
||||||
|
console.log('Chart types loaded:', data);
|
||||||
this.chartTypes = data;
|
this.chartTypes = data;
|
||||||
this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
|
this.chartTypeLoadingState = ClrLoadingState.SUCCESS;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,29 +14,34 @@ export class UiComponentService {
|
|||||||
// Get all UI components for a chart type
|
// Get all UI components for a chart type
|
||||||
getUiComponentsByChartType(chartTypeId: number): Observable<UiComponent[]> {
|
getUiComponentsByChartType(chartTypeId: number): Observable<UiComponent[]> {
|
||||||
const url = `${this.uiComponentsUrl}/chart-type/${chartTypeId}`;
|
const url = `${this.uiComponentsUrl}/chart-type/${chartTypeId}`;
|
||||||
|
console.log(`Fetching UI components for chart type ${chartTypeId} from ${url}`);
|
||||||
return this.apiRequest.get(url);
|
return this.apiRequest.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get UI component by ID
|
// Get UI component by ID
|
||||||
getUiComponentById(id: number): Observable<UiComponent> {
|
getUiComponentById(id: number): Observable<UiComponent> {
|
||||||
const url = `${this.uiComponentsUrl}/${id}`;
|
const url = `${this.uiComponentsUrl}/${id}`;
|
||||||
|
console.log(`Fetching UI component ${id} from ${url}`);
|
||||||
return this.apiRequest.get(url);
|
return this.apiRequest.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new UI component
|
// Create new UI component
|
||||||
createUiComponent(uiComponent: Partial<UiComponent>): Observable<UiComponent> {
|
createUiComponent(uiComponent: Partial<UiComponent>): Observable<UiComponent> {
|
||||||
|
console.log('Creating UI component:', uiComponent);
|
||||||
return this.apiRequest.post(this.uiComponentsUrl, uiComponent);
|
return this.apiRequest.post(this.uiComponentsUrl, uiComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update UI component
|
// Update UI component
|
||||||
updateUiComponent(id: number, uiComponent: UiComponent): Observable<UiComponent> {
|
updateUiComponent(id: number, uiComponent: UiComponent): Observable<UiComponent> {
|
||||||
const url = `${this.uiComponentsUrl}/${id}`;
|
const url = `${this.uiComponentsUrl}/${id}`;
|
||||||
|
console.log(`Updating UI component ${id}:`, uiComponent);
|
||||||
return this.apiRequest.put(url, uiComponent);
|
return this.apiRequest.put(url, uiComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete UI component
|
// Delete UI component
|
||||||
deleteUiComponent(id: number): Observable<void> {
|
deleteUiComponent(id: number): Observable<void> {
|
||||||
const url = `${this.uiComponentsUrl}/${id}`;
|
const url = `${this.uiComponentsUrl}/${id}`;
|
||||||
|
console.log(`Deleting UI component ${id}`);
|
||||||
return this.apiRequest.delete(url);
|
return this.apiRequest.delete(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
<div class="add-chart-type-page">
|
||||||
|
<div class="header">
|
||||||
|
<h2>Add New Chart Type</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error and Success Messages -->
|
||||||
|
<div class="alert alert-danger" *ngIf="errorMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="errorMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ errorMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-success" *ngIf="successMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="successMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ successMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-block">
|
||||||
|
<form clrForm (ngSubmit)="createChartType()" #addChartTypeForm="ngForm">
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Name <span class="required">*</span></label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="chartType.name" name="chartTypeName" required />
|
||||||
|
<clr-control-helper>Enter a unique name for the chart type (e.g., "line-chart", "bar-chart")</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Display Name</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="chartType.displayName" name="chartTypeDisplayName" />
|
||||||
|
<clr-control-helper>This is the user-friendly name shown in the UI</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-textarea-container>
|
||||||
|
<label>Description</label>
|
||||||
|
<textarea clrTextarea [(ngModel)]="chartType.description" name="chartTypeDescription" rows="3"></textarea>
|
||||||
|
<clr-control-helper>Provide a detailed description of this chart type and when to use it</clr-control-helper>
|
||||||
|
</clr-textarea-container>
|
||||||
|
|
||||||
|
<clr-checkbox-container>
|
||||||
|
<label>Is Active</label>
|
||||||
|
<clr-checkbox-wrapper>
|
||||||
|
<input type="checkbox" clrCheckbox [(ngModel)]="chartType.isActive" name="chartTypeIsActive" />
|
||||||
|
<label>Active</label>
|
||||||
|
</clr-checkbox-wrapper>
|
||||||
|
<clr-control-helper>Deactivate chart types that should not be available for selection</clr-control-helper>
|
||||||
|
</clr-checkbox-container>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button class="btn btn-primary" type="submit" [disabled]="!chartType.name || loadingState === ClrLoadingState.LOADING">
|
||||||
|
<clr-spinner *ngIf="loadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
||||||
|
Create Chart Type
|
||||||
|
</button>
|
||||||
|
<button class="btn" type="button" (click)="onCancel()">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-section">
|
||||||
|
<h4>About Chart Types</h4>
|
||||||
|
<p>Chart types define the different visualization options available in the dashboard builder. Each chart type can have:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Associated UI components that define the configuration form</li>
|
||||||
|
<li>Templates that define how the chart is rendered</li>
|
||||||
|
<li>Dynamic fields that capture specific configuration parameters</li>
|
||||||
|
</ul>
|
||||||
|
<p>After creating a chart type, you can configure its components, templates, and fields in the chart configuration manager.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
.add-chart-type-page {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
h2 {
|
||||||
|
color: #0079b8;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.card-block {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { ClrLoadingState } from '@clr/angular';
|
||||||
|
import { ChartType, ChartTypeService } from './chart-type.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-add-chart-type',
|
||||||
|
templateUrl: './add-chart-type.component.html',
|
||||||
|
styleUrls: ['./add-chart-type.component.scss']
|
||||||
|
})
|
||||||
|
export class AddChartTypeComponent {
|
||||||
|
chartType: Partial<ChartType> = {
|
||||||
|
isActive: true
|
||||||
|
};
|
||||||
|
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 router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
createChartType(): void {
|
||||||
|
if (!this.chartType.name) {
|
||||||
|
this.showError('Chart type name is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.chartTypeService.createChartType(this.chartType).subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
this.showSuccess('Chart type created successfully');
|
||||||
|
this.loadingState = ClrLoadingState.SUCCESS;
|
||||||
|
// Redirect to chart types list after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']);
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Error creating chart type:', error);
|
||||||
|
this.showError('Error creating chart type: ' + (error.error?.message || error.message || 'Unknown error'));
|
||||||
|
this.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel(): void {
|
||||||
|
this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,47 +20,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Add Chart Type Form -->
|
|
||||||
<div class="card" *ngIf="showAddChartTypeForm">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>Add New Chart Type</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-block">
|
|
||||||
<form clrForm>
|
|
||||||
<clr-input-container>
|
|
||||||
<label>Name <span class="required">*</span></label>
|
|
||||||
<input clrInput type="text" [(ngModel)]="newChartType.name" name="chartTypeName" required />
|
|
||||||
</clr-input-container>
|
|
||||||
|
|
||||||
<clr-input-container>
|
|
||||||
<label>Display Name</label>
|
|
||||||
<input clrInput type="text" [(ngModel)]="newChartType.displayName" name="chartTypeDisplayName" />
|
|
||||||
</clr-input-container>
|
|
||||||
|
|
||||||
<clr-textarea-container>
|
|
||||||
<label>Description</label>
|
|
||||||
<textarea clrTextarea [(ngModel)]="newChartType.description" name="chartTypeDescription" rows="3"></textarea>
|
|
||||||
</clr-textarea-container>
|
|
||||||
|
|
||||||
<clr-checkbox-container>
|
|
||||||
<label>Is Active</label>
|
|
||||||
<clr-checkbox-wrapper>
|
|
||||||
<input type="checkbox" clrCheckbox [(ngModel)]="newChartType.isActive" name="chartTypeIsActive" />
|
|
||||||
<label>Active</label>
|
|
||||||
</clr-checkbox-wrapper>
|
|
||||||
</clr-checkbox-container>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="btn btn-primary" (click)="createChartType()" [disabled]="!newChartType.name || chartTypeLoadingState === ClrLoadingState.LOADING">
|
|
||||||
<clr-spinner *ngIf="chartTypeLoadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
<button class="btn" (click)="showAddChartTypeForm = false">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Chart Types Grid -->
|
<!-- Chart Types Grid -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@@ -69,7 +28,7 @@
|
|||||||
<h3>Chart Types</h3>
|
<h3>Chart Types</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="clr-col" style="text-align: right;">
|
<div class="clr-col" style="text-align: right;">
|
||||||
<button class="btn btn-primary" (click)="showAddChartTypeForm = true">
|
<button class="btn btn-primary" [routerLink]="['/cns-portal/dashboardbuilder/chart-types/add']">
|
||||||
<cds-icon shape="plus"></cds-icon> Add Chart Type
|
<cds-icon shape="plus"></cds-icon> Add Chart Type
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -98,7 +57,7 @@
|
|||||||
<clr-dg-cell>{{chartType.createdAt | date:'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{chartType.createdAt | date:'short'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>{{chartType.updatedAt | date:'short'}}</clr-dg-cell>
|
<clr-dg-cell>{{chartType.updatedAt | date:'short'}}</clr-dg-cell>
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<button class="btn btn-sm btn-icon" (click)="selectChartTypeForEdit(chartType)" title="Edit">
|
<button class="btn btn-sm btn-icon" [routerLink]="['/cns-portal/dashboardbuilder/chart-types/edit', chartType.id]" title="Edit">
|
||||||
<cds-icon shape="pencil"></cds-icon>
|
<cds-icon shape="pencil"></cds-icon>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm btn-icon" (click)="deleteChartType(chartType.id)" title="Delete">
|
<button class="btn btn-sm btn-icon" (click)="deleteChartType(chartType.id)" title="Delete">
|
||||||
@@ -113,45 +72,4 @@
|
|||||||
</clr-datagrid>
|
</clr-datagrid>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Edit Chart Type Form -->
|
|
||||||
<div class="card" *ngIf="selectedChartType">
|
|
||||||
<div class="card-header">
|
|
||||||
<h3>Edit Chart Type</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-block">
|
|
||||||
<form clrForm>
|
|
||||||
<clr-input-container>
|
|
||||||
<label>Name <span class="required">*</span></label>
|
|
||||||
<input clrInput type="text" [(ngModel)]="selectedChartType.name" name="editChartTypeName" required />
|
|
||||||
</clr-input-container>
|
|
||||||
|
|
||||||
<clr-input-container>
|
|
||||||
<label>Display Name</label>
|
|
||||||
<input clrInput type="text" [(ngModel)]="selectedChartType.displayName" name="editChartTypeDisplayName" />
|
|
||||||
</clr-input-container>
|
|
||||||
|
|
||||||
<clr-textarea-container>
|
|
||||||
<label>Description</label>
|
|
||||||
<textarea clrTextarea [(ngModel)]="selectedChartType.description" name="editChartTypeDescription" rows="3"></textarea>
|
|
||||||
</clr-textarea-container>
|
|
||||||
|
|
||||||
<clr-checkbox-container>
|
|
||||||
<label>Is Active</label>
|
|
||||||
<clr-checkbox-wrapper>
|
|
||||||
<input type="checkbox" clrCheckbox [(ngModel)]="selectedChartType.isActive" name="editChartTypeIsActive" />
|
|
||||||
<label>Active</label>
|
|
||||||
</clr-checkbox-wrapper>
|
|
||||||
</clr-checkbox-container>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<button class="btn btn-primary" (click)="updateChartType()" [disabled]="!selectedChartType.name || chartTypeLoadingState === ClrLoadingState.LOADING">
|
|
||||||
<clr-spinner *ngIf="chartTypeLoadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
<button class="btn" (click)="selectedChartType = null">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@@ -1,60 +1,71 @@
|
|||||||
.chart-type-manager {
|
.chart-type-manager {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #0079b8;
|
||||||
|
font-weight: 300;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: #0079b8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-block {
|
.card-block {
|
||||||
padding: 15px;
|
padding: 20px;
|
||||||
|
|
||||||
form {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.form-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
clr-datagrid {
|
|
||||||
min-height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-radius: 3px;
|
border-radius: 12px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
|
||||||
|
|
||||||
.label-success {
|
&.label-success {
|
||||||
background-color: #318700;
|
background-color: #3d9970;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-danger {
|
&.label-danger {
|
||||||
background-color: #e62200;
|
background-color: #d32f2f;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.required {
|
|
||||||
color: red;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
clr-datagrid {
|
||||||
margin-bottom: 20px;
|
margin-top: 10px;
|
||||||
|
|
||||||
|
clr-dg-cell {
|
||||||
|
&:first-child {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
.clr-row {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.clr-col {
|
||||||
|
text-align: left !important;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,9 +9,6 @@ import { ChartType, ChartTypeService } from './chart-type.service';
|
|||||||
})
|
})
|
||||||
export class ChartTypeManagerComponent implements OnInit {
|
export class ChartTypeManagerComponent implements OnInit {
|
||||||
chartTypes: ChartType[] = [];
|
chartTypes: ChartType[] = [];
|
||||||
selectedChartType: ChartType | null = null;
|
|
||||||
newChartType: Partial<ChartType> = {};
|
|
||||||
showAddChartTypeForm = false;
|
|
||||||
chartTypeLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
|
chartTypeLoadingState: ClrLoadingState = ClrLoadingState.DEFAULT;
|
||||||
|
|
||||||
// Make ClrLoadingState available to template
|
// Make ClrLoadingState available to template
|
||||||
@@ -59,54 +56,6 @@ export class ChartTypeManagerComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
deleteChartType(id: number): void {
|
||||||
if (!confirm('Are you sure you want to delete this chart type?')) {
|
if (!confirm('Are you sure you want to delete this chart type?')) {
|
||||||
return;
|
return;
|
||||||
@@ -126,8 +75,4 @@ export class ChartTypeManagerComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
selectChartTypeForEdit(chartType: ChartType): void {
|
|
||||||
this.selectedChartType = { ...chartType };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,12 @@ import { Component } from '@angular/core';
|
|||||||
.chart-type-page {
|
.chart-type-page {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.chart-type-page {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
`]
|
`]
|
||||||
})
|
})
|
||||||
export class ChartTypePageComponent { }
|
export class ChartTypePageComponent { }
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
<div class="chart-type-ui-components-page">
|
||||||
|
<div class="header">
|
||||||
|
<h2>
|
||||||
|
<button class="btn btn-link back-button" (click)="goBack()">
|
||||||
|
<cds-icon shape="arrow" direction="left"></cds-icon>
|
||||||
|
</button>
|
||||||
|
UI Components for {{ chartType?.name || 'Chart Type' }}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error and Success Messages -->
|
||||||
|
<div class="alert alert-danger" *ngIf="errorMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="errorMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ errorMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-success" *ngIf="successMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="successMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ successMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Add UI Component Form -->
|
||||||
|
<div class="card" *ngIf="showAddForm">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Add New UI Component</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<form clrForm (ngSubmit)="createUiComponent()" #addUiComponentForm="ngForm">
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Component Name <span class="required">*</span></label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="newUiComponent.componentName" name="componentName" required />
|
||||||
|
<clr-control-helper>Enter a unique name for the UI component (e.g., "title-config", "axis-config")</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Component Type</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="newUiComponent.componentType" name="componentType" />
|
||||||
|
<clr-control-helper>Type of the component (e.g., "input", "select", "checkbox")</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Display Label</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="newUiComponent.displayLabel" name="displayLabel" />
|
||||||
|
<clr-control-helper>User-friendly label shown in the configuration form</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Placeholder</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="newUiComponent.placeholder" name="placeholder" />
|
||||||
|
<clr-control-helper>Placeholder text for input fields</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Sort Order</label>
|
||||||
|
<input clrInput type="number" [(ngModel)]="newUiComponent.sortOrder" name="sortOrder" />
|
||||||
|
<clr-control-helper>Order in which components appear in the form</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-checkbox-container>
|
||||||
|
<label>Is Required</label>
|
||||||
|
<clr-checkbox-wrapper>
|
||||||
|
<input type="checkbox" clrCheckbox [(ngModel)]="newUiComponent.isRequired" name="isRequired" />
|
||||||
|
<label>Required</label>
|
||||||
|
</clr-checkbox-wrapper>
|
||||||
|
<clr-control-helper>Mark as required if this component must be filled</clr-control-helper>
|
||||||
|
</clr-checkbox-container>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button class="btn btn-primary" type="submit" [disabled]="!newUiComponent.componentName || loadingState === ClrLoadingState.LOADING">
|
||||||
|
<clr-spinner *ngIf="loadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
||||||
|
Create UI Component
|
||||||
|
</button>
|
||||||
|
<button class="btn" type="button" (click)="showAddForm = false">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- UI Components Grid -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="clr-row">
|
||||||
|
<div class="clr-col">
|
||||||
|
<h3>UI Components</h3>
|
||||||
|
</div>
|
||||||
|
<div class="clr-col" style="text-align: right;">
|
||||||
|
<button class="btn btn-primary" (click)="showAddForm = true">
|
||||||
|
<cds-icon shape="plus"></cds-icon> Add UI Component
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-block">
|
||||||
|
<clr-datagrid [clrDgLoading]="loadingState === ClrLoadingState.LOADING">
|
||||||
|
<clr-dg-column>Component Name</clr-dg-column>
|
||||||
|
<clr-dg-column>Component Type</clr-dg-column>
|
||||||
|
<clr-dg-column>Display Label</clr-dg-column>
|
||||||
|
<clr-dg-column>Placeholder</clr-dg-column>
|
||||||
|
<clr-dg-column>Required</clr-dg-column>
|
||||||
|
<clr-dg-column>Sort Order</clr-dg-column>
|
||||||
|
<clr-dg-column>Actions</clr-dg-column>
|
||||||
|
|
||||||
|
<clr-dg-row *clrDgItems="let uiComponent of uiComponents" [clrDgItem]="uiComponent">
|
||||||
|
<clr-dg-cell>{{uiComponent.componentName}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{uiComponent.componentType}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{uiComponent.displayLabel}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{uiComponent.placeholder}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>
|
||||||
|
<span class="label" [class.label-success]="uiComponent.isRequired" [class.label-danger]="!uiComponent.isRequired">
|
||||||
|
{{uiComponent.isRequired ? 'Yes' : 'No'}}
|
||||||
|
</span>
|
||||||
|
</clr-dg-cell>
|
||||||
|
<clr-dg-cell>{{uiComponent.sortOrder}}</clr-dg-cell>
|
||||||
|
<clr-dg-cell>
|
||||||
|
<button class="btn btn-sm btn-icon" (click)="selectUiComponentForEdit(uiComponent)" title="Edit">
|
||||||
|
<cds-icon shape="pencil"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-icon" (click)="deleteUiComponent(uiComponent.id)" title="Delete">
|
||||||
|
<cds-icon shape="trash"></cds-icon>
|
||||||
|
</button>
|
||||||
|
</clr-dg-cell>
|
||||||
|
</clr-dg-row>
|
||||||
|
|
||||||
|
<clr-dg-footer>
|
||||||
|
{{uiComponents.length}} UI component(s)
|
||||||
|
</clr-dg-footer>
|
||||||
|
</clr-datagrid>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Edit UI Component Form -->
|
||||||
|
<div class="card" *ngIf="selectedUiComponent">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Edit UI Component</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<form clrForm (ngSubmit)="updateUiComponent()" #editUiComponentForm="ngForm">
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Component Name <span class="required">*</span></label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="selectedUiComponent.componentName" name="editComponentName" required />
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Component Type</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="selectedUiComponent.componentType" name="editComponentType" />
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Display Label</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="selectedUiComponent.displayLabel" name="editDisplayLabel" />
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Placeholder</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="selectedUiComponent.placeholder" name="editPlaceholder" />
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Sort Order</label>
|
||||||
|
<input clrInput type="number" [(ngModel)]="selectedUiComponent.sortOrder" name="editSortOrder" />
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-checkbox-container>
|
||||||
|
<label>Is Required</label>
|
||||||
|
<clr-checkbox-wrapper>
|
||||||
|
<input type="checkbox" clrCheckbox [(ngModel)]="selectedUiComponent.isRequired" name="editIsRequired" />
|
||||||
|
<label>Required</label>
|
||||||
|
</clr-checkbox-wrapper>
|
||||||
|
</clr-checkbox-container>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button class="btn btn-primary" type="submit" [disabled]="!selectedUiComponent.componentName || loadingState === ClrLoadingState.LOADING">
|
||||||
|
<clr-spinner *ngIf="loadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
||||||
|
Update UI Component
|
||||||
|
</button>
|
||||||
|
<button class="btn" type="button" (click)="selectedUiComponent = null">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-section">
|
||||||
|
<h4>About UI Components</h4>
|
||||||
|
<p>UI components define the configuration form elements for a chart type. Each component represents:</p>
|
||||||
|
<ul>
|
||||||
|
<li>A form field that appears when configuring a chart of this type</li>
|
||||||
|
<li>Metadata like label, placeholder, and validation rules</li>
|
||||||
|
<li>An order in which they appear in the configuration form</li>
|
||||||
|
</ul>
|
||||||
|
<p>After creating UI components, you can define their properties in the component properties section.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-chart-type-ui-components',
|
||||||
|
templateUrl: './chart-type-ui-components.component.html',
|
||||||
|
styleUrls: ['./chart-type-ui-components.component.scss']
|
||||||
|
})
|
||||||
|
export class ChartTypeUiComponentsComponent implements OnInit {
|
||||||
|
chartType: ChartType | null = null;
|
||||||
|
uiComponents: UiComponent[] = [];
|
||||||
|
newUiComponent: Partial<UiComponent> = {
|
||||||
|
isRequired: false
|
||||||
|
};
|
||||||
|
selectedUiComponent: UiComponent | 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 uiComponentService: UiComponentService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const chartTypeId = Number(this.route.snapshot.paramMap.get('id'));
|
||||||
|
if (chartTypeId) {
|
||||||
|
this.loadChartType(chartTypeId);
|
||||||
|
this.loadUiComponents(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'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadUiComponents(chartTypeId: number): void {
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.uiComponentService.getUiComponentsByChartType(chartTypeId).subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
this.uiComponents = data;
|
||||||
|
this.loadingState = 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.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
createUiComponent(): void {
|
||||||
|
if (!this.chartType || !this.newUiComponent.componentName) {
|
||||||
|
this.showError('Component name is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const componentData = {
|
||||||
|
...this.newUiComponent,
|
||||||
|
chartType: { id: this.chartType.id }
|
||||||
|
};
|
||||||
|
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.uiComponentService.createUiComponent(componentData).subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
this.uiComponents.push(data);
|
||||||
|
this.newUiComponent = { isRequired: false };
|
||||||
|
this.showAddForm = false;
|
||||||
|
this.showSuccess('UI component created successfully');
|
||||||
|
this.loadingState = 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.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateUiComponent(): void {
|
||||||
|
if (!this.selectedUiComponent || !this.selectedUiComponent.componentName) {
|
||||||
|
this.showError('Component name is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingState = 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.loadingState = 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.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUiComponent(id: number): void {
|
||||||
|
if (!confirm('Are you sure you want to delete this UI component?')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.uiComponentService.deleteUiComponent(id).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.uiComponents = this.uiComponents.filter(uc => uc.id !== id);
|
||||||
|
this.showSuccess('UI component deleted successfully');
|
||||||
|
this.loadingState = 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.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
selectUiComponentForEdit(uiComponent: UiComponent): void {
|
||||||
|
this.selectedUiComponent = { ...uiComponent };
|
||||||
|
}
|
||||||
|
|
||||||
|
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']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,29 +22,34 @@ export class ChartTypeService {
|
|||||||
|
|
||||||
// Get all chart types
|
// Get all chart types
|
||||||
getAllChartTypes(): Observable<ChartType[]> {
|
getAllChartTypes(): Observable<ChartType[]> {
|
||||||
|
console.log('Fetching all chart types from', this.chartTypesUrl);
|
||||||
return this.apiRequest.get(this.chartTypesUrl);
|
return this.apiRequest.get(this.chartTypesUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get chart type by ID
|
// Get chart type by ID
|
||||||
getChartTypeById(id: number): Observable<ChartType> {
|
getChartTypeById(id: number): Observable<ChartType> {
|
||||||
const url = `${this.chartTypesUrl}/${id}`;
|
const url = `${this.chartTypesUrl}/${id}`;
|
||||||
|
console.log(`Fetching chart type ${id} from ${url}`);
|
||||||
return this.apiRequest.get(url);
|
return this.apiRequest.get(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new chart type
|
// Create new chart type
|
||||||
createChartType(chartType: Partial<ChartType>): Observable<ChartType> {
|
createChartType(chartType: Partial<ChartType>): Observable<ChartType> {
|
||||||
|
console.log('Creating chart type:', chartType);
|
||||||
return this.apiRequest.post(this.chartTypesUrl, chartType);
|
return this.apiRequest.post(this.chartTypesUrl, chartType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update chart type
|
// Update chart type
|
||||||
updateChartType(id: number, chartType: ChartType): Observable<ChartType> {
|
updateChartType(id: number, chartType: ChartType): Observable<ChartType> {
|
||||||
const url = `${this.chartTypesUrl}/${id}`;
|
const url = `${this.chartTypesUrl}/${id}`;
|
||||||
|
console.log(`Updating chart type ${id}:`, chartType);
|
||||||
return this.apiRequest.put(url, chartType);
|
return this.apiRequest.put(url, chartType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete chart type
|
// Delete chart type
|
||||||
deleteChartType(id: number): Observable<void> {
|
deleteChartType(id: number): Observable<void> {
|
||||||
const url = `${this.chartTypesUrl}/${id}`;
|
const url = `${this.chartTypesUrl}/${id}`;
|
||||||
|
console.log(`Deleting chart type ${id}`);
|
||||||
return this.apiRequest.delete(url);
|
return this.apiRequest.delete(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
<div class="edit-chart-type-page">
|
||||||
|
<div class="header">
|
||||||
|
<h2>Edit Chart Type</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading State -->
|
||||||
|
<div *ngIf="loadingState === ClrLoadingState.LOADING" class="loading-spinner">
|
||||||
|
<clr-spinner clrMedium></clr-spinner>
|
||||||
|
<span>Loading chart type...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Error and Success Messages -->
|
||||||
|
<div class="alert alert-danger" *ngIf="errorMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="errorMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ errorMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-success" *ngIf="successMessage">
|
||||||
|
<button type="button" class="close" aria-label="Close" (click)="successMessage = null">
|
||||||
|
<cds-icon shape="close"></cds-icon>
|
||||||
|
</button>
|
||||||
|
<div class="alert-item">
|
||||||
|
<span class="alert-text">{{ successMessage }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chart Type Form -->
|
||||||
|
<div class="card" *ngIf="chartType && loadingState !== ClrLoadingState.LOADING">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="chart-type-header">
|
||||||
|
<h3>{{ chartType.name }}</h3>
|
||||||
|
<span class="label" [class.label-success]="chartType.isActive" [class.label-danger]="!chartType.isActive">
|
||||||
|
{{ chartType.isActive ? 'Active' : 'Inactive' }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<form clrForm (ngSubmit)="updateChartType()" #editChartTypeForm="ngForm">
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Name <span class="required">*</span></label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="chartType.name" name="chartTypeName" required />
|
||||||
|
<clr-control-helper>Enter a unique name for the chart type (e.g., "line-chart", "bar-chart")</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-input-container>
|
||||||
|
<label>Display Name</label>
|
||||||
|
<input clrInput type="text" [(ngModel)]="chartType.displayName" name="chartTypeDisplayName" />
|
||||||
|
<clr-control-helper>This is the user-friendly name shown in the UI</clr-control-helper>
|
||||||
|
</clr-input-container>
|
||||||
|
|
||||||
|
<clr-textarea-container>
|
||||||
|
<label>Description</label>
|
||||||
|
<textarea clrTextarea [(ngModel)]="chartType.description" name="chartTypeDescription" rows="3"></textarea>
|
||||||
|
<clr-control-helper>Provide a detailed description of this chart type and when to use it</clr-control-helper>
|
||||||
|
</clr-textarea-container>
|
||||||
|
|
||||||
|
<clr-checkbox-container>
|
||||||
|
<label>Is Active</label>
|
||||||
|
<clr-checkbox-wrapper>
|
||||||
|
<input type="checkbox" clrCheckbox [(ngModel)]="chartType.isActive" name="chartTypeIsActive" />
|
||||||
|
<label>Active</label>
|
||||||
|
</clr-checkbox-wrapper>
|
||||||
|
<clr-control-helper>Deactivate chart types that should not be available for selection</clr-control-helper>
|
||||||
|
</clr-checkbox-container>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<button class="btn btn-primary" type="submit" [disabled]="!chartType.name || loadingState === ClrLoadingState.LOADING">
|
||||||
|
<clr-spinner *ngIf="loadingState === ClrLoadingState.LOADING" clrSmall clrInline></clr-spinner>
|
||||||
|
Update Chart Type
|
||||||
|
</button>
|
||||||
|
<button class="btn" type="button" (click)="onCancel()">Cancel</button>
|
||||||
|
<button class="btn btn-danger" type="button" (click)="onDelete()" style="margin-left: auto;">
|
||||||
|
<cds-icon shape="trash"></cds-icon> Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Related Entities Management -->
|
||||||
|
<div class="card" *ngIf="chartType && loadingState !== ClrLoadingState.LOADING">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Related Configuration</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="related-entities-grid">
|
||||||
|
<div class="entity-card">
|
||||||
|
<div class="entity-header">
|
||||||
|
<cds-icon shape="view-list" size="24"></cds-icon>
|
||||||
|
<h4>UI Components</h4>
|
||||||
|
</div>
|
||||||
|
<p>Manage the UI components that define the configuration form for this chart type.</p>
|
||||||
|
<button class="btn btn-sm btn-link" [routerLink]="['/cns-portal/dashboardbuilder/chart-types', chartType.id, 'ui-components']">
|
||||||
|
Manage UI Components
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="entity-card">
|
||||||
|
<div class="entity-header">
|
||||||
|
<cds-icon shape="template" size="24"></cds-icon>
|
||||||
|
<h4>Chart Templates</h4>
|
||||||
|
</div>
|
||||||
|
<p>Manage the templates that define how this chart type is rendered.</p>
|
||||||
|
<button class="btn btn-sm btn-link" [routerLink]="['/cns-portal/dashboardbuilder/chart-types', chartType.id, 'templates']">
|
||||||
|
Manage Templates
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="entity-card">
|
||||||
|
<div class="entity-header">
|
||||||
|
<cds-icon shape="form" size="24"></cds-icon>
|
||||||
|
<h4>Dynamic Fields</h4>
|
||||||
|
</div>
|
||||||
|
<p>Manage the dynamic fields that capture specific configuration parameters.</p>
|
||||||
|
<button class="btn btn-sm btn-link" [routerLink]="['/cns-portal/dashboardbuilder/chart-types', chartType.id, 'fields']">
|
||||||
|
Manage Fields
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chart Type Details -->
|
||||||
|
<div class="card" *ngIf="chartType && loadingState !== ClrLoadingState.LOADING">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3>Chart Type Details</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="details-grid">
|
||||||
|
<div class="detail-item">
|
||||||
|
<label>ID:</label>
|
||||||
|
<span>{{ chartType.id }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<label>Created At:</label>
|
||||||
|
<span>{{ chartType.createdAt | date:'medium' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-item">
|
||||||
|
<label>Updated At:</label>
|
||||||
|
<span>{{ chartType.updatedAt | date:'medium' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-section">
|
||||||
|
<h4>About Chart Types</h4>
|
||||||
|
<p>Chart types define the different visualization options available in the dashboard builder. Each chart type can have:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Associated UI components that define the configuration form</li>
|
||||||
|
<li>Templates that define how the chart is rendered</li>
|
||||||
|
<li>Dynamic fields that capture specific configuration parameters</li>
|
||||||
|
</ul>
|
||||||
|
<p>After creating a chart type, you can configure its components, templates, and fields using the management links above.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
.edit-chart-type-page {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
h2 {
|
||||||
|
color: #0079b8;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
.card-block {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
.chart-type-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-entities-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
.entity-card {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
|
||||||
|
.entity-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
|
||||||
|
cds-icon {
|
||||||
|
color: #0079b8;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
color: #0079b8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-link {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.details-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
padding: 8px;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-type-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start !important;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.related-entities-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ClrLoadingState } from '@clr/angular';
|
||||||
|
import { ChartType, ChartTypeService } from './chart-type.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-edit-chart-type',
|
||||||
|
templateUrl: './edit-chart-type.component.html',
|
||||||
|
styleUrls: ['./edit-chart-type.component.scss']
|
||||||
|
})
|
||||||
|
export class EditChartTypeComponent implements OnInit {
|
||||||
|
chartType: ChartType | null = null;
|
||||||
|
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 route: ActivatedRoute,
|
||||||
|
private router: Router
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
const id = Number(this.route.snapshot.paramMap.get('id'));
|
||||||
|
if (id) {
|
||||||
|
this.loadChartType(id);
|
||||||
|
} 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.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.chartTypeService.getChartTypeById(id).subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
this.chartType = data;
|
||||||
|
this.loadingState = ClrLoadingState.SUCCESS;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Error loading chart type:', error);
|
||||||
|
this.showError('Error loading chart type: ' + (error.error?.message || error.message || 'Unknown error'));
|
||||||
|
this.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateChartType(): void {
|
||||||
|
if (!this.chartType || !this.chartType.name) {
|
||||||
|
this.showError('Chart type name is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.chartTypeService.updateChartType(this.chartType.id, this.chartType).subscribe({
|
||||||
|
next: (data) => {
|
||||||
|
this.chartType = data;
|
||||||
|
this.showSuccess('Chart type updated successfully');
|
||||||
|
this.loadingState = ClrLoadingState.SUCCESS;
|
||||||
|
// Redirect to chart types list after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']);
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Error updating chart type:', error);
|
||||||
|
this.showError('Error updating chart type: ' + (error.error?.message || error.message || 'Unknown error'));
|
||||||
|
this.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel(): void {
|
||||||
|
this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDelete(): void {
|
||||||
|
if (!this.chartType) return;
|
||||||
|
|
||||||
|
if (confirm('Are you sure you want to delete this chart type? This action cannot be undone.')) {
|
||||||
|
this.loadingState = ClrLoadingState.LOADING;
|
||||||
|
this.chartTypeService.deleteChartType(this.chartType.id).subscribe({
|
||||||
|
next: () => {
|
||||||
|
this.showSuccess('Chart type deleted successfully');
|
||||||
|
this.loadingState = ClrLoadingState.SUCCESS;
|
||||||
|
// Redirect to chart types list after a short delay
|
||||||
|
setTimeout(() => {
|
||||||
|
this.router.navigate(['/cns-portal/dashboardbuilder/chart-types']);
|
||||||
|
}, 1500);
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
console.error('Error deleting chart type:', error);
|
||||||
|
this.showError('Error deleting chart type: ' + (error.error?.message || error.message || 'Unknown error'));
|
||||||
|
this.loadingState = ClrLoadingState.ERROR;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,9 +11,6 @@
|
|||||||
<button class="btn btn-primary" (click)="openCommonFilterModal()" style="margin-left: 10px;" *ngIf="!fromRunner">
|
<button class="btn btn-primary" (click)="openCommonFilterModal()" style="margin-left: 10px;" *ngIf="!fromRunner">
|
||||||
<clr-icon shape="filter"></clr-icon> Common Filter
|
<clr-icon shape="filter"></clr-icon> Common Filter
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-primary" (click)="openChartConfigManager()" style="margin-left: 10px;" *ngIf="!fromRunner">
|
|
||||||
<clr-icon shape="cog"></clr-icon> Chart Config
|
|
||||||
</button>
|
|
||||||
<div style="display: inline;">
|
<div style="display: inline;">
|
||||||
{{dashboardName}}
|
{{dashboardName}}
|
||||||
</div>
|
</div>
|
||||||
@@ -735,16 +732,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
||||||
|
|
||||||
<clr-modal [(clrModalOpen)]="chartConfigModalOpen" [clrModalSize]="'xl'" [clrModalStaticBackdrop]="true">
|
|
||||||
<h3 class="modal-title">Chart Configuration Manager</h3>
|
|
||||||
<div class="modal-body">
|
|
||||||
<app-chart-config-manager></app-chart-config-manager>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-outline" (click)="closeChartConfigManager()">Close</button>
|
|
||||||
</div>
|
|
||||||
</clr-modal>
|
|
||||||
|
|
||||||
<!-- Common Filter Modal -->
|
<!-- Common Filter Modal -->
|
||||||
<clr-modal [(clrModalOpen)]="commonFilterModalOpen" [clrModalStaticBackdrop]="true" clrModalSize="lg">
|
<clr-modal [(clrModalOpen)]="commonFilterModalOpen" [clrModalStaticBackdrop]="true" clrModalSize="lg">
|
||||||
<h3 class="modal-title">Configure Common Filter</h3>
|
<h3 class="modal-title">Configure Common Filter</h3>
|
||||||
@@ -829,4 +816,3 @@
|
|||||||
<button type="button" class="btn btn-primary" (click)="saveCommonFilter()">Save</button>
|
<button type="button" class="btn btn-primary" (click)="saveCommonFilter()">Save</button>
|
||||||
</div>
|
</div>
|
||||||
</clr-modal>
|
</clr-modal>
|
||||||
|
|
||||||
|
|||||||
@@ -206,9 +206,6 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
// Add drilldown column data property
|
// Add drilldown column data property
|
||||||
drilldownColumnData = []; // Add drilldown column data property
|
drilldownColumnData = []; // Add drilldown column data property
|
||||||
|
|
||||||
// Add property for chart config modal
|
|
||||||
chartConfigModalOpen: boolean = false;
|
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute,
|
constructor(private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private dashboardService: Dashboard3Service,
|
private dashboardService: Dashboard3Service,
|
||||||
@@ -334,7 +331,6 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
this.toggle = !this.toggle;
|
this.toggle = !this.toggle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onDrag(event, identifier) {
|
onDrag(event, identifier) {
|
||||||
console.log("on drag", identifier);
|
console.log("on drag", identifier);
|
||||||
console.log("on drag ", event);
|
console.log("on drag ", event);
|
||||||
@@ -2049,14 +2045,4 @@ export class EditnewdashComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add method to open chart configuration manager
|
|
||||||
openChartConfigManager(): void {
|
|
||||||
this.chartConfigModalOpen = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add method to close chart configuration manager
|
|
||||||
closeChartConfigManager(): void {
|
|
||||||
this.chartConfigModalOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user