diff --git a/internal/commands/plugins.go b/internal/commands/plugins.go index e826c69..2e3a6df 100644 --- a/internal/commands/plugins.go +++ b/internal/commands/plugins.go @@ -87,6 +87,7 @@ func RunBinaryWithOptions(ctx context.Context, cmd string, args []string, wg *sy webservice.SendAlert( webservice.Error, fmt.Sprintf("Plugin '%s' failed to start: %v", cmd, err), + true, ) } } diff --git a/internal/commands/plugins_windows.go b/internal/commands/plugins_windows.go index cc0ff4e..342e605 100644 --- a/internal/commands/plugins_windows.go +++ b/internal/commands/plugins_windows.go @@ -146,6 +146,7 @@ func RunBinaryWithOptions(ctx context.Context, cmd string, args []string, wg *sy webservice.SendAlert( webservice.Error, fmt.Sprintf("Plugin '%s' failed to start: %v", cmd, err), + true, ) } } diff --git a/internal/commands/root.go b/internal/commands/root.go index bf2761b..f92f6be 100644 --- a/internal/commands/root.go +++ b/internal/commands/root.go @@ -75,7 +75,7 @@ func launch(cmd *cobra.Command, args []string) { } } else { log.Printf("config %s", err) - webservice.SendAlert(webservice.Info, fmt.Sprintf("%s", err)) + webservice.SendAlert(webservice.Info, fmt.Sprintf("%s", err), true) } // just a little ditty to see if we should open the ui or the webservice or both diff --git a/internal/webservice/alerts.go b/internal/webservice/alerts.go index 482967b..1e67e9c 100644 --- a/internal/webservice/alerts.go +++ b/internal/webservice/alerts.go @@ -34,6 +34,7 @@ const ( type Alert struct { Level AlertLevel Message string + Fade bool } // Alerts serves as a queue to hold alerts to be sent to the UI, @@ -44,10 +45,11 @@ var Alerts []Alert // SendAlert tests for the existence of an established websocket // and either sends the message over the websocket, or adds it // to the Alerts queue to be sent later -func SendAlert(lvl AlertLevel, msg string) { +func SendAlert(lvl AlertLevel, msg string, fade bool) { alert := Alert{ Level: lvl, Message: msg, + Fade: fade, } if ws == nil { @@ -63,6 +65,7 @@ func sendAlertMessage(a Alert) { "component": "alert", "level": a.Level, "message": a.Message, + "fade": a.Fade, "timestamp": time.Now().UnixNano() / 1000000, }); err != nil { onError(err) diff --git a/web/index.html b/web/index.html index 3383e76..8856f4b 100755 --- a/web/index.html +++ b/web/index.html @@ -26,7 +26,7 @@ spinner.style.display = "none"; } const loadFail = (err) => { - showDismissableAlert("danger", `Error loading '${err.validatedURL}': ${err.errorDescription} (${err.errorCode})`); + showDismissableAlert("danger", `Error loading '${err.validatedURL}': ${err.errorDescription} (${err.errorCode})`, true); } webview.addEventListener("did-start-loading", loadStart) webview.addEventListener("did-stop-loading", loadStop) diff --git a/web/js/common.js b/web/js/common.js index 5c6e1a8..f045340 100755 --- a/web/js/common.js +++ b/web/js/common.js @@ -97,8 +97,11 @@ function removeElement(id) { // eslint-disable-line no-unused-vars } } -function showDismissableAlert(alertLevel, msg) { // eslint-disable-line no-unused-vars +// show a dismissable alert in the UI +// if 'fade' is set to true, the alert will fade out and disappear after 5s +function showDismissableAlert(alertLevel, msg, fade) { // eslint-disable-line no-unused-vars let e = document.getElementById("alert-div"); + let alertId = `alert-${Math.floor(Math.random() * 1000)}`; let alertHeading = ""; switch (alertLevel) { @@ -113,9 +116,11 @@ function showDismissableAlert(alertLevel, msg) { // eslint-disable-line no-unuse } let div = document.createElement("div"); + div.id = alertId; div.className = `alert alert-${alertLevel} alert-dismissable fade show`; div.setAttribute("role", "alert"); div.innerHTML = `${alertHeading}: ${msg}`; + div.style.opacity = "1"; // dismissable button let btn = document.createElement("button"); @@ -131,5 +136,24 @@ function showDismissableAlert(alertLevel, msg) { // eslint-disable-line no-unuse btn.appendChild(span); div.appendChild(btn); + // add auto-hide if fade is true + if (fade === true) { + let script = document.createElement("script"); + let inline = `alertFadeOut("${alertId}")`; + script.innerText = inline; + div.appendChild(script); + } + e.appendChild(div); +} + +function alertFadeOut(id) { // eslint-disable-line no-unused-vars + let element = document.getElementById(id); + setTimeout(function() { + element.style.transition = "opacity 2s ease"; + element.style.opacity = "0"; + }, 5000); + element.addEventListener("transitionend", function() { + element.parentNode.removeChild(element); + }); } \ No newline at end of file diff --git a/web/js/websocket.js b/web/js/websocket.js index c0eb6bc..f08b2d4 100755 --- a/web/js/websocket.js +++ b/web/js/websocket.js @@ -77,7 +77,7 @@ function handleMessages(message) { } else if (json["component"] === "authcomplete") { authComplete(); } else if (json["component"] === "alert") { - showDismissableAlert(json["level"], json["message"]); + showDismissableAlert(json["level"], json["message"], json["fade"]); } } else { // TODO: determine if we're dispatching events or just doing function calls