Update the design of notifications (#7049)

Co-authored-by: Tim Jacomb <timjacomb1@gmail.com>
Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com>
Co-authored-by: Alexander Brandes <mc.cache@web.de>
This commit is contained in:
Jan Faracik 2022-10-19 19:18:31 +01:00 committed by GitHub
parent f04f407846
commit 42a4998045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 216 additions and 208 deletions

View File

@ -50,7 +50,7 @@ public class FormApply {
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
if (isApply(req)) {
// if the submission is via 'apply', show a response in the notification bar
applyResponse("notificationBar.show('" + Messages.HttpResponses_Saved() + "',notificationBar.OK)")
applyResponse("notificationBar.show('" + Messages.HttpResponses_Saved() + "',notificationBar.SUCCESS)")
.generateResponse(req, rsp, node);
} else {
rsp.sendRedirect(destination);

View File

@ -173,6 +173,7 @@ THE SOFTWARE.
<script src="${resURL}/jsbundles/page-init.js" type="text/javascript"/>
<!-- Sortable library used in drag & drop -->
<script src="${resURL}/jsbundles/sortable-drag-drop.js" type="text/javascript"/>
<script src="${resURL}/jsbundles/app.js" type="text/javascript" defer="true" />
</head>
<body id="jenkins" class="yui-skin-sam ${layoutType} jenkins-${h.version}" data-version="${h.version}" data-model-type="${it.class.name}">

3
war/src/main/js/app.js Normal file
View File

@ -0,0 +1,3 @@
import Notifications from "@/components/notifications";
Notifications.init();

View File

@ -0,0 +1,78 @@
import * as Symbols from "@/util/symbols";
import { createElementFromHtml } from "@/util/dom";
function init() {
window.notificationBar = {
OPACITY: 1,
DELAY: 3000, // milliseconds to auto-close the notification
div: null, // the main 'notification-bar' DIV
token: null, // timer for cancelling auto-close
defaultIcon: Symbols.INFO,
defaultAlertClass: "jenkins-notification",
SUCCESS: {
alertClass: "jenkins-notification jenkins-notification--success",
icon: Symbols.SUCCESS,
},
WARNING: {
alertClass: "jenkins-notification jenkins-notification--warning",
icon: Symbols.WARNING,
},
ERROR: {
alertClass: "jenkins-notification jenkins-notification--error",
icon: Symbols.ERROR,
sticky: true,
},
init: function () {
if (this.div == null) {
this.div = document.createElement("div");
this.div.id = "notification-bar";
document.body.insertBefore(this.div, document.body.firstElementChild);
const self = this;
this.div.onclick = function () {
self.hide();
};
} else {
this.div.innerHTML = "";
}
},
// cancel pending auto-hide timeout
clearTimeout: function () {
if (this.token) {
window.clearTimeout(this.token);
}
this.token = null;
},
// hide the current notification bar, if it's displayed
hide: function () {
this.clearTimeout();
this.div.classList.remove("jenkins-notification--visible");
this.div.classList.add("jenkins-notification--hidden");
},
// show a notification bar
show: function (text, options) {
options = options || {};
this.init();
this.div.appendChild(
createElementFromHtml(options.icon || this.defaultIcon)
);
const message = this.div.appendChild(document.createElement("span"));
message.appendChild(document.createTextNode(text));
this.div.className = options.alertClass || this.defaultAlertClass;
this.div.classList.add("jenkins-notification--visible");
this.clearTimeout();
const self = this;
if (!options.sticky) {
this.token = window.setTimeout(function () {
self.hide();
}, this.DELAY);
}
},
};
}
export default { init };

View File

@ -0,0 +1,4 @@
export const INFO = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 56C145.72 56 56 145.72 56 256s89.72 200 200 200 200-89.72 200-200S366.28 56 256 56zm0 82a26 26 0 11-26 26 26 26 0 0126-26zm48 226h-88a16 16 0 010-32h28v-88h-16a16 16 0 010-32h32a16 16 0 0116 16v104h28a16 16 0 010 32z" fill='currentColor' /></svg>`;
export const SUCCESS = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm108.25 138.29l-134.4 160a16 16 0 01-12 5.71h-.27a16 16 0 01-11.89-5.3l-57.6-64a16 16 0 1123.78-21.4l45.29 50.32 122.59-145.91a16 16 0 0124.5 20.58z" fill='currentColor'/></svg>`;
export const WARNING = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M449.07 399.08L278.64 82.58c-12.08-22.44-44.26-22.44-56.35 0L51.87 399.08A32 32 0 0080 446.25h340.89a32 32 0 0028.18-47.17zm-198.6-1.83a20 20 0 1120-20 20 20 0 01-20 20zm21.72-201.15l-5.74 122a16 16 0 01-32 0l-5.74-121.95a21.73 21.73 0 0121.5-22.69h.21a21.74 21.74 0 0121.73 22.7z" fill='currentColor'/></svg>`;
export const ERROR = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48zm0 319.91a20 20 0 1120-20 20 20 0 01-20 20zm21.72-201.15l-5.74 122a16 16 0 01-32 0l-5.74-121.94v-.05a21.74 21.74 0 1143.44 0z" fill='currentColor'/></svg>`;

View File

@ -41,7 +41,7 @@
// Status icon colors
--weather-icon-color: var(--primary);
--unstable-build-icon-color: var(--notification-warning-icon-color);
--unstable-build-icon-color: var(--orange);
// Background colors
--background: var(--white);
@ -76,31 +76,6 @@
--breadcrumbs-text-color: #4d545d;
--breadcrumbs-item-bg-color--hover: var(--light-grey);
// Alert banners
// Default
--alert-default-icon-color: #2196f3;
--alert-default-bg-color: #d1ecf1;
--alert-default-border-color: #bee5eb;
--alert-default-color: #0c5464;
// Success
--notification-success-icon-color: #4caf50;
--notification-success-bg-color: #d4edda;
--notification-success-border-color: #c3e6cb;
--notification-success-color: var(--success);
// Warning
--notification-warning-icon-color: #ff9800;
--notification-warning-bg-color: #fff3cd;
--notification-warning-border-color: #ffeeba;
--notification-warning-color: #856404;
// Error
--notification-error-icon-color: #f44336;
--notification-error-bg-color: #f8d7da;
--notification-error-border-color: #f5c6cb;
--notification-error-color: #721c24;
// Alert call outs
--alert-success-text-color: #155724;
--alert-success-bg-color: #d4edda;

View File

@ -1170,96 +1170,7 @@ table.progress-bar.red td.progress-bar-done {
background-color: #c00;
}
/* ========================= notification bar ========================= */
#notification-bar {
width: 100%;
position: fixed;
text-align: center;
left: 0;
font-size: 1.75rem;
z-index: 1000;
border-bottom: 1px solid var(--black);
line-height: 3.5rem;
height: 3.5rem;
display: block;
will-change: opacity;
}
#notification-bar .svg-icon {
width: 35px;
height: 35px;
padding-bottom: 5px;
}
#notification-bar.notif-alert-default {
background-color: var(--alert-default-bg-color);
border-color: var(--alert-default-border-color);
color: var(--alert-default-color);
.svg-icon {
color: var(--alert-default-icon-color);
}
}
#notification-bar.notif-alert-success {
background-color: var(--notification-success-bg-color);
border-color: var(--notification-success-border-color);
color: var(--notification-success-color);
.svg-icon {
color: var(--notification-success-icon-color);
}
}
#notification-bar.notif-alert-warn {
background-color: var(--notification-warning-bg-color);
border-color: var(--notification-warning-border-color);
color: var(--notification-warning-color);
.svg-icon {
color: var(--notification-warning-icon-color);
}
}
#notification-bar.notif-alert-err {
background-color: var(--notification-error-bg-color);
border-color: var(--notification-error-border-color);
color: var(--notification-error-color);
.svg-icon {
color: var(--notification-error-icon-color);
}
}
#notification-bar.notif-alert-show {
animation: fadein 350ms ease-out 1 normal forwards;
}
#notification-bar.notif-alert-clear {
animation: fadeout 350ms ease-in 1 normal forwards;
}
@keyframes fadein {
from {
opacity: 0;
}
to {
opacity: 1;
visibility: visible;
}
}
@keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
visibility: hidden;
}
}
/* Unknown */
@keyframes spin {
from {

View File

@ -0,0 +1,124 @@
.jenkins-notification {
position: fixed;
left: 1.2rem;
bottom: 1.2rem;
min-width: 321px;
max-width: ~"min(600px, calc(100vw - 2.4rem))";
display: grid;
grid-template-columns: auto 1fr;
grid-gap: 1.5ch;
padding: 0.8rem;
border-radius: 10px;
font-weight: 500;
line-height: 1.66;
color: var(--text-color);
box-shadow: 0 0 1px 1px rgba(darken(#024cb6, 50%), 0.075),
0 10px 30px rgba(darken(#024cb6, 50%), 0.25), 0 0 30px 5px var(--background);
will-change: opacity, transform;
z-index: 999;
cursor: pointer;
transition: filter var(--standard-transition);
backdrop-filter: brightness(2) blur(30px);
svg {
width: 1.4rem;
height: 1.4rem;
}
&::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
z-index: -1;
background: var(--background);
opacity: 0.3;
}
@supports not (backdrop-filter: blur(15px)) {
&::after {
opacity: 0.9;
}
}
&:hover {
filter: brightness(0.95);
}
&:active {
filter: brightness(0.9);
}
}
.jenkins-notification--success {
color: var(--background);
&::after {
background-color: var(--success-color);
opacity: 1;
}
}
.jenkins-notification--warning {
color: var(--background);
&::after {
background-color: var(--warning-color);
opacity: 1;
}
}
.jenkins-notification--error {
color: var(--background);
&::after {
background-color: var(--error-color);
opacity: 1;
}
}
.jenkins-notification--visible {
animation: show-notification var(--elastic-transition) 1 normal forwards;
& > * {
animation: show-notification-icon var(--elastic-transition) 1 normal
forwards;
}
}
.jenkins-notification--hidden {
animation: hide-notification 150ms ease-in 1 normal forwards;
}
@keyframes show-notification {
from {
opacity: 0;
transform: translateY(1.2rem);
}
to {
opacity: 1;
transform: translateY(0);
visibility: visible;
}
}
@keyframes show-notification-icon {
from {
opacity: 0;
transform: translateY(0.3rem);
}
}
@keyframes hide-notification {
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.9);
visibility: hidden;
}
}

View File

@ -23,6 +23,7 @@
@import url("./modules/buttons-deprecated");
@import url("./modules/content-blocks");
@import url("./modules/icons");
@import url("./modules/notifications");
@import url("./modules/page-footer");
@import url("./modules/page-header");
@import url("./modules/panes-and-bigtable");

View File

@ -2759,94 +2759,3 @@ var layoutUpdateCallback = {
this.callbacks[i]();
},
};
// Notification bar
// ==============================
// this control displays a single line message at the top of the page, like StackOverflow does
// see ui-samples for more details
var notificationBar = {
OPACITY: 1,
DELAY: 3000, // milliseconds to auto-close the notification
div: null, // the main 'notification-bar' DIV
token: null, // timer for cancelling auto-close
defaultIcon: "svg-sprite-action-symbol.svg#ic_info_24px",
defaultAlertClass: "notif-alert-default",
OK: {
// standard option values for typical OK notification
icon: "svg-sprite-action-symbol.svg#ic_check_circle_24px",
alertClass: "notif-alert-success",
},
WARNING: {
// likewise, for warning
icon: "svg-sprite-action-symbol.svg#ic_report_problem_24px",
alertClass: "notif-alert-warn",
},
ERROR: {
// likewise, for error
icon: "svg-sprite-action-symbol.svg#ic_highlight_off_24px",
alertClass: "notif-alert-err",
sticky: true,
},
init: function () {
if (this.div == null) {
this.div = document.createElement("div");
YAHOO.util.Dom.setStyle(this.div, "opacity", 0);
this.div.id = "notification-bar";
document.body.insertBefore(this.div, document.body.firstElementChild);
var self = this;
this.div.onclick = function () {
self.hide();
};
} else {
this.div.innerHTML = "";
}
},
// cancel pending auto-hide timeout
clearTimeout: function () {
if (this.token) window.clearTimeout(this.token);
this.token = null;
},
// hide the current notification bar, if it's displayed
hide: function () {
this.clearTimeout();
this.div.classList.remove("notif-alert-show");
this.div.classList.add("notif-alert-clear");
},
// show a notification bar
show: function (text, options) {
options = options || {};
this.init();
var icon = this.div.appendChild(document.createElement("div"));
icon.style.display = "inline-block";
if (options.iconColor || this.defaultIconColor) {
icon.style.color = options.iconColor || this.defaultIconColor;
}
var svg = icon.appendChild(
document.createElementNS("http://www.w3.org/2000/svg", "svg")
);
svg.setAttribute("viewBox", "0 0 24 24");
svg.setAttribute("focusable", "false");
svg.setAttribute("class", "svg-icon");
var use = svg.appendChild(
document.createElementNS("http://www.w3.org/2000/svg", "use")
);
use.setAttribute(
"href",
rootURL + "/images/material-icons/" + (options.icon || this.defaultIcon)
);
var message = this.div.appendChild(document.createElement("span"));
message.appendChild(document.createTextNode(text));
this.div.className = options.alertClass || this.defaultAlertClass;
this.div.classList.add("notif-alert-show");
this.clearTimeout();
var self = this;
if (!options.sticky)
this.token = window.setTimeout(function () {
self.hide();
}, this.DELAY);
},
};

View File

@ -30,6 +30,7 @@ module.exports = (env, argv) => ({
path.join(__dirname, "src/main/js/config-tabbar.js"),
path.join(__dirname, "src/main/js/config-tabbar.less"),
],
app: [path.join(__dirname, "src/main/js/app.js")],
"keyboard-shortcuts": [
path.join(__dirname, "src/main/js/keyboard-shortcuts.js"),
],
@ -178,6 +179,7 @@ module.exports = (env, argv) => ({
},
resolve: {
alias: {
"@": path.resolve(__dirname, "src/main/js"),
// Needed to be able to register helpers at runtime
handlebars: "handlebars/runtime",
},