Skip to content

Commit

Permalink
UI renovation (#328)
Browse files Browse the repository at this point in the history
- remove all style attributes and replace with classes
- use only standard jenkins variables and color so everything looks good
  with dark theme as well
- do all styling via an explicit css file
- use jenkins-table where appropriate
- use a grid layout instead of tables to arrange the portlets
- wrap the portlet in a div instead of a table
- use new weather icons for job statistics
- sort jobs by full name for job grid
- add border to portlets without table
- border around the content
- dedicated jelly for tables with tweaked styling
- move implementation guide to separate file
  • Loading branch information
mawinter69 authored Feb 8, 2024
1 parent 9c68383 commit a74654f
Show file tree
Hide file tree
Showing 48 changed files with 1,239 additions and 1,086 deletions.
89 changes: 89 additions & 0 deletions Implementation-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Implementation Guide

Much of the benefit of this plugin will be realized when other plugins that
enhance Jenkins offer support for it.

## Add support in your plugin

- Extend the DashboardPortlet class and provide a descriptor that
extends the `Descriptor<DashboardPortlet>`
- Create a jelly view called *portlet.jelly*
- Optionally create a jelly view called *main.jelly* to be used when the portlet
is in maximized mode (otherwise the same *portlet.jelly* view will be used)

It is possible to define custom parameters for the DashboardPortlet. The
displayName is always required. To add new parameters:

- create a jelly file called *config.jelly* to be used when the portlet is
configured (added to the view in 'Edit View' config page);
- modify constructor (with `@DataBoundConstructor`) to receive the new
parameters.

Looking at the source code of this plugin will show a number of examples
of doing this. The core portlets do the same thing that your plugin
would do.

## Sample files

***MyPortlet.java***

```
import hudson.plugins.view.dashboard.DashboardPortlet;
class MyPortlet extends DashboardPortlet {
@DataBoundConstructor
public MyPortlet(String name) {
super(name);
}
// do whatever you want
@Extension
public static class DescriptorImpl extends Descriptor<DashboardPortlet> {
@Override
public String getDisplayName() {
return "MyPortlet";
}
}
};
```

***portlet.jelly***

If you want to show a single table inside the portlet use *dp:decorate-table*. This ensures that the table is properly
rendered and really fills the complete area (The default styling of Jenkins adds rounded borders everywhere and a margin
at the bottom that make it look not so nice).<br/>
You can pass additional classes to be set on the table, e.g. to make it sortable.<br/>
```
<j:jelly xmlns:j="jelly:core" xmlns:dp="/hudson/plugins/view/dashboard">
<dp:decorate-table portlet="${it}" class="sortable"> <!-- This is to say that this is a dashboard view portlet for a table-->
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<j:forEach var="col" items="${it.myitems}">
<tr>
<td>${col.name}</td>
<td>${col.description}</td>
</tr>
</j:forEach>
</tbody>
</dp:decorate-table>
</j:jelly>
```

To show any other kind of content use *dp:decorate-plain*
```
<j:jelly xmlns:j="jelly:core" xmlns:dp="/hudson/plugins/view/dashboard">
<dp:decorate-plain portlet="${it}"> <!-- This is to say that this is a dashboard view portlet -->
<!-- you can include a separate file with the logic to display your data or you can write here directly -->
<st:include page="myportlet.jelly"/>
</dp:decorate-plain>
</j:jelly>
```
72 changes: 1 addition & 71 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,76 +152,7 @@ to reformat Java code in the proper style.

## Extending the Dashboard View plugin

Much of the benefit of this plugin will be realized when other plugins that
enhance Jenkins offer support for it.

Add support in your plugin:

- Extend the DashboardPortlet class and provide a descriptor that
extends the `Descriptor<DashboardPortlet>`
- Create a jelly view called portlet.jelly
- Optionally create a jelly view called main.jelly to be used when the portlet
is in maximized mode (otherwise the same portlet.jelly view will be used)

It is possible to define custom parameters for the DashboardPortlet. The
displayName is always required. To add new parameters:

- create a jelly file called config.jelly to be used when the portlet is
configured (added to the view in 'Edit View' config page);
- modify constructor (with `@DataBoundConstructor`) to receive the new
parameters.

Looking at the source code of this plugin will show a number of examples
of doing this. The core portlets do the same thing that your plugin
would do.

Please update the list below with a [pull request] against this repository.

Sample files:

**MyPortlet.java**:

```
import hudson.plugins.view.dashboard.DashboardPortlet;
class MyPortlet extends DashboardPortlet {
@DataBoundConstructor
public MyPortlet(String name) {
super(name);
}
// do whatever you want
@Extension
public static class DescriptorImpl extends Descriptor<DashboardPortlet> {
@Override
public String getDisplayName() {
return "MyPortlet";
}
}
};
```

**portlet.jelly**:

```
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
xmlns:dp="/hudson/plugins/view/dashboard" xmlns:l="/lib/layout"
xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<dp:decorate portlet="${it}"> <!-- This is to say that this is a dashboard view portlet -->
<tr><td> <!-- This is needed because everything is formatted as a table - ugly, I know -->
<!-- you can include a separate file with the logic to display your data or you can write here directly -->
<div align="center">
<st:include page="myportlet.jelly"/>
</div>
</td></tr>
</dp:decorate>
</j:jelly>
```
Read the [Implementation guide](Implementation-guide.md) if you want to write your own portlet for your plugin.

## Other plugins that support the Dashboard View

Expand Down Expand Up @@ -273,7 +204,6 @@ This plugin is licensed under the MIT License (MIT), see [LICENSE](LICENSE).

## TODO

- Use `<div>` instead of `<table>` to place portlets in the page.
- Update this README with more screenshots.


Expand Down
8 changes: 6 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
<revision>2</revision>
<changelist>999999-SNAPSHOT</changelist>
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
<jenkins.version>2.401.3</jenkins.version>
<jenkins.version>2.426.2</jenkins.version>
<spotless.check.skip>false</spotless.check.skip>
</properties>

Expand All @@ -53,7 +53,7 @@
<dependencies>
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.401.x</artifactId>
<artifactId>bom-2.426.x</artifactId>
<version>2675.v1515e14da_7a_6</version>
<type>pom</type>
<scope>import</scope>
Expand All @@ -62,6 +62,10 @@
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>ionicons-api</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class JobsPortlet extends DashboardPortlet {
private static final int MIN_COLUMN_COUNT = 3;

private final int columnCount;

private boolean fillColumnFirst = false;

@DataBoundConstructor
Expand All @@ -30,13 +31,17 @@ public JobsPortlet(String name, int columnCount, boolean fillColumnFirst) {
this.fillColumnFirst = fillColumnFirst;
}

public boolean isFillColumnFirst() {
return fillColumnFirst;
}

public int getColumnCount() {
return columnCount <= 0 ? MIN_COLUMN_COUNT : columnCount;
}

public List<List<Job>> getJobs() {
List<Job> jobs = this.getDashboard().getJobs();
Collections.sort(jobs, (p1, p2) -> p1.getDisplayName().compareToIgnoreCase(p2.getDisplayName()));
Collections.sort(jobs, (p1, p2) -> p1.getFullDisplayName().compareToIgnoreCase(p2.getFullDisplayName()));

if (this.fillColumnFirst) {
return transposed(jobs);
Expand Down
36 changes: 16 additions & 20 deletions src/main/java/hudson/plugins/view/dashboard/stats/StatJobs.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import hudson.Extension;
import hudson.model.Descriptor;
import hudson.model.Hudson;
import hudson.model.Job;
import hudson.model.TopLevelItem;
import hudson.plugins.view.dashboard.DashboardPortlet;
Expand Down Expand Up @@ -34,19 +33,22 @@ public StatJobs(String name) {
*/
@Deprecated
public enum HealthStatus {
HEALTH_OVER_80("health-80plus.gif", Messages.Dashboard_NoRecentBuildsFailed()),
HEALTH_60_TO_79("health-60to79.gif", Messages.Dashboard_RecentBuildsFailed("20", "40")),
HEALTH_40_TO_59("health-40to59.gif", Messages.Dashboard_RecentBuildsFailed("40", "60")),
HEALTH_20_TO_39("health-20to39.gif", Messages.Dashboard_RecentBuildsFailed("60", "80")),
HEALTH_0_TO_19("health-00to19.gif", Messages.Dashboard_AllRecentBuildsFailed()),
HEALTH_UNKNOWN("empty.gif", Messages.Dashboard_UnknownStatus());
HEALTH_OVER_80("symbol-weather-icon-health-80plus", Messages.Dashboard_NoRecentBuildsFailed(), 100),
HEALTH_60_TO_79("symbol-weather-icon-health-60to79", Messages.Dashboard_RecentBuildsFailed("20", "40"), 80),
HEALTH_40_TO_59("symbol-weather-icon-health-40to59", Messages.Dashboard_RecentBuildsFailed("40", "60"), 60),
HEALTH_20_TO_39("symbol-weather-icon-health-20to39", Messages.Dashboard_RecentBuildsFailed("60", "80"), 40),
HEALTH_0_TO_19("symbol-weather-icon-health-00to19", Messages.Dashboard_AllRecentBuildsFailed(), 20),
HEALTH_UNKNOWN("symbol-indeterminate", Messages.Dashboard_UnknownStatus(), 0);
// private HealthReport healthReport;
private final String iconUrl;
private final String iconClassName;
private final String description;

HealthStatus(String iconUrl, String description) {
this.iconUrl = iconUrl;
private int score;

HealthStatus(String iconClassName, String description, int score) {
this.iconClassName = iconClassName;
this.description = description;
this.score = score;
}

public static HealthStatus getHealthStatus(Job job) {
Expand All @@ -67,18 +69,12 @@ public static HealthStatus getHealthStatus(Job job) {
return job.getFirstBuild() != null ? HEALTH_OVER_80 : HEALTH_UNKNOWN;
}

public String getIconUrl() {
return Hudson.RESOURCE_PATH + "/images/32x32/" + iconUrl;
public String getIconClassName() {
return iconClassName;
}

public String getIconUrl(String size) {
if (iconUrl == null) {
return Hudson.RESOURCE_PATH + "/images/" + size + "/" + HEALTH_UNKNOWN.getIconUrl();
}
if (iconUrl.startsWith("/")) {
return iconUrl.replace("/32x32/", "/" + size + "/");
}
return Hudson.RESOURCE_PATH + "/images/" + size + "/" + iconUrl;
public int getScore() {
return score;
}

public String getDescription() {
Expand Down
Loading

0 comments on commit a74654f

Please sign in to comment.