Adding pages to the webapp
SonarQube's UI is built as a Single Page Application using React. It provides the ability to add new pages to the UI using JavaScript. A page (or page extension) is a self-contained 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.
Note that for security reasons, pages added to the UI cannot include inline scripts and unsafe eval expressions.
Prerequisites
Before reading this guide, make sure you know how to build, deploy, and debug a plugin.
Create a Java class implementing PageDefinition
For each page, you'll need to set a key and a name. The page key should have the format plugin_key/page_id
(e.g.: governance/project_dump
). The plugin_key
is computed from the <artifactId>
in your pom.xml
, or can be set explicitly in the pom using the <pluginKey>
parameter in the sonar-packaging-maven-plugin
configuration. All the pages should be declared in this class. Here is an example.
Configuring each page
There are 3 settings available when you define the page extensions using the PageDefinition
class:
setAdmin(boolean admin)
: flag this page as restricted to users with "administer" permission. Defaults tofalse
.setScope(org.sonar.api.web.page.Page.Scope scope)
: set the scope of this page. Available scopes areGLOBAL
(default), which will add this page to the main menu, andCOMPONENT
, which will add the page to a project, application, or portfolio menu (applications and portfolios only apply to Enterprise Edition and above).setComponentQualifiers(org.sonar.api.web.page.Qualifier... qualifiers)
: ifsetScope()
is set toCOMPONENT
, this sets to what kind of component the page applies to. Available qualifiers arePROJECT
,APP
,VIEW
(portfolio), andSUB_VIEW
(APP
,VIEW
, andSUB_VIEW
only apply to Enterprise Edition and above). You can pass multiple qualifiers. If no qualifier is set, it will apply to all types.
Create a JavaScript file per page
The PageDefinition
will register each key as an available route in SonarQube. Whenever this route is visited, SonarQube will asynchronously fetch a single JavaScript file from your plugin's /static/
directory, and boot up your page's application. This file should have the same name as the page_id
you defined in your PageDefinition
class. In the example in Step 1, you would need 4 different JavaScript files:
/static/global_page.js
/static/project_page.js
/static/portfolio_page.js
/static/admin_page.js
Each file must call the global window.registerExtension()
function, and pass its full key as a first argument (plugin_key/page_id
, e.g.: governance/project_dump
). The second argument is the start callback. This function will be called once your page is started, and receive information about the current page as an argument (see below). The return value of the start callback depends on how you want to implement your page:
If you want to use React, you should return a React Component:
If you want to use any other framework, you should perform any start logic directly inside the start function body, and return a shutdown callback:
The options
object will contain the following:
options.el
: A DOM node you must use to inject your content.options.currentUser
: Information about the current user.- (optional)
options.component
: Contains the information of the current project, application, or portfolio. - (optional)
options.branchLike
: Contains the information of the current branch or pull request.
SonarQube doesn't guarantee any JavaScript library availability at runtime (except React). If you need a library, include it in the final file.
CSS files
If you want a static CSS file to be loaded when your extension is bootstrapped, rather than using run-time inclusion of styles, you can pass true
as a third parameter to the window.registerExtension()
function. This will trigger the loading of a CSS file that must have the same basename as the registering JS file. I.e., if your extension JS file is /static/global_page.js
, the CSS file must be called /static/global_page.css
. The bootstrap will wait for the CSS file to be fully loaded before calling the start
callback.
Examples
We recommend checking out the sonar-custom-plugin-example repository. It contains detailed examples using several front-end frameworks, and its code is thoroughly documented. It also describes how to run a local development server to speed up the front-end development, without requiring a full rebuild and re-deploy to test your changes.
Was this page helpful?