Use Case: In this document we are going to cover how to implement a specific use case in which a dashboard is created with certain panels. Then based on the logged role of the person, the dashboard will show some reports to some users, other set of reports to other role. In a similar way this method can also be implemented for organization, profile etc as well.

Implementation Steps:

  1. When creating the dashboard, set up all the reports that are going to be present in the dashboard, irrespective of which role the user belongs to.
  2. The number of reports visible at a time can be maximum up to all the reports that are added while creating dashboard
  3. Create the dashboard with all the reports that needs to displayed.
  4. Now right click on empty space on dashboard and select option Advance and go to JS section
  5. Paste the below given code in JS Editor , tick the Enable button and click on Apply button.

Code :


var reportDivIds = ['#html-item-pYOvN','#html-item-hp8DH','#html-item-JZFZp','#html-item-NZ2kG' , '#html-item-zfCrQ'];

var removedDivs = {};

var roles_reports_obj = {
	'ROLE_ADMIN' : ['#html-item-pYOvN','#html-item-hp8DH','#html-item-JZFZp','#html-item-NZ2kG' , '#html-item-zfCrQ'],
	'ROLE_USER' : ['#html-item-zfCrQ' , '#html-item-NZ2kG'],
	'ROLE_VIEWER' : ['#html-item-JZFZp']
}

var reports_to_display = [];

const stylesObj = {};

let roles_of_current_user = [];

function positionTracker(){
	const items = document.querySelectorAll('.react-grid-item.grid-item');
	items.forEach((el, index) => {
	  stylesObj[index + 1] = el.getAttribute('style') || '';
	});
	console.log(stylesObj);
}

const removeReportsPromise = () => {
  return new Promise((resolve) => {
    const result = removeReports();
    if (result) {
      resolve();
    } else {
      setTimeout(resolve, 1000);
    }
  });
};

const roleFetching = async () => {
  const stores = new Set();
  const traverse = (element) => {
    let store =
      element?.memoizedState?.element?.props?.store
      || element?.pendingProps?.store
      || element?.stateNode?.store;

    if (store) {
      stores.add(store);
    }

    if (element.child) {
      traverse(element.child);
    }
  };
  const reactRoot = Array.from(document.querySelectorAll("*[id]")).find((el) => el?._reactRootContainer?._internalRoot?.current);
  const internalRoot = reactRoot._reactRootContainer._internalRoot.current;
  traverse(internalRoot);

  let loggedInUserDetails = [...stores][0].getState().app.applicationSettingsData.userData.user
  roles_of_current_user = loggedInUserDetails.roles ; 
  
  roles_of_current_user.forEach(function(role) {
	  if (roles_reports_obj[role]) {
		  console.log(roles_reports_obj[role] , 'roles_reports_obj[role]');
		reports_to_display = reports_to_display.concat(roles_reports_obj[role]);
	  }
	});
	
	 reports_to_display = [...new Set(reports_to_display)];
	 
	 reports_to_display.sort((a, b) => {
	  return reportDivIds.indexOf(a) - reportDivIds.indexOf(b);
	});
	 
	 setTimeout(() =>{
		addReportsBack() 
	 },1000)
}

function addReportsBack() {
  console.log(reports_to_display, 'reports_to_display');
  reports_to_display.forEach(function(selector, index) {
    var div = document.querySelector(selector);
    if (!div && removedDivs[selector.substring(6)]) {
      var restoredDiv = removedDivs[selector.substring(6)];
      const styleString = stylesObj[String(index + 1)];
      if (styleString) {
        styleString.split(';').forEach((styleRule) => {
          const [property, value] = styleRule.split(':').map(s => s && s.trim());
          if (property && value) {
            restoredDiv.style[property] = value;
          }
        });
      }
      document.querySelector('.react-grid-layout.layout').appendChild(restoredDiv);
      div = document.querySelector(selector);
    }
  });
}

function removeReports(){
  reportDivIds.forEach(function(selector) {
    var div = document.querySelector(selector);
    if (div) {
      var removableDiv = document.getElementById(selector.substring(6));
      console.log(removableDiv, 'removableDiv');
      removableDiv.style.position = '';
      removableDiv.style.left = '';
      removableDiv.style.top = '';
      removableDiv.style.right = '';
      removableDiv.style.bottom = '';
      removableDiv.style.width = '';
      removableDiv.style.height = '';
      removedDivs[removableDiv.id] = removableDiv;
      removableDiv.remove();
    }
  });
  layoutHeightAdjusting()
  return true ;
}

setTimeout(() =>{
  positionTracker();
  removeReportsPromise();
},1000)

function layoutHeightAdjusting(){
  var layout = document.querySelector('.react-grid-layout.layout');
  if (layout) {
    layout.setAttribute('style', 'height: auto !important');
  }
}

window.addEventListener('resize', function() {
  layoutHeightAdjusting()
});

roleFetching()
  

Code Explanation and Changes :

The above code handles the complete functionality for displaying reports dynamically. However, you may need to make a few adjustments to ensure it works with your specific dashboard setup.

Change 1 :


var reportDivIds = ['#html-item-pYOvN','#html-item-hp8DH','#html-item-JZFZp','#html-item-NZ2kG' , '#html-item-zfCrQ'];
  

Here reportDivIds holds all the ids of the all the reports that are present on the dashboard. Replace them with your reports id’s. You can get a specific id of a report by following below steps.

  • Right click on the report and go to CSS section from Advance options. There you can see Component Id of the reports. That is the Id we are looking for. There is a copy button as well which can be used.
  • Make sure to prefix each ID with #html-, as shown in the sample entries.
  • Paste them in the same sequence you want the reports to appear on the dashboard.

Change 2 :


var roles_reports_obj = {
	'ROLE_ADMIN' : ['#html-item-pYOvN','#html-item-hp8DH','#html-item-JZFZp','#html-item-NZ2kG' , '#html-item-zfCrQ'],
	'ROLE_USER' : ['#html-item-zfCrQ' , '#html-item-NZ2kG'],
	'ROLE_VIEWER' : ['#html-item-JZFZp']
}
  
  • This object is mapping of role and the reports that he is going to see. From the above sample you can ‘ROLE_ADMIN’ can view all the reports so we have mentioned all the report id’s here. Whereas ‘ROLE_USER’ can only see two report, so he has only 2 report id’s. Similarly ‘ROLE_VIEWER’ has got access to only one report
  • You can modify this as per your requirements.

Code Responsible for fetching Roles (No changes required) :


const roleFetching = async () => {
  const stores = new Set();
  const traverse = (element) => {
    let store =
      element?.memoizedState?.element?.props?.store
      || element?.pendingProps?.store
      || element?.stateNode?.store;

    if (store) {
      stores.add(store);
    }

    if (element.child) {
      traverse(element.child);
    }
  };
  const reactRoot = Array.from(document.querySelectorAll("*[id]")).find((el) => el?._reactRootContainer?._internalRoot?.current);
  const internalRoot = reactRoot._reactRootContainer._internalRoot.current;
  traverse(internalRoot);

  let loggedInUserDetails = [...stores][0].getState().app.applicationSettingsData.userData.user
  roles_of_current_user = loggedInUserDetails.roles ; 
  
  roles_of_current_user.forEach(function(role) {
	  if (roles_reports_obj[role]) {
		  console.log(roles_reports_obj[role] , 'roles_reports_obj[role]');
		reports_to_display = reports_to_display.concat(roles_reports_obj[role]);
	  }
	});
	
	 reports_to_display = [...new Set(reports_to_display)];
	 
	 reports_to_display.sort((a, b) => {
	  return reportDivIds.indexOf(a) - reportDivIds.indexOf(b);
	});
	 
	 setTimeout(() =>{
		addReportsBack() 
	 },1000)
}
  

This function is responsible for fetching roles of the currently logged in user which are defined while creating the user.

Functionality of the Entire Code :

  • When the dashboard is opened, the roleFetching() function is triggered, which calls all other functions. This includes removing reports and adding them back based on the currently logged-in user.
  • While removing reports, we strip all position-related styling and store them in another object. The key of this object is the sequence in which the report IDs appear in reportDivIds. After this, all removed reports are moved to removedDivs.
  • When adding the reports back based on the role, we assign the position styling to each report based on the order they will appear on the screen.
  • For example, if a ROLE_USER is meant to see the reports starting from the 2nd report in the full list of report IDs, the 2nd report will get the styling of the first report (position, height, width), the 3rd report will get the styling of the 2nd report, and so on. This ensures there is no gap at the beginning or in between the reports.

Leave a Reply

Helical Insight’s self-service capabilities is one to reckon with. It allows you to simply drag and drop columns, add filters, apply aggregate functions if required, and create reports and dashboards on the fly. For advanced users, the self-service component has ability to add javascript, HTML, HTML5, CSS, CSS3 and AJAX. These customizations allow you to create dynamic reports and dashboards. You can also add new charts inside the self-service component, add new kind of aggregate functions and customize it using our APIs.
Helical Insight’s self-service capabilities is one to reckon with. It allows you to simply drag and drop columns, add filters, apply aggregate functions if required, and create reports and dashboards on the fly. For advanced users, the self-service component has ability to add javascript, HTML, HTML5, CSS, CSS3 and AJAX. These customizations allow you to create dynamic reports and dashboards. You can also add new charts inside the self-service component, add new kind of aggregate functions and customize it using our APIs.
Helical Insight, via simple browser based interface of Canned Reporting module, also allows to create pixel perfect printer friendly document kind of reports also like Invoice, P&L Statement, Balance sheet etc.
Helical Insight, via simple browser based interface of Canned Reporting module, also allows to create pixel perfect printer friendly document kind of reports also like Invoice, P&L Statement, Balance sheet etc.
If you have a product, built on any platform like Dot Net or Java or PHP or Ruby, you can easily embed Helical Insight within it using iFrames or webservices, for quick value add through instant visualization of data.
If you have a product, built on any platform like Dot Net or Java or PHP or Ruby, you can easily embed Helical Insight within it using iFrames or webservices, for quick value add through instant visualization of data.
Being a 100% browser-based BI tool, you can connect with your database and analyse across any location and device. There is no need to download or install heavy memory-consuming developer tools – All you need is a Browser application! We are battle-tested on most of the commonly used browsers.
Being a 100% browser-based BI tool, you can connect with your database and analyse across any location and device. There is no need to download or install heavy memory-consuming developer tools – All you need is a Browser application! We are battle-tested on most of the commonly used browsers.
We have organization level security where the Superadmin can create, delete and modify roles. Dashboards and reports can be added to that organization. This ensures multitenancy.
We have organization level security where the Superadmin can create, delete and modify roles. Dashboards and reports can be added to that organization. This ensures multitenancy.
We have organization level security where the Superadmin can create, delete and modify roles. Dashboards and reports can be added to that organization. This ensures multitenancy.
We have organization level security where the Superadmin can create, delete and modify roles. Dashboards and reports can be added to that organization. This ensures multitenancy.
A first-of-its-kind Open-Source BI framework, Helical Insight is completely API-driven. This allows you to add functionalities, including but not limited to adding a new exporting type, new datasource type, core functionality expansion, new charting in adhoc etc., at any place whenever you wish, using your own in-house developers.
A first-of-its-kind Open-Source BI framework, Helical Insight is completely API-driven. This allows you to add functionalities, including but not limited to adding a new exporting type, new datasource type, core functionality expansion, new charting in adhoc etc., at any place whenever you wish, using your own in-house developers.
It handles huge volumes of data effectively. Caching, Pagination, Load-Balancing and In-Memory not only provides you with amazing experience, but also and does not burden the database server more than required. Further effective use of computing power gives best performance and complex calculations even on the big data even with smaller machines for your personal use. Filtering, Sorting, Cube Analysis, Inter Panel Communication on the dashboards all at lightning speed. Thereby, making best open-source Business Intelligence solution in the market.
It handles huge volumes of data effectively. Caching, Pagination, Load-Balancing and In-Memory not only provides you with amazing experience, but also and does not burden the database server more than required. Further effective use of computing power gives best performance and complex calculations even on the big data even with smaller machines for your personal use. Filtering, Sorting, Cube Analysis, Inter Panel Communication on the dashboards all at lightning speed. Thereby, making best open-source Business Intelligence solution in the market.
With advance NLP algorithm, business users simply ask questions like, “show me sales of last quarter”, “average monthly sales of my products”. Let the application give the power to users without knowledge of query language or underlying data architecture
With advance NLP algorithm, business users simply ask questions like, “show me sales of last quarter”, “average monthly sales of my products”. Let the application give the power to users without knowledge of query language or underlying data architecture
Our application is compatible with almost all databases, be it RDBMS, or columnar database, or even flat files like spreadsheets or csv files. You can even connect to your own custom database via JDBC connection. Further, our database connection can be switched dynamically based on logged in users or its organization or other parameters. So, all your clients can use the same reports and dashboards without worrying about any data security breech.
Our application is compatible with almost all databases, be it RDBMS, or columnar database, or even flat files like spreadsheets or csv files. You can even connect to your own custom database via JDBC connection. Further, our database connection can be switched dynamically based on logged in users or its organization or other parameters. So, all your clients can use the same reports and dashboards without worrying about any data security breech.
Our application can be installed on an in-house server where you have full control of your data and its security. Or on cloud where it is accessible to larger audience without overheads and maintenance of the servers. One solution that works for all.
Our application can be installed on an in-house server where you have full control of your data and its security. Or on cloud where it is accessible to larger audience without overheads and maintenance of the servers. One solution that works for all.
Different companies have different business processes that the existing BI tools do not encompass. Helical Insight permits you to design your own workflows and specify what functional module of BI gets triggered
Different companies have different business processes that the existing BI tools do not encompass. Helical Insight permits you to design your own workflows and specify what functional module of BI gets triggered