Skip to end of metadata
Go to start of metadata

SonarQube provides the ability to add a new Javascript page to the UI since SonarQube 6.3 (the prior mechanism relying on Ruby was dropped in 6.1). A page (or page extension) is a Javascript application that runs in the SonarQube environment.

You can find the example of page extensions in the SonarQube or sonar-custom-plugin-example repositories on GitHub. For versions prior to 6.3, please see the example based on Ruby on Rails.

Getting started

Page Key Format

The page key should have the format plugin_key/page_id. Example: governance/project_dump. The plugin_key is computed from your <artifactId> or can be set using the <pluginKey> parameter in sonar-packaging-maven-plugin configuration.

Step 1. Create a Java class implementing PageDefinition

All the pages should be declared in this class. 


public class MyPluginPageDefinition implements PageDefinition {
  public void define(Context context) {
      .addPage(Page.builder("my_plugin/my_page").setName("My Page").build())
      .addPage(Page.builder("my_plugin/another_page").setName("Another Page").build());

Step 2. Create a Javascript file

This file should have the same name as the page key (my_page.js in this case) and should be located in src/main/resources/static.

window.registerExtension('my_plugin/my_page', function (options) {
  options.el.textContent = 'This is my page!';
  return function () {
    options.el.textContent = '';

Where my_plugin/my_page is the same page key specified in step 1.

Configuring page

There are 3 settings available when you define the page extensions using the PageDefinition class:

  • isAdmin: tells if the page should be restricted to user with the administer permission.
  • scope: tells if the page should be displayed in the primary menu (GLOBAL scope) or inside a component page (COMPONENT scope). By default, a page is global. Since 6.4, the ORGANIZATION scope is added.
  • component qualifiers: allows you to specify if the page should be displayed for PROJECT, MODULE, VIEW or SUB_VIEW (two last comes with the Enterprise Edition). If set, the scope of the page must be COMPONENT.

Runtime environment

SonarQube provides a global function registerExtension which should be called from the main javascript file. The function accepts two parameters:

  • page extension key, which has a form of <plugin key>/<page key> (Ex: governance/project_dump)
  • callback function, which is executed when the page extension is loaded. This callback should return another function, which will be called once the page extension will be closed. The callback accepts a single parameter options containing: 
    • options.el is a DOM element you must use to put the content inside
    • options.currentUser contains the response of api/users/current (see Web API docs for details)
    • (optional) options.component contains the information of the current project or view, if the page is project-level: key, name and qualifier

Please have a look to the Making Ajax Request page to learn how to fetch the data from the server.

Note that SonarQube doesn't guarantee any Javascript libraries available at runtime. If you need some, include them in the final file.


Displaying the number of project issues

window.registerExtension('my_plugin/my_page', function (options) {

  // let's create a flag telling if the page is still displayed
  var isDisplayed = true;

  // then do a Web API call to the /api/issues/search to get the number of issues
  // we pass `resolved: false` to request only unresolved issues
  // and `componentKeys: options.component.key` to request issues of the given project
  window.SonarRequest.getJSON('/api/issues/search', {
    resolved: false,
    componentKeys: options.component.key
  }).then(function (response) {

    // once the request is done, and the page is still displayed (not closed already)
    if (isDisplayed) {

      // let's create an `h2` tag and place the text inside
      var header = document.createElement('h2');
      header.textContent = 'The project has ' + + ' issues';

      // append just created element to the container

  // return a function, which is called when the page is being closed
  return function () {

    // we unset the `isDisplayed` flag to ignore to Web API calls finished after the page is closed
    isDisplayed = false;
  • No labels