Enter the API URL for base drilldown data. Use angle brackets for parameters, e.g., http://api.example.com/data/<country>
+
+
+
+
+
+
+
+
+
+
+
Select the column to use for X-axis in base drilldown view
+
+
+
+
+
+
+
+
+
+
+
Select the column to use for Y-axis in base drilldown view
+
+
+
+
+
+
+
+
+
+
+
+
Select the column to use as parameter for URL template replacement in base drilldown
+
+
+
+
+
+
+
Multi-Layer Drilldown Configurations
+
+
Add additional drilldown layers for multi-level navigation
+
+
+
+
+
+
+
+
Drilldown Layer {{i + 1}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Enter the API URL for layer {{i + 1}} drilldown data. Use angle brackets for parameters, e.g., http://api.example.com/data/<state>
+
+
+
+
+
+
+
+
+
+
+
Select the column to use for X-axis in layer {{i + 1}} drilldown view
+
+
+
+
+
+
+
+
+
+
+
Select the column to use for Y-axis in layer {{i + 1}} drilldown view
+
+
+
+
+
+
+
+
+
+
+
+
Select the column to use as parameter for URL template replacement in layer {{i + 1}} drilldown
+
+
+
+
+
+
+
+
-
+
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
index 5104759..9e52f83 100644
--- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/editnewdash/editnewdash.component.ts
@@ -20,7 +20,8 @@ import { GridViewComponent } from '../gadgets/grid-view/grid-view.component';
import { DatastoreService } from 'src/app/services/fnd/datastore.service';
import { AlertsService } from 'src/app/services/fnd/alerts.service';
import { isArray } from 'highcharts';
-// import { ChartItem } from '../chartitem';
+// Add the SureconnectService import
+import { SureconnectService } from '../sureconnect/sureconnect.service';
function isNullArray(arr) {
return !Array.isArray(arr) || arr.length === 0;
@@ -36,487 +37,574 @@ function isNullArray(arr) {
export class EditnewdashComponent implements OnInit {
- editId:number;
- toggle:boolean;
- modeledit:boolean = false;
+ editId: number;
+ toggle: boolean;
+ modeledit: boolean = false;
public entryForm: FormGroup;
WidgetsMock: WidgetModel[] = [
{
- name: 'Radar Chart',
- identifier: 'radar_chart'
+ name: 'Radar Chart',
+ identifier: 'radar_chart'
},
{
- name: 'Doughnut Chart',
- identifier: 'doughnut_chart'
+ name: 'Doughnut Chart',
+ identifier: 'doughnut_chart'
},
{
- name: 'Line Chart',
- identifier: 'line_chart'
+ name: 'Line Chart',
+ identifier: 'line_chart'
+ },
+ {
+ name: 'Bar Chart',
+ identifier: 'bar_chart'
+ },
+ {
+ name: 'Pie Chart',
+ identifier: 'pie_chart'
+ },
+ {
+ name: 'Polar Area Chart',
+ identifier: 'polar_area_chart'
+ },
+ {
+ name: 'Bubble Chart',
+ identifier: 'bubble_chart'
+ },
+ {
+ name: 'Scatter Chart',
+ identifier: 'scatter_chart'
+ },
+ // {
+ // name: 'Dynamic Chart',
+ // identifier: 'dynamic_chart'
+ // },
+ // {
+ // name: 'Financial Chart',
+ // identifier: 'financial_chart'
+ // },
+ {
+ name: 'To Do',
+ identifier: 'to_do_chart'
},
- {
- name: 'Bar Chart',
- identifier: 'bar_chart'
- },
- {
- name: 'Pie Chart',
- identifier: 'pie_chart'
- },
- {
- name: 'Polar Area Chart',
- identifier: 'polar_area_chart'
- },
- {
- name: 'Bubble Chart',
- identifier: 'bubble_chart'
- },
- {
- name: 'Scatter Chart',
- identifier: 'scatter_chart'
- },
- // {
- // name: 'Dynamic Chart',
- // identifier: 'dynamic_chart'
- // },
- // {
- // name: 'Financial Chart',
- // identifier: 'financial_chart'
- // },
- {
- name: 'To Do',
- identifier: 'to_do_chart'
- },
{
name: 'Grid View',
identifier: 'grid_view'
- }
-]
+ }
+ ]
public options: GridsterConfig;
- protected dashboardId: number;
- protected dashboardCollection: DashboardModel;
- //dashboardCollection:any;
- protected dashboardCollection1: DashboardModel[];
- public dashboardArray: DashboardContentModel[];
- public dashArr:[];
+ protected dashboardId: number;
+ protected dashboardCollection: DashboardModel;
+ //dashboardCollection:any;
+ protected dashboardCollection1: DashboardModel[];
+ public dashboardArray: DashboardContentModel[];
+ public dashArr: [];
- protected componentCollection = [
- { name: "Line Chart", componentInstance: LineChartComponent },
- { name: "Doughnut Chart", componentInstance: DoughnutChartComponent },
- { name: "Radar Chart", componentInstance: RadarChartComponent },
- { name: "Bar Chart", componentInstance: BarChartComponent },
- { name: "Pie Chart", componentInstance: PieChartComponent },
- { name: "Polar Area Chart", componentInstance: PolarChartComponent },
- { name: "Bubble Chart", componentInstance: BubbleChartComponent },
- { name: "Scatter Chart", componentInstance: ScatterChartComponent },
- { name: "Dynamic Chart", componentInstance: DynamicChartComponent },
- { name: "Financial Chart", componentInstance: FinancialChartComponent },
- { name: "To Do Chart", componentInstance: ToDoChartComponent },
+ protected componentCollection = [
+ { name: "Line Chart", componentInstance: LineChartComponent },
+ { name: "Doughnut Chart", componentInstance: DoughnutChartComponent },
+ { name: "Radar Chart", componentInstance: RadarChartComponent },
+ { name: "Bar Chart", componentInstance: BarChartComponent },
+ { name: "Pie Chart", componentInstance: PieChartComponent },
+ { name: "Polar Area Chart", componentInstance: PolarChartComponent },
+ { name: "Bubble Chart", componentInstance: BubbleChartComponent },
+ { name: "Scatter Chart", componentInstance: ScatterChartComponent },
+ { name: "Dynamic Chart", componentInstance: DynamicChartComponent },
+ { name: "Financial Chart", componentInstance: FinancialChartComponent },
+ { name: "To Do Chart", componentInstance: ToDoChartComponent },
{ name: "Grid View", componentInstance: GridViewComponent },
- ];
- model:any;
- linesdata:any;
- id:any;
+ ];
+ model: any;
+ linesdata: any;
+ id: any;
gadgetsEditdata = {
- donut : '',
+ donut: '',
chartlegend: '',
- showlabel : '',
+ showlabel: '',
charturl: '',
- chartparameter : '',
- datastore : '',
- table:'',
- datasource : '',
- charttitle:'',
- id:'',
- fieldName:'',
- chartcolor:'',
- slices:'',
- yAxis:'',
- xAxis:''
+ chartparameter: '',
+ datastore: '',
+ table: '',
+ datasource: '',
+ charttitle: '',
+ id: '',
+ fieldName: '',
+ chartcolor: '',
+ slices: '',
+ yAxis: '',
+ xAxis: '',
+ connection: '', // Add connection field
+ // Drilldown configuration properties (base level)
+ drilldownEnabled: false,
+ drilldownApiUrl: '',
+ // Removed drilldownParameterKey since we're using URL templates
+ drilldownXAxis: '',
+ drilldownYAxis: '',
+ drilldownParameter: '', // Add drilldown parameter property
+ // Multi-layer drilldown configurations
+ drilldownLayers: [] as any[]
+ };
+
+ // Add sureconnect data property
+ sureconnectData: any[] = [];
+ layerColumnData: { [key: number]: any[] } = {}; // Add layer column data property
-};
constructor(private route: ActivatedRoute,
- private router : Router,
- private dashboardService: Dashboard3Service,
- private toastr:ToastrService,
+ private router: Router,
+ private dashboardService: Dashboard3Service,
+ private toastr: ToastrService,
private _fb: FormBuilder,
private datastoreService: DatastoreService,
- private alertService:AlertsService,) { }
+ private alertService: AlertsService,
+ private sureconnectService: SureconnectService) { } // Add SureconnectService to constructor
- ngOnInit(): void {
+ ngOnInit(): void {
- // Grid options
- this.options = {
- gridType: "fit",
- enableEmptyCellDrop: true,
- emptyCellDropCallback: this.onDrop,
- pushItems: true,
- swap: true,
- pushDirections: { north: true, east: true, south: true, west: true },
- resizable: { enabled: true },
- itemChangeCallback: this.itemChange.bind(this),
- draggable: {
- enabled: true,
- ignoreContent: true,
- dropOverItems: true,
- dragHandleClass: "drag-handler",
- ignoreContentClass: "no-drag",
- },
- displayGrid: "always",
- minCols: 10,
- minRows: 10
- };
- this.getData();
-
- this.editId = this.route.snapshot.params.id;
- console.log(this.editId);
- this.dashboardService.getById(this.editId).subscribe((data)=>{
- console.log("ngOnInit",data);
- this.linesdata = data;
- this.id = data.dashbord1_Line[0].id;
- console.log("this.id ",this.id);
+ // Grid options
+ this.options = {
+ gridType: "fit",
+ enableEmptyCellDrop: true,
+ emptyCellDropCallback: this.onDrop,
+ pushItems: true,
+ swap: true,
+ pushDirections: { north: true, east: true, south: true, west: true },
+ resizable: { enabled: true },
+ itemChangeCallback: this.itemChange.bind(this),
+ draggable: {
+ enabled: true,
+ ignoreContent: true,
+ dropOverItems: true,
+ dragHandleClass: "drag-handler",
+ ignoreContentClass: "no-drag",
},
- (error: any)=>{
+ displayGrid: "always",
+ minCols: 10,
+ minRows: 10
+ };
+
+ this.editId = this.route.snapshot.params.id;
+ console.log(this.editId);
+ this.dashboardService.getById(this.editId).subscribe((data) => {
+ console.log("ngOnInit", data);
+ this.linesdata = data;
+ this.id = data.dashbord1_Line[0].id;
+ console.log("this.id ", this.id);
+ },
+ (error: any) => {
}
- );
+ );
- this.entryForm = this._fb.group({
- donut : [null],
- chartlegend: [null],
- showlabel : [null],
- charturl: [null],
- chartparameter : [null],
- datastore:[null],
- table:[null],
- fieldName: [null],
- datasource : [null],
- charttitle:[null],
- id:[null],
- chartcolor:[null],
- slices:[null],
- yAxis:[null],
- xAxis: [null],
- });
- }
+ this.entryForm = this._fb.group({
+ donut: [null],
+ chartlegend: [null],
+ showlabel: [null],
+ charturl: [null],
+ chartparameter: [null],
+ datastore: [null],
+ table: [null],
+ fieldName: [null],
+ datasource: [null],
+ charttitle: [null],
+ id: [null],
+ chartcolor: [null],
+ slices: [null],
+ yAxis: [null],
+ xAxis: [null],
+ connection: [null], // Add connection to form group
+ // Base drilldown configuration form controls
+ drilldownEnabled: [null],
+ drilldownApiUrl: [null],
+ drilldownXAxis: [null],
+ drilldownYAxis: [null],
+ drilldownParameter: [null] // Add drilldown parameter to form group
+ // Note: Dynamic drilldown layers will be handled separately since they're complex objects
+ });
+
+ // Load sureconnect data first, then load dashboard data
+ this.loadSureconnectData();
+ }
+
+ // Add method to load sureconnect data
+ loadSureconnectData() {
+ this.sureconnectService.getAll().subscribe((data: any[]) => {
+ this.sureconnectData = data;
+ console.log('Sureconnect data loaded:', this.sureconnectData);
+ // Now that sureconnect data is loaded, we can safely load dashboard data
+ this.getData();
+ }, (error) => {
+ console.log('Error loading sureconnect data:', error);
+ // Even if there's an error loading sureconnect data, we still need to load dashboard data
+ this.getData();
+ });
+ }
- toggleMenu() {
- this.toggle = !this.toggle;
- }
+ toggleMenu() {
+ this.toggle = !this.toggle;
+ }
- onDrag(event, identifier) {
- console.log("on drag",identifier);
- console.log("on drag ",event);
- event.dataTransfer.setData('widgetIdentifier', identifier);
- }
- datagadgets:any;
- dashboardLine:any;
- dashboardName:any;
- getData() {
- // We get the id in get current router dashboard/:id
- this.route.params.subscribe(params => {
- // + is used to cast string to int
- this.dashboardId = +params["id"];
- // We make a get request with the dashboard id
- this.dashboardService.getById(this.dashboardId).subscribe(dashboard => {
- // We fill our dashboardCollection with returned Observable
- this.dashboardName = dashboard.dashboard_name;
- this.datagadgets = dashboard;
- this.dashboardLine = dashboard.dashbord1_Line;
- //this.dashboardCollection = dashboard.dashbord1_Line.model;
- console.log("this.datagadgets",this.datagadgets);
- console.log("this.dashboardLine",this.dashboardLine);
- this.dashboardCollection =JSON.parse(this.dashboardLine[0].model) ;
- //this.dashboardCollection =this.dashboardLine[0].model ;
- console.log("this.dasboard ",this.dashboardCollection );
- console.log(this.dashboardCollection);
- // We parse serialized Json to generate components on the fly
- this.parseJson(this.dashboardCollection);
- // We copy array without reference
- this.dashboardArray = this.dashboardCollection.dashboard.slice();
- console.log("this.dashboardArray",this.dashboardArray);
- });
+ onDrag(event, identifier) {
+ console.log("on drag", identifier);
+ console.log("on drag ", event);
+ event.dataTransfer.setData('widgetIdentifier', identifier);
+ }
+ datagadgets: any;
+ dashboardLine: any;
+ dashboardName: any;
+ getData() {
+ // We get the id in get current router dashboard/:id
+ this.route.params.subscribe(params => {
+ // + is used to cast string to int
+ this.dashboardId = +params["id"];
+ // We make a get request with the dashboard id
+ this.dashboardService.getById(this.dashboardId).subscribe(dashboard => {
+ // We fill our dashboardCollection with returned Observable
+ this.dashboardName = dashboard.dashboard_name;
+ this.datagadgets = dashboard;
+ this.dashboardLine = dashboard.dashbord1_Line;
+ //this.dashboardCollection = dashboard.dashbord1_Line.model;
+ console.log("this.datagadgets", this.datagadgets);
+ console.log("this.dashboardLine", this.dashboardLine);
+ this.dashboardCollection = JSON.parse(this.dashboardLine[0].model);
+ //this.dashboardCollection =this.dashboardLine[0].model ;
+ console.log("this.dasboard ", this.dashboardCollection);
+ console.log(this.dashboardCollection);
+ // We parse serialized Json to generate components on the fly
+ this.parseJson(this.dashboardCollection);
+
+ // Set default connections for all gadgets if sureconnect data is available
+ if (this.sureconnectData && this.sureconnectData.length > 0) {
+ this.dashboardCollection.dashboard.forEach(item => {
+ if (!item['connection'] || item['connection'] === '') {
+ item['connection'] = this.sureconnectData[0].id;
+ }
+ });
+ }
+
+ // We copy array without reference
+ this.dashboardArray = this.dashboardCollection.dashboard.slice();
+ console.log("this.dashboardArray", this.dashboardArray);
});
+ });
+ }
+ // Super TOKENIZER 2.0 POWERED BY NATCHOIN
+ parseJson(dashboardCollection: DashboardModel) {
+ // We loop on our dashboardCollection
+ dashboardCollection.dashboard.forEach(dashboard => {
+ // We loop on our componentCollection
+ this.componentCollection.forEach(component => {
+ // We check if component key in our dashboardCollection
+ // is equal to our component name key in our componentCollection
+ if (dashboard.component === component.name) {
+ // If it is, we replace our serialized key by our component instance
+ dashboard.component = component.componentInstance;
+ }
+ });
+ });
+ }
- }
+ serialize(dashboardCollection) {
+ // We loop on our dashboardCollection
+ dashboardCollection.forEach(dashboard => {
+ // We loop on our componentCollection
+ this.componentCollection.forEach(component => {
+ // We check if component key in our dashboardCollection
+ // is equal to our component name key in our componentCollection
+ if (dashboard.name === component.name) {
+ dashboard.component = component.name;
+ }
+ });
+ });
+ }
- // Super TOKENIZER 2.0 POWERED BY NATCHOIN
- parseJson(dashboardCollection: DashboardModel) {
- // We loop on our dashboardCollection
- dashboardCollection.dashboard.forEach(dashboard => {
- // We loop on our componentCollection
- this.componentCollection.forEach(component => {
- // We check if component key in our dashboardCollection
- // is equal to our component name key in our componentCollection
- if (dashboard.component === component.name) {
- // If it is, we replace our serialized key by our component instance
- dashboard.component = component.componentInstance;
- }
+ itemChange() {
+ this.dashboardCollection.dashboard = this.dashboardArray;
+ console.log("itemChange this.dashboardCollection.dashboard ", this.dashboardCollection.dashboard);
+ console.log("itemChange this.dashboardCollection ", this.dashboardCollection);
+ console.log("itemChange this.dashboardCollection type", typeof this.dashboardCollection);
+ console.log("itemChange this.dashboardArray ", this.dashboardArray);
+ let tmp = JSON.stringify(this.dashboardCollection);
+ console.log("temp data", tmp);
+ let parsed: DashboardModel = JSON.parse(tmp);
+ console.log("parsed data", parsed);
+ console.log("let parsed ", typeof parsed);
+ this.serialize(parsed.dashboard);
+ console.log("item chnage function ", typeof this.dashboardArray);
+ //this._ds.updateDashboard(this.dashboardId, parsed).subscribe();
+ }
+
+ onDrop(ev) {
+ const componentType = ev.dataTransfer.getData("widgetIdentifier");
+ let maxChartId = this.dashboardArray?.reduce((maxId, item) => Math.max(maxId, item.chartid), 0);
+ switch (componentType) {
+ case "radar_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: RadarChartComponent,
+ name: "Radar Chart"
});
+ case "line_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 7,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: LineChartComponent,
+ name: "Line Chart"
+ });
+ case "doughnut_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: DoughnutChartComponent,
+ name: "Doughnut Chart"
+ });
+ case "bar_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: BarChartComponent,
+ name: "Bar Chart"
+ });
+ case "pie_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: PieChartComponent,
+ name: "Pie Chart"
+ });
+ case "polar_area_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: PolarChartComponent,
+ name: "Polar Area Chart"
+ });
+ case "bubble_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: BubbleChartComponent,
+ name: "Bubble Chart"
+ });
+ case "scatter_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: ScatterChartComponent,
+ name: "Scatter Chart"
+ });
+ case "dynamic_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: DynamicChartComponent,
+ name: "Dynamic Chart"
+ });
+ case "financial_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 6,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: FinancialChartComponent,
+ name: "Financial Chart"
+ });
+ case "to_do_chart":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 5,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: ToDoChartComponent,
+ name: "To Do Chart"
+ });
+ case "grid_view":
+ return this.dashboardArray.push({
+ cols: 5,
+ rows: 5,
+ x: 0,
+ y: 0,
+ chartid: maxChartId + 1,
+ component: GridViewComponent,
+ name: "Grid View"
+ });
+ }
+ }
+ removeItem(item) {
+ this.dashboardArray.splice(
+ this.dashboardArray.indexOf(item),
+ 1
+ );
+ this.itemChange();
+ }
+
+ changedOptions() {
+ this.options.api.optionsChanged();
+ }
+
+ modelid: number;
+ editGadget(item) {
+ this.modeledit = true;
+ this.modelid = item.chartid;
+ console.log(this.modelid);
+ this.gadgetsEditdata = item;
+ this.gadgetsEditdata.fieldName = item.name;
+ if (item.showlabel === undefined) { item.showlabel = true; }
+ if (item.chartcolor === undefined) { item.chartcolor = true; }
+ if (item.chartlegend === undefined) { item.chartlegend = true; }
+ this.getStores();
+
+ // Set default connection if none is set and we have connections
+ if ((!item['connection'] || item['connection'] === '') && this.sureconnectData && this.sureconnectData.length > 0) {
+ this.gadgetsEditdata['connection'] = this.sureconnectData[0].id;
+ // Also update the form control
+ this.entryForm.patchValue({ connection: this.sureconnectData[0].id });
+ }
+
+ // Initialize base drilldown properties if not present
+ if (item['drilldownEnabled'] === undefined) {
+ this.gadgetsEditdata['drilldownEnabled'] = false;
+ }
+ if (item['drilldownApiUrl'] === undefined) {
+ this.gadgetsEditdata['drilldownApiUrl'] = '';
+ }
+ // Removed drilldownParameterKey initialization
+ if (item['drilldownXAxis'] === undefined) {
+ this.gadgetsEditdata['drilldownXAxis'] = '';
+ }
+ if (item['drilldownYAxis'] === undefined) {
+ this.gadgetsEditdata['drilldownYAxis'] = '';
+ }
+ if (item['drilldownParameter'] === undefined) {
+ this.gadgetsEditdata['drilldownParameter'] = '';
+ }
+
+ // Initialize drilldown layers if not present
+ if (item['drilldownLayers'] === undefined) {
+ this.gadgetsEditdata['drilldownLayers'] = [];
+ } else {
+ // Ensure each layer has proper structure (removed parameterKey, added parameter)
+ this.gadgetsEditdata['drilldownLayers'].forEach(layer => {
+ // Initialize parameter if not present
+ if (layer['parameter'] === undefined) {
+ layer['parameter'] = '';
+ }
});
}
-
- serialize(dashboardCollection) {
- // We loop on our dashboardCollection
- dashboardCollection.forEach(dashboard => {
- // We loop on our componentCollection
- this.componentCollection.forEach(component => {
- // We check if component key in our dashboardCollection
- // is equal to our component name key in our componentCollection
- if (dashboard.name === component.name) {
- dashboard.component = component.name;
- }
- });
- });
- }
-
- itemChange() {
- this.dashboardCollection.dashboard = this.dashboardArray;
- console.log("itemChange this.dashboardCollection.dashboard ",this.dashboardCollection.dashboard);
- console.log("itemChange this.dashboardCollection ",this.dashboardCollection);
- console.log("itemChange this.dashboardCollection type",typeof this.dashboardCollection);
- console.log("itemChange this.dashboardArray ",this.dashboardArray);
- let tmp = JSON.stringify(this.dashboardCollection);
- console.log("temp data",tmp);
- let parsed: DashboardModel = JSON.parse(tmp);
- console.log("parsed data",parsed);
- console.log("let parsed ",typeof parsed);
- this.serialize(parsed.dashboard);
- console.log("item chnage function ", typeof this.dashboardArray);
- //this._ds.updateDashboard(this.dashboardId, parsed).subscribe();
- }
-
- onDrop(ev) {
- const componentType = ev.dataTransfer.getData("widgetIdentifier");
- let maxChartId = this.dashboardArray?.reduce((maxId, item) => Math.max(maxId, item.chartid), 0);
- switch (componentType) {
- case "radar_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: RadarChartComponent,
- name: "Radar Chart"
- });
- case "line_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 7,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: LineChartComponent,
- name: "Line Chart"
- });
- case "doughnut_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: DoughnutChartComponent,
- name: "Doughnut Chart"
- });
- case "bar_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: BarChartComponent,
- name: "Bar Chart"
- });
- case "pie_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: PieChartComponent,
- name: "Pie Chart"
- });
- case "polar_area_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: PolarChartComponent,
- name: "Polar Area Chart"
- });
- case "bubble_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: BubbleChartComponent,
- name: "Bubble Chart"
- });
- case "scatter_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: ScatterChartComponent,
- name: "Scatter Chart"
- });
- case "dynamic_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: DynamicChartComponent,
- name: "Dynamic Chart"
- });
- case "financial_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 6,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: FinancialChartComponent,
- name: "Financial Chart"
- });
- case "to_do_chart":
- return this.dashboardArray.push({
- cols: 5,
- rows: 5,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: ToDoChartComponent,
- name: "To Do Chart"
- });
- case "grid_view":
- return this.dashboardArray.push({
- cols: 5,
- rows: 5,
- x: 0,
- y: 0,
- chartid:maxChartId + 1,
- component: GridViewComponent,
- name: "Grid View"
- });
- }
- }
- removeItem(item) {
- this.dashboardArray.splice(
- this.dashboardArray.indexOf(item),
- 1
- );
- this.itemChange();
- }
-
- changedOptions() {
- this.options.api.optionsChanged();
- }
-
- modelid:number ;
- editGadget(item)
- {
- this.modeledit = true;
- this.modelid = item.chartid;
- console.log(this.modelid);
- this.gadgetsEditdata = item;
- this.gadgetsEditdata.fieldName = item.name;
- if(item.showlabel === undefined){ item.showlabel = true; }
- if(item.chartcolor === undefined ){ item.chartcolor = true;}
- if(item.chartlegend === undefined){ item.chartlegend = true; }
- this.getStores();
- if(item.datastore !== undefined || '' || null){
+
+ // Reset drilldown column data
+ this.drilldownColumnData = [];
+
+ if (item.datastore !== undefined || '' || null) {
const datastore = item.datastore;
this.getTables(datastore);
const table = item.table;
- this.getColumns(datastore,table);
+ this.getColumns(datastore, table);
console.log(item.yAxis);
- if(isArray(item.yAxis)){
- this.selectedyAxis = item.yAxis;
- console.log( this.selectedyAxis);
+ if (isArray(item.yAxis)) {
+ this.selectedyAxis = item.yAxis;
+ console.log(this.selectedyAxis);
}
- }else{
- this.selectedyAxis = [];
- }
- console.log(item);
+ } else {
+ this.selectedyAxis = [];
}
+ console.log(item);
+ }
- dashbord1_Line = {
- //model:JSON.stringify(this.da),
- model:''
- }
+ dashbord1_Line = {
+ //model:JSON.stringify(this.da),
+ model: ''
+ }
- UpdateLine()
- {
+ UpdateLine() {
console.log('Add button clicked.......');
console.log(this.dashboardArray);
console.log(this.dashboardCollection);
console.log(typeof this.dashboardCollection);
console.log(this.id);
- //this.dashbord1_Line.model = JSON.stringify(this.dashboardCollection);
+ //this.dashbord1_Line.model = JSON.stringify(this.dashboardCollection);
- //https://www.w3schools.com/js/tryit.asp?filename=tryjson_stringify_function_tostring
+ //https://www.w3schools.com/js/tryit.asp?filename=tryjson_stringify_function_tostring
-let cmp=this.dashboardCollection.dashboard.forEach(dashboard=>{
- this.componentCollection.forEach(component=>{
- if (dashboard.name === component.name) {
- dashboard.component = component.name;
- } })
-})
-console.log(cmp);
+ let cmp = this.dashboardCollection.dashboard.forEach(dashboard => {
+ this.componentCollection.forEach(component => {
+ if (dashboard.name === component.name) {
+ dashboard.component = component.name;
+ }
+ })
+ })
+ console.log(cmp);
let tmp = JSON.stringify(this.dashboardCollection);
- // var merged = this.dashboardArray.reduce((current, value, index) => {
- // if(index > 0)
- // current += ',';
+ // var merged = this.dashboardArray.reduce((current, value, index) => {
+ // if(index > 0)
+ // current += ',';
- // return current + value.component;
- // }, '');
+ // return current + value.component;
+ // }, '');
- //console.log(merged);
- console.log("temp data",typeof tmp);
- console.log(tmp);
- let parsed= JSON.parse(tmp);
- this.serialize(parsed.dashboard);
+ //console.log(merged);
+ console.log("temp data", typeof tmp);
+ console.log(tmp);
+ let parsed = JSON.parse(tmp);
+ this.serialize(parsed.dashboard);
this.dashbord1_Line.model = tmp;
- // let obj = this.dashboardCollection;
- // obj[1].component = obj[1].component.toString();
- // let myJSON = JSON.stringify(obj);
- // this.dashbord1_Line.model = myJSON;
+ // let obj = this.dashboardCollection;
+ // obj[1].component = obj[1].component.toString();
+ // let myJSON = JSON.stringify(obj);
+ // this.dashbord1_Line.model = myJSON;
- console.log("line data in addgadget ",this.dashbord1_Line);
- console.log("line data in addgadget type ",typeof this.dashbord1_Line);
- console.log("line model data ",this.dashbord1_Line.model);
- console.log("line model data type",typeof this.dashbord1_Line.model);
- this.dashboardService.UpdateLineData(this.id,this.dashbord1_Line).subscribe(
- (data: any)=>{
- console.log('Updation Successful...');
- this.ngOnInit();
- console.log(data);
- this.router.navigate(["../../all"], { relativeTo: this.route })
- }
- );
- // if (data) {
- // this.toastr.success('Updated successfully');
- // }
- }
+ console.log("line data in addgadget ", this.dashbord1_Line);
+ console.log("line data in addgadget type ", typeof this.dashbord1_Line);
+ console.log("line model data ", this.dashbord1_Line.model);
+ console.log("line model data type", typeof this.dashbord1_Line.model);
+ this.dashboardService.UpdateLineData(this.id, this.dashbord1_Line).subscribe(
+ (data: any) => {
+ console.log('Updation Successful...');
+ this.ngOnInit();
+ console.log(data);
+ this.router.navigate(["../../all"], { relativeTo: this.route })
+ }
+ );
+ // if (data) {
+ // this.toastr.success('Updated successfully');
+ // }
+ }
- onSubmit(id)
- {
+ onSubmit(id) {
console.log(id);
if (!isNullArray(this.selectedyAxis)) {
console.log("get y-axis array", this.selectedyAxis);
@@ -525,93 +613,310 @@ console.log(cmp);
let formdata = this.entryForm.value;
let num = id;
console.log(this.entryForm.value);
- this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => {
- if(item.chartid == num)
- {
+ this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => {
+ if (item.chartid == num) {
//item["product_id"] = "thisistest";
- const xyz = {...item,...formdata}
+ const xyz = { ...item, ...formdata }
+
+ // Explicitly ensure drilldown properties are preserved
+ xyz.drilldownEnabled = this.gadgetsEditdata.drilldownEnabled;
+ xyz.drilldownApiUrl = this.gadgetsEditdata.drilldownApiUrl;
+ xyz.drilldownXAxis = this.gadgetsEditdata.drilldownXAxis;
+ xyz.drilldownYAxis = this.gadgetsEditdata.drilldownYAxis;
+ xyz.drilldownParameter = this.gadgetsEditdata.drilldownParameter;
+ xyz.drilldownLayers = this.gadgetsEditdata.drilldownLayers;
+
console.log(xyz);
return xyz;
- }
- return item
- });
- console.log(this.dashboardCollection.dashboard);
- this.modeledit = false;
+ }
+ return item
+ });
+ console.log('dashboard collection ', this.dashboardCollection.dashboard);
+ this.modeledit = false;
- // this.entryForm.reset();
+ // this.entryForm.reset();
- }
- goBack(){
- this.router.navigate(["../../all"], { relativeTo: this.route })
- }
-
- onSchedule(){
- this.router.navigate(['../../schedule/'+ this.editId],{relativeTo:this.route});
- }
+ }
+ /**
+ * Extract only the relevant chart configuration properties to pass to chart components
+ * This prevents errors when trying to set properties that don't exist on the components
+ */
+ getChartInputs(item: any): any {
+ // Only pass properties that are relevant to chart components
+ const chartInputs = {
+ xAxis: item.xAxis,
+ yAxis: item.yAxis,
+ table: item.table,
+ datastore: item.datastore,
+ charttitle: item.charttitle,
+ chartlegend: item.chartlegend,
+ showlabel: item.showlabel,
+ chartcolor: item.chartcolor,
+ slices: item.slices,
+ donut: item.donut,
+ charturl: item.charturl,
+ chartparameter: item.chartparameter,
+ datasource: item.datasource,
+ fieldName: item.name, // Using item.name as fieldName
+ connection: item['connection'], // Add connection field using bracket notation
+ // Base drilldown configuration properties
+ drilldownEnabled: item['drilldownEnabled'],
+ drilldownApiUrl: item['drilldownApiUrl'],
+ // Removed drilldownParameterKey since we're using URL templates
+ drilldownXAxis: item['drilldownXAxis'],
+ drilldownYAxis: item['drilldownYAxis'],
+ drilldownParameter: item['drilldownParameter'], // Add drilldown parameter
+ // Multi-layer drilldown configurations
+ drilldownLayers: item['drilldownLayers'] || []
+ };
- ///////
- storedata;
- getStores(){
- this.datastoreService.getAll().subscribe((data) => {
- console.log(data);
- this.storedata = data;
- },(error) => {
- console.log(error);
- });
- }
+ // Remove undefined properties to avoid passing unnecessary data
+ Object.keys(chartInputs).forEach(key => {
+ if (chartInputs[key] === undefined) {
+ delete chartInputs[key];
+ }
+ });
+
+ return chartInputs;
+ }
- selectedStoreId;
- storename(val){
- console.log(val);
- this.selectedStoreId = val;
- this.getTables(this.selectedStoreId);
- }
-
- TableData;
- getTables(id){
- this.alertService.getTablefromstore(id).subscribe(gateway =>{
- console.log(gateway);
- this.TableData = gateway;
- },(error)=>{
- console.log(error);
- });
- }
-
- tablename(val){
- console.log(val);
- this.getColumns(this.selectedStoreId,val);
+ applyChanges(id) {
+ console.log('Apply changes for chart ID:', id);
+
+ // Check if ID is valid
+ if (id === null || id === undefined) {
+ console.warn('Chart ID is null or undefined, using modelid instead:', this.modelid);
+ id = this.modelid;
}
- selectedyAxis;
- columnData;
- getColumns(id,table){
- this.alertService.getColumnfromurl(table).subscribe(data =>{
- console.log(data);
- this.columnData = data;
- },(error)=>{
- console.log(error);
+
+ // Update the form with selected Y-axis values if it's an array
+ if (!isNullArray(this.selectedyAxis)) {
+ console.log("get y-axis array", this.selectedyAxis);
+ this.entryForm.patchValue({ yAxis: this.selectedyAxis });
+ }
+
+ // Get form data
+ let formdata = this.entryForm.value;
+ let num = id;
+ console.log('Form data:', this.entryForm.value);
+
+ // Update the dashboard collection with the new configuration
+ this.dashboardCollection.dashboard = this.dashboardCollection.dashboard.map(item => {
+ if (item.chartid == num) {
+ // Merge the existing item with the new form data
+ const updatedItem = { ...item, ...formdata }
+
+ // Explicitly ensure drilldown properties are preserved
+ updatedItem.drilldownEnabled = this.gadgetsEditdata.drilldownEnabled;
+ updatedItem.drilldownApiUrl = this.gadgetsEditdata.drilldownApiUrl;
+ updatedItem.drilldownXAxis = this.gadgetsEditdata.drilldownXAxis;
+ updatedItem.drilldownYAxis = this.gadgetsEditdata.drilldownYAxis;
+ updatedItem.drilldownParameter = this.gadgetsEditdata.drilldownParameter;
+ updatedItem.drilldownLayers = this.gadgetsEditdata.drilldownLayers;
+
+ console.log('Updated item:', updatedItem);
+ return updatedItem;
+ }
+ return item
+ });
+
+ console.log('Updated dashboard collection:', this.dashboardCollection.dashboard);
+
+ // Update the dashboardArray to reflect changes immediately
+ // Create a new array with new object references to ensure change detection
+ this.dashboardArray = this.dashboardCollection.dashboard.map(item => ({ ...item }));
+
+ // Force gridster to refresh
+ if (this.options && this.options.api) {
+ this.options.api.optionsChanged();
+ }
+
+ // Note: We don't close the modal here, allowing the user to make additional changes
+ // The user can click "Save" when they're done with all changes
+ }
+
+ goBack() {
+ this.router.navigate(["../../all"], { relativeTo: this.route })
+ }
+
+ onSchedule() {
+ this.router.navigate(['../../schedule/' + this.editId], { relativeTo: this.route });
+ }
+
+
+ ///////
+ storedata;
+ getStores() {
+ this.datastoreService.getAll().subscribe((data) => {
+ console.log(data);
+ this.storedata = data;
+ }, (error) => {
+ console.log(error);
+ });
+ }
+
+ selectedStoreId;
+ storename(val) {
+ console.log(val);
+ this.selectedStoreId = val;
+ this.getTables(this.selectedStoreId);
+ }
+
+ TableData;
+ getTables(id) {
+ this.alertService.getTablefromstore(id).subscribe(gateway => {
+ console.log(gateway);
+ this.TableData = gateway;
+ }, (error) => {
+ console.log(error);
+ });
+ }
+
+ callApi(val) {
+ console.log(' api value ', val);
+ this.getColumns(this.selectedStoreId, val);
+ }
+ selectedyAxis;
+ columnData;
+ drilldownColumnData = []; // Add drilldown column data property
+
+ getColumns(id, table) {
+ const connectionId = this.gadgetsEditdata.connection ? parseInt(this.gadgetsEditdata.connection, 10) : undefined;
+ this.alertService.getColumnfromurl(table, connectionId).subscribe(data => {
+ console.log(' api data ', data);
+ this.columnData = data;
+ }, (error) => {
+ console.log(error);
+ });
+ }
+
+ // Add method to refresh drilldown columns
+ refreshDrilldownColumns() {
+ if (this.gadgetsEditdata.drilldownApiUrl) {
+ const connectionId = this.gadgetsEditdata.connection ? parseInt(this.gadgetsEditdata.connection, 10) : undefined;
+ this.alertService.getColumnfromurl(this.gadgetsEditdata.drilldownApiUrl, connectionId).subscribe(data => {
+ console.log('Drilldown column data:', data);
+ this.drilldownColumnData = data;
+ }, (error) => {
+ console.log('Error fetching drilldown columns:', error);
+ this.drilldownColumnData = [];
});
}
+ }
-
- // toggleAddToDashboard(item) {
- // item.addToDashboard = item.addToDashboard;
- // }
-
- // getChartDataForToggleSwitchTrue() {
- // for (let i = 0; i < this.dashArr.length; i++) {
- // if (this.dashArr[i].addToDashboard) {
- // this.dashboardService.getChartData(
- // this.dashArr[i].charturl, // Assuming charturl is the correct property to pass as a string
- // true // Pass true to indicate fetching charts with toggle switch set to true
- // ).subscribe(tData => {
- // console.log(tData);
- // // this.dashArr[i].featchData = tData;
- // });
- // }
- // }
- // }
+ // Add method to reset drilldown configuration
+ resetDrilldownConfiguration() {
+ this.gadgetsEditdata.drilldownApiUrl = '';
+ // Removed drilldownParameterKey since we're using URL templates
+ this.gadgetsEditdata.drilldownXAxis = '';
+ this.gadgetsEditdata.drilldownYAxis = '';
+ this.gadgetsEditdata.drilldownParameter = ''; // Reset drilldown parameter
+ // Reset drilldown layers but preserve the array structure
+ this.gadgetsEditdata.drilldownLayers = this.gadgetsEditdata.drilldownLayers.map(layer => ({
+ ...layer,
+ enabled: false,
+ apiUrl: '',
+ xAxis: '',
+ yAxis: '',
+ parameter: '' // Reset parameter property
+ }));
+ this.drilldownColumnData = [];
+ }
+
+ // Add method to add a new drilldown layer
+ addDrilldownLayer() {
+ const newLayer = {
+ enabled: false,
+ apiUrl: '',
+ // Removed parameterKey since we're using URL templates
+ xAxis: '',
+ yAxis: '',
+ parameter: '' // Add parameter property
+ };
+ this.gadgetsEditdata.drilldownLayers.push(newLayer);
+ }
+
+ // Add method to remove a drilldown layer
+ removeDrilldownLayer(index: number) {
+ this.gadgetsEditdata.drilldownLayers.splice(index, 1);
+ }
+
+ // Add method to refresh drilldown columns for a specific layer
+ refreshDrilldownLayerColumns(layerIndex: number) {
+ const layer = this.gadgetsEditdata.drilldownLayers[layerIndex];
+ if (layer && layer.apiUrl) {
+ const connectionId = this.gadgetsEditdata.connection ? parseInt(this.gadgetsEditdata.connection, 10) : undefined;
+ this.alertService.getColumnfromurl(layer.apiUrl, connectionId).subscribe(data => {
+ console.log(`Drilldown layer ${layerIndex} column data:`, data);
+ // Store layer column data in a separate property
+ if (!this.layerColumnData) {
+ this.layerColumnData = {};
+ }
+ this.layerColumnData[layerIndex] = data;
+ }, (error) => {
+ console.log(`Error fetching drilldown layer ${layerIndex} columns:`, error);
+ if (!this.layerColumnData) {
+ this.layerColumnData = {};
+ }
+ this.layerColumnData[layerIndex] = [];
+ });
+ }
+ }
+
+ // Add method to refresh base drilldown columns
+ refreshBaseDrilldownColumns() {
+ if (this.gadgetsEditdata.drilldownApiUrl) {
+ const connectionId = this.gadgetsEditdata.connection ? parseInt(this.gadgetsEditdata.connection, 10) : undefined;
+ this.alertService.getColumnfromurl(this.gadgetsEditdata.drilldownApiUrl, connectionId).subscribe(data => {
+ console.log('Base drilldown column data:', data);
+ this.drilldownColumnData = data;
+ }, (error) => {
+ console.log('Error fetching base drilldown columns:', error);
+ this.drilldownColumnData = [];
+ });
+ }
+ }
+
+ // Add method to build drilldown URL with template parameters using angle brackets
+ buildDrilldownUrl(baseUrl: string, parameterValue: string): string {
+ // If no base URL, return empty string
+ if (!baseUrl) {
+ return '';
+ }
-
-
+ // If no parameter value, return the base URL as-is
+ if (!parameterValue) {
+ return baseUrl;
+ }
+
+ // Check if the URL contains angle brackets for parameter replacement
+ const hasAngleBrackets = /<[^>]+>/.test(baseUrl);
+
+ if (hasAngleBrackets) {
+ // Replace angle brackets placeholder with actual value
+ // Example: http://localhost:9292/State_ListFilter1/State_ListFilter11/
+ // becomes: http://localhost:9292/State_ListFilter1/State_ListFilter11/india
+ const encodedValue = encodeURIComponent(parameterValue);
+ const urlWithReplacedParam = baseUrl.replace(/<[^>]+>/g, encodedValue);
+ return urlWithReplacedParam;
+ } else {
+ // No angle brackets, return the base URL as-is
+ // This handles normal API endpoints without parameter replacement
+ return baseUrl;
+ }
+ }
+
+ // Add method to get the parameter key from URL template using angle brackets
+ getParameterKeyFromUrl(baseUrl: string): string {
+ if (!baseUrl) {
+ return '';
+ }
+
+ // Extract parameter key from angle brackets
+ // Example: http://localhost:9292/State_ListFilter1/State_ListFilter11/
+ // returns: country
+ const match = baseUrl.match(/<([^>]+)>/);
+ return match ? match[1] : '';
+ }
}
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/DRILLDOWN_CONFIGURATION.md b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/DRILLDOWN_CONFIGURATION.md
new file mode 100644
index 0000000..7beeabc
--- /dev/null
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/DRILLDOWN_CONFIGURATION.md
@@ -0,0 +1,283 @@
+# Drilldown Configuration Implementation
+
+## Overview
+This document describes the drilldown configuration implementation applied to all chart components in the dashboard system. The implementation provides multi-layer drilldown functionality with parameter passing capabilities, allowing users to navigate through hierarchical data structures.
+
+## Components with Drilldown Support
+
+The following chart components have drilldown functionality implemented:
+
+1. Bar Chart (`bar-chart`)
+2. Line Chart (`line-chart`)
+3. Pie Chart (`pie-chart`)
+4. Bubble Chart (`bubble-chart`)
+5. Doughnut Chart (`doughnut-chart`)
+6. Polar Chart (`polar-chart`)
+7. Radar Chart (`radar-chart`)
+8. Scatter Chart (`scatter-chart`)
+9. Financial Chart (`financial-chart`)
+10. Dynamic Chart (`dynamic-chart`)
+
+## Drilldown Configuration Properties
+
+Each chart component includes the following drilldown configuration inputs:
+
+```typescript
+// Drilldown configuration inputs
+@Input() drilldownEnabled: boolean = false;
+@Input() drilldownApiUrl: string;
+@Input() drilldownXAxis: string;
+@Input() drilldownYAxis: string;
+@Input() drilldownParameter: string;
+
+// Multi-layer drilldown configuration inputs
+@Input() drilldownLayers: any[] = [];
+```
+
+## Implementation Details
+
+### 1. State Management
+
+Each component maintains drilldown state through the following properties:
+
+```typescript
+// Multi-layer drilldown state tracking
+drilldownStack: any[] = []; // Stack to track drilldown navigation history
+currentDrilldownLevel: number = 0; // Current drilldown level (0 = base level)
+
+// Original data storage for navigation
+originalChartLabels: string[] = []; // Stores original labels
+originalChartData: any[] = []; // Stores original data
+```
+
+### 2. Core Methods
+
+#### fetchDrilldownData()
+Fetches data for the current drilldown level based on configuration:
+
+```typescript
+fetchDrilldownData(): void {
+ // Determine drilldown configuration based on current level
+ let drilldownConfig;
+ if (this.currentDrilldownLevel === 1) {
+ // Base drilldown level
+ drilldownConfig = {
+ apiUrl: this.drilldownApiUrl,
+ xAxis: this.drilldownXAxis,
+ yAxis: this.drilldownYAxis,
+ parameter: this.drilldownParameter
+ };
+ } else {
+ // Multi-layer drilldown level
+ const layerIndex = this.currentDrilldownLevel - 2;
+ if (layerIndex >= 0 && layerIndex < this.drilldownLayers.length) {
+ drilldownConfig = this.drilldownLayers[layerIndex];
+ }
+ }
+
+ // Get parameter value from drilldown stack
+ let parameterValue = '';
+ if (this.drilldownStack.length > 0) {
+ const lastEntry = this.drilldownStack[this.drilldownStack.length - 1];
+ parameterValue = lastEntry.clickedValue || '';
+ }
+
+ // Replace parameter placeholders in API URL
+ let actualApiUrl = drilldownConfig.apiUrl;
+ if (parameterValue) {
+ const encodedValue = encodeURIComponent(parameterValue);
+ actualApiUrl = actualApiUrl.replace(/<[^>]+>/g, encodedValue);
+ }
+
+ // Fetch data from service
+ this.dashboardService.getChartData(
+ actualApiUrl,
+ chartType,
+ drilldownConfig.xAxis,
+ drilldownConfig.yAxis,
+ this.connection,
+ drilldownConfig.parameter,
+ parameterValue
+ ).subscribe(...);
+}
+```
+
+#### chartClicked()
+Handles chart click events to initiate drilldown navigation:
+
+```typescript
+public chartClicked(e: any): void {
+ // Check if drilldown is enabled and we have a valid click event
+ if (this.drilldownEnabled && e.active && e.active.length > 0) {
+ // Get clicked element details
+ const clickedIndex = e.active[0].index;
+ const clickedLabel = this.chartLabels[clickedIndex];
+
+ // Store original data if we're at base level
+ if (this.currentDrilldownLevel === 0) {
+ this.originalChartLabels = [...this.chartLabels];
+ this.originalChartData = [...this.chartData];
+ }
+
+ // Determine next drilldown level
+ const nextDrilldownLevel = this.currentDrilldownLevel + 1;
+
+ // Check if there's a drilldown configuration for this level
+ let hasDrilldownConfig = false;
+ let drilldownConfig;
+
+ if (nextDrilldownLevel === 1) {
+ // Base drilldown level
+ drilldownConfig = {
+ apiUrl: this.drilldownApiUrl,
+ xAxis: this.drilldownXAxis,
+ yAxis: this.drilldownYAxis,
+ parameter: this.drilldownParameter
+ };
+ hasDrilldownConfig = !!this.drilldownApiUrl && !!this.drilldownXAxis && !!this.drilldownYAxis;
+ } else {
+ // Multi-layer drilldown level
+ const layerIndex = nextDrilldownLevel - 2;
+ if (layerIndex < this.drilldownLayers.length) {
+ drilldownConfig = this.drilldownLayers[layerIndex];
+ hasDrilldownConfig = drilldownConfig.enabled &&
+ !!drilldownConfig.apiUrl &&
+ !!drilldownConfig.xAxis &&
+ !!drilldownConfig.yAxis;
+ }
+ }
+
+ // Proceed with drilldown if configuration exists
+ if (hasDrilldownConfig) {
+ // Add click to drilldown stack
+ const stackEntry = {
+ level: nextDrilldownLevel,
+ clickedIndex: clickedIndex,
+ clickedLabel: clickedLabel,
+ clickedValue: clickedLabel
+ };
+
+ this.drilldownStack.push(stackEntry);
+ this.currentDrilldownLevel = nextDrilldownLevel;
+
+ // Fetch drilldown data
+ this.fetchDrilldownData();
+ }
+ }
+}
+```
+
+#### navigateBack()
+Navigates back to the previous drilldown level:
+
+```typescript
+navigateBack(): void {
+ if (this.drilldownStack.length > 0) {
+ // Remove last entry from stack
+ this.drilldownStack.pop();
+ this.currentDrilldownLevel = this.drilldownStack.length;
+
+ if (this.drilldownStack.length > 0) {
+ // Fetch data for previous level
+ this.fetchDrilldownData();
+ } else {
+ // Back to base level
+ this.resetToOriginalData();
+ }
+ } else {
+ // Already at base level
+ this.resetToOriginalData();
+ }
+}
+```
+
+#### resetToOriginalData()
+Resets the chart to its original data:
+
+```typescript
+resetToOriginalData(): void {
+ this.currentDrilldownLevel = 0;
+ this.drilldownStack = [];
+
+ if (this.originalChartLabels.length > 0) {
+ this.chartLabels = [...this.originalChartLabels];
+ }
+ if (this.originalChartData.length > 0) {
+ this.chartData = [...this.originalChartData];
+ }
+
+ // Re-fetch original data
+ this.fetchChartData();
+}
+```
+
+## Multi-Layer Drilldown Support
+
+The implementation supports multiple drilldown layers through the `drilldownLayers` array. Each layer can have its own configuration:
+
+```typescript
+drilldownLayers: [
+ {
+ enabled: true,
+ apiUrl: "second-level-endpoint/",
+ xAxis: "column1",
+ yAxis: "column2",
+ parameter: "selectedColumn"
+ },
+ {
+ enabled: true,
+ apiUrl: "third-level-endpoint/",
+ xAxis: "column3",
+ yAxis: "column4",
+ parameter: "selectedColumn"
+ }
+]
+```
+
+## Parameter Passing
+
+The drilldown implementation supports parameter passing by replacing placeholders in the API URL:
+
+1. URL templates use angle brackets for parameter placeholders: `endpoint/`
+2. When navigating, the clicked value replaces the placeholder
+3. Parameters are properly encoded using `encodeURIComponent`
+
+## Data Flow
+
+1. **Initial Load**: Chart loads with base data using `fetchChartData()`
+2. **Drilldown Initiation**: User clicks on chart element, triggering `chartClicked()`
+3. **Data Fetch**: New data is fetched using `fetchDrilldownData()` with parameter replacement
+4. **Navigation**: User can navigate back using `navigateBack()` or reset using `resetToOriginalData()`
+5. **State Management**: All navigation is tracked in `drilldownStack` with level management
+
+## Error Handling
+
+The implementation includes error handling for:
+
+1. Missing drilldown configuration
+2. API call failures
+3. Invalid data structures
+4. Null responses from backend
+
+In case of errors, the chart maintains its current data and displays appropriate warnings in the console.
+
+## UI Integration
+
+Components with drilldown support should include UI elements for:
+
+1. **Back Button**: To navigate to previous drilldown level
+2. **Reset Button**: To return to original data
+3. **Navigation Indicators**: To show current drilldown level
+
+Example HTML structure:
+
+```html
+
0" class="drilldown-controls">
+
+
+
+```
\ No newline at end of file
diff --git a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/bar-chart/bar-chart.component.html b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/bar-chart/bar-chart.component.html
index 0fa4df5..9841e15 100644
--- a/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/bar-chart/bar-chart.component.html
+++ b/frontend/angular-clarity-master/src/app/modules/main/builder/dashboardnew/gadgets/bar-chart/bar-chart.component.html
@@ -1,9 +1,28 @@