Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support design library symbols and colors #130

Merged
merged 30 commits into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4c17da3
feat: support jenkins design library symbols and colors
cronik May 1, 2024
8cadb9c
Reduce docs diffs
MarkEWaite May 2, 2024
79e778d
Add a line break to avoid damage
MarkEWaite May 2, 2024
766971b
Separate link to new paragraph
MarkEWaite May 2, 2024
9674128
Clarify link to ionicons symbol catalog
MarkEWaite May 2, 2024
e7ec39c
Improve ionicons symbols link description
MarkEWaite May 2, 2024
49d799c
Include required text in symbol example
MarkEWaite May 3, 2024
90cd6f5
Add required text param to examples
MarkEWaite May 3, 2024
7416feb
Add AbstractAddBadgeStep
cronik May 3, 2024
721fcfa
Add success semantic color
cronik May 3, 2024
49bad30
Add color field to addBadge jelly page
MarkEWaite May 4, 2024
c11e330
Fix developer connection URL warning from hpi plugin
MarkEWaite May 4, 2024
db1e983
Add online help for addBadge step
MarkEWaite May 4, 2024
ece93c1
Simplify quoting in addBadge step test
MarkEWaite May 4, 2024
77b1499
Fix syntax error in help
MarkEWaite May 4, 2024
ddcd76f
Fix broken hyperlinks in online help
MarkEWaite May 4, 2024
88e310c
Clearly separate icon descriptions in help
MarkEWaite May 4, 2024
e9b8cf2
More fixes for the red bug example
MarkEWaite May 4, 2024
a4fbcf5
Remove unused imports
MarkEWaite May 4, 2024
2ff53e9
Merge branch 'master' into feature/jenkins-symbols
MarkEWaite May 4, 2024
3b4c000
Remove extra 'span' text from appendText
MarkEWaite May 5, 2024
d659e50
Remove unused imports
MarkEWaite May 5, 2024
599ab85
Add color style for icons and clarify documentation
cronik May 6, 2024
ecb05d5
Remove name parameter from OptionalParam
cronik May 6, 2024
faf09b7
Update copyright
cronik May 6, 2024
4c8283f
Fix OptionalParam name reference
cronik May 6, 2024
1c48304
Lift constraint on icons to enable sources other than ionicons-api-pl…
strangelookingnerd May 10, 2024
e7dd035
Merge branch 'master' into feature/jenkins-symbols
MarkEWaite May 11, 2024
5c83323
Wrap text for better layout on plugins.jenkins.io site
MarkEWaite May 11, 2024
054abb7
Fix spelling of 'ok' in example
MarkEWaite May 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ addBadge(icon: <icon>, text: <text>)
*
* icon: The icon for this badge
* text: The text for this badge
* color: (optional) The Jenkins palette/semantic color name of the badge icon symbol
* id: (optional) Badge identifier. Selectively delete badges by id.
* link: (optional) The link to be added to this badge
*/
addBadge(icon: <icon>, text: <text>, id: <id>, link: <link>)
addBadge(icon: <icon>, text: <text>, color: <color>,
id: <id>, link: <link>)


// addInfoBadge
Expand Down Expand Up @@ -277,6 +279,16 @@ removeSummaries(id: <id>)

## Icons

Icons can reference [Jenkins Symbols](https://weekly.ci.jenkins.io/design-library/Symbols/), including all the symbols provided by the [ionicons-api-plugin](https://plugins.jenkins.io/ionicons-api).

More symbols can be referenced by installing additional plugins, such as [font-awesome-api-plugin](https://plugins.jenkins.io/font-awesome-api) or [custom-folder-icon-plugin](https://plugins.jenkins.io/custom-folder-icon).

```groovy
addBadge(icon: 'symbol-cube', text: 'a cubed build')
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'a starred build')
addBadge(icon: 'symbol-symbolName plugin-yourArtifactId', text: 'another icon build')
```

In addition to the default [16x16](https://github.com/jenkinsci/jenkins/tree/master/war/src/main/webapp/images/16x16) icons offered by Jenkins, badge plugin provides the following icons:

- ![alt text](src/main/webapp/images/completed.gif "completed.gif") completed.gif
Expand All @@ -302,6 +314,39 @@ Other plugin icons can be used by setting the path of the icon within the jenkin
addBadge(icon: "/static/8361d0d6/images/16x16/help.png", text: "help")
```

## Colors

Colors may reference [Jenkins palette colors or variables](https://weekly.ci.jenkins.io/design-library/Colors/).

`symbol` badges **must** reference a named color from the Jenkins palette.
```groovy
// jenkins palette colors
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'yellow')
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'dark-yellow')
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'jenkins-!-color-yellow')

// jenkins semantic colors
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'warning')
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'success')
addBadge(icon: 'symbol-star plugin-ionicons-api', text: 'A star', color: 'jenkins-!-warning-color')
```

Short text badges may use additional css color styles.
```groovy
// jenkins palette colors
addShortText(text: 'ok', color: 'green')
addShortText(text: 'ok', color: 'jenkins-!-color-green')

// jenkins semantic colors
addShortText(text: 'ok', color: 'success')
addShortText(text: 'ok', color: 'jenkins-!-success-color')

// css colors
addShortText(text: 'ok', color: '#42f557')
addShortText(text: 'ok', color: 'rgb(66, 245, 87)')
addShortText(text: 'ok', color: 'var(--green)') // jenkins css vars
```

## Allow HTML in Badge and Summary

The badge plugin uses by default the OWASP Markup Formatter to sanitize the HTML Badge and Summary. This feature can be disabled in the Jenkins configuration:
Expand Down
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>antisamy-markup-formatter</artifactId>
</dependency>
<dependency>
<groupId>io.jenkins.plugins</groupId>
<artifactId>ionicons-api</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
Expand Down
Binary file modified src/doc/badge.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/doc/summary.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
*/
package com.jenkinsci.plugins.badge.action;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import hudson.model.Action;
import org.kohsuke.stapler.export.Exported;

Expand All @@ -42,4 +44,64 @@
public String getId() {
return id;
}

/**
* Is the icon reference a Jenkins symbol name.
* @param icon icon reference
* @return {@code true} if the icon reference is a Jenkins symbol name
*/
static boolean isJenkinsSymbolRef(@Nullable String icon) {
return icon != null && icon.startsWith("symbol-");

Check warning on line 54 in src/main/java/com/jenkinsci/plugins/badge/action/AbstractAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 54 is only partially covered, one branch is missing
}

/**
* Get the Jenkins color class for the given color reference. Returns {@code null} if the color is not a
* known Jenkins palette color or semantic color.
* @param color color reference
* @return jenkins color class name or {@code null}
*/
@CheckForNull
static String getJenkinsColorClass(@Nullable String color) {
if (color == null) {
return null;
}

String primary = color;
if (color.startsWith("light-") && color.length() > 6) {
primary = color.substring(6);
} else if (color.startsWith("dark-") && color.length() > 5) {
primary = color.substring(5);
}

// https://github.com/jenkinsci/jenkins/blob/master/war/src/main/scss/abstracts/_theme.scss
switch(primary) {
// palette
case "blue":
case "brown":
case "cyan":
case "green":
case "indigo":
case "orange":
case "pink":
case "purple":
case "red":
case "yellow":
case "white":
case "black":
return "jenkins-!-color-" + color;
// semantics
case "accent":
case "text":
case "error":
case "warning":
case "destructive":
case "build":
case "success":
case "danger":
case "info":
return "jenkins-!-" + color + "-color";
default:
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.jenkinsci.plugins.badge.BadgePlugin;
import hudson.PluginWrapper;
import hudson.model.Hudson;
import io.jenkins.plugins.ionicons.Ionicons;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
Expand All @@ -34,6 +35,8 @@

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -43,10 +46,10 @@
private static final long serialVersionUID = 1L;
private final String iconPath;
private final String text;
private String color = "#000000";
private String background = "#FFFF00";
private String border = "1px";
private String borderColor = "#C0C000";
private String color;
private String background;
private String border;
private String borderColor;
private String link;

private BadgeAction(String iconPath, String text) {
Expand All @@ -65,6 +68,14 @@
return action;
}

public static BadgeAction createBadge(String icon, String color, String text, String link) throws IllegalArgumentException {
BadgeAction action = new BadgeAction(getIconPath(icon), text);
action.link = link;
action.color = color;
action.validate();
return action;
}

public static BadgeAction createShortText(String text) {
return new BadgeAction(null, text);
}
Expand All @@ -89,23 +100,23 @@
}

public static BadgeAction createInfoBadge(String text, String link) throws IllegalArgumentException {
return createBadge("info.gif", text, link);
return createBadge(Ionicons.getIconClassName("information-circle"), "jenkins-!-color-blue", text, link);
}

public static BadgeAction createWarningBadge(String text) throws IllegalArgumentException {
return createWarningBadge(text, null);
}

public static BadgeAction createWarningBadge(String text, String link) throws IllegalArgumentException {
return createBadge("warning.gif", text, link);
return createBadge(Ionicons.getIconClassName("warning"), "jenkins-!-warning-color", text, link);
}

public static BadgeAction createErrorBadge(String text) throws IllegalArgumentException {
return createErrorBadge(text, null);
}

public static BadgeAction createErrorBadge(String text, String link) throws IllegalArgumentException {
return createBadge("error.gif", text, link);
return createBadge(Ionicons.getIconClassName("remove-circle"), "jenkins-!-error-color", text, link);
}

protected void validate() throws IllegalArgumentException {
Expand Down Expand Up @@ -181,6 +192,42 @@
return borderColor;
}

/**
* Get the class value for the icon element.
* @return string of css class names to add or empty string if no class to add.
*/
public String getIconClass() {
List<String> classes = new LinkedList<>();
if (isJenkinsSymbolRef(this.iconPath)) {
classes.add("icon-sm");
}

if (this.color != null) {
if (this.color.startsWith("jenkins-!-")) {

Check warning on line 206 in src/main/java/com/jenkinsci/plugins/badge/action/BadgeAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 206 is only partially covered, one branch is missing
classes.add(this.color);

Check warning on line 207 in src/main/java/com/jenkinsci/plugins/badge/action/BadgeAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 207 is not covered by tests
} else {
String colorClass = getJenkinsColorClass(this.color);
if (colorClass != null) {
classes.add(colorClass);
}
}
}

return String.join(" ", classes);
}

/**
* Get the color value for the {@code style} attribute of the icon element.
* @return {@code null} if color not set or color is a Jenkins color class.
*/
public String getIconColorStyle() {
if (this.color != null && !this.color.startsWith("jenkins-!-") && getJenkinsColorClass(this.color) == null) {
return this.color;
}

return null;
}

@Exported
public String getLink() {
if (link == null || BadgePlugin.get().isDisableFormatHTML()) {
Expand All @@ -204,11 +251,16 @@
return icon;
}

if (isJenkinsSymbolRef(icon)) {
return icon;
}

Jenkins jenkins = Jenkins.getInstanceOrNull();

// Try plugin images dir, fallback to Hudson images dir
PluginWrapper wrapper = jenkins != null ? jenkins.getPluginManager().getPlugin("badge") : null;
boolean pluginIconExists = (wrapper != null) && new File(wrapper.baseResourceURL.getPath() + "/images/" + icon).exists();
return pluginIconExists ? "/plugin/" + wrapper.getShortName() + "/images/" + icon : Hudson.RESOURCE_PATH + "/images/16x16/" + icon;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -96,27 +96,28 @@

@Whitelisted
public void appendText(String text, boolean escapeHtml, boolean bold, boolean italic, String color) {
String closeTags = "";
if (bold) {
summaryText += "<b>";
closeTags += "</b>";
}
if (italic) {
summaryText += "<i>";
closeTags += "</i>";
}
if (color != null) {
summaryText += "<font color=\"" + color + "\">";
String cls = getJenkinsColorClass(color);
if (cls != null) {

Check warning on line 110 in src/main/java/com/jenkinsci/plugins/badge/action/BadgeSummaryAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 110 is only partially covered, one branch is missing
summaryText += "<span class=\"" + StringEscapeUtils.escapeHtml(cls) + "\">";
closeTags += "</span>";

Check warning on line 112 in src/main/java/com/jenkinsci/plugins/badge/action/BadgeSummaryAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 111-112 are not covered by tests
} else {
summaryText += "<font color=\"" + StringEscapeUtils.escapeHtml(color) + "\">";
closeTags += "</font>";
}
}
if (escapeHtml) {
text = StringEscapeUtils.escapeHtml(text);
}
summaryText += text;
if (color != null) {
summaryText += "</font>";
}
if (italic) {
summaryText += "</i>";
}
if (bold) {
summaryText += "</b>";
}
summaryText += text + closeTags;
}
}
Loading