Skip to content

Commit

Permalink
Merge pull request #932 from bartbutenaers/notification-confirmation
Browse files Browse the repository at this point in the history
notification ui node enhancements
  • Loading branch information
joepavitt authored Aug 20, 2024
2 parents c3c13a4 + 1a2ce97 commit ce226ab
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 30 deletions.
50 changes: 47 additions & 3 deletions docs/nodes/widgets/ui-notification.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,52 @@ description: Notify users of important updates and alerts with ui-notification i
props:
UI: Unlike most widgets, notifications are owned by a "UI", not Group. This allows for notifications to be displayed across all pages.
Position: The position on the screen whethere the notification will appear.
Color: The color that should be used for the notification border.
Timeout: Number of seconds before the notification will automatically close.
Show Countdown Bar: Whether or not to show a reducing progfress bar to indicate the time remaining before the notification will close.
Show Countdown Bar: Whether or not to show a reducing progress bar to indicate the time remaining before the notification will close.
Allow Manual Dismissal: Whether or not to show a button that will allow the user to dismiss the notification. Otherwise, will only close after Timeout.
Button Label: If "Allow Manual Dismissal" is enabled, this is the label for the button.
Allow Manual Confirmation: Whether or not to show a button that will allow the user to confirm the notification. Otherwise, will only close after Timeout.
Button Label: If "Allow Manual Confirmation" is enabled, this is the label for the button.
Accept Raw: Whether you're passing in raw HTML that should be processed client-side.
Class: Appends CSS classes to the widget
dynamic:
Disabled State:
payload: msg.enabled
structure: ["Boolean"]
Allow confirmation:
payload: msg.ui_update.allowConfirm
structure: ["Boolean"]
Allow dismissal:
payload: msg.ui_update.allowDismiss
structure: ["Boolean"]
Color:
payload: msg.ui_update.color
structure: ["String"]
Confirmation button text:
payload: msg.ui_update.confirmText
structure: ["String"]
Dismissal button text:
payload: msg.ui_update.dismissText
structure: ["String"]
Display time(out):
payload: msg.ui_update.displayTime
structure: ["Number"]
Position:
payload: msg.ui_update.position
structure: ["top right", "top center", "top left", "bottom right", "bottom center", "bottom left", "center center"]
Progress bar color:
payload: msg.ui_update.progressColor
structure: ["String"]
Accept raw html:
payload: msg.ui_update.raw
structure: ["Boolean"]
Show:
payload: msg.ui_update.show
structure: ["Boolean"]
Show countdown bar:
payload: msg.ui_update.showCountdown
structure: ["Boolean"]
---

<script setup>
Expand All @@ -22,12 +62,16 @@ props:

Known in Dashboard 1.0 as a "Toast", this widget displays text/HTML in a small window that will appear on the screen for a defined duration of time (`timeout`) and at a defined location on the screen (`position`).

If you want to have the notification show indefinitely, you can set `timeout` to `0`. It will not be possible to close the notification manually unless you also set `allowDismiss` to `true`.
If you want to have the notification show indefinitely, you can set `timeout` to `0`. It will not be possible to close the notification manually unless you also set `allowDismiss` or `allowConfirm` to `true`.

## Properties

<PropsTable/>

## Dynamic Properties

<DynamicPropsTable/>

## Example

![Example of rendered Notification](/images/node-examples/ui-notification.png "Example of rendered Notification"){data-zoomable}
Expand All @@ -37,4 +81,4 @@ This notification was created using a `msg.payload` of:

```html
<h3>Generated Notification</h3><p>This is custom HTML injected into <b>Node-RED</b></p>
```
```
80 changes: 80 additions & 0 deletions nodes/widgets/locales/en-US/ui_notification.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<script type="text/html" data-help-name="ui-notification">
<p>
Displays text/HTML in a small window, that will appear on the screen
a defined duration of time(out) at a defined location.
</p>
<p>
Each received <code>msg.payload</code> will update the value shown
inside the notification dialog (and the notification will be displayed).
</p>
<h3>Properties</h3>
<dl class="message-properties">
<dt>Position <span class="property-type">list</span></dt>
<dd>The position on the screen whethere the notification will appear.</dd>
<dt>Color <span class="property-type">color</span></dt>
<dd>The color that should be used for the notification border.</dd>
<dt>Timeout <span class="property-type">number</span></dt>
<dd>Number of seconds before the notification will automatically close.</dd>
<dt>Show Countdown Bar <span class="property-type">boolean</span></dt>
<dd>Whether or not to show a reducing progress bar to indicate the time remaining.</dd>
<dt>Allow Manual Dismissal <span class="property-type">boolean</span></dt>
<dd>Whether or not to show a button that will allow the user to dismiss the notification.</dd>
<dt>Allow Manual Confirmation <span class="property-type">boolean</span></dt>
<dd>Whether or not to show a button that will allow the user to confirm the notification.</dd>
<dt>Accept Raw <span class="property-type">boolean</span></dt>
<dd>Whether you're passing in raw HTML that should be processed client-side.</dd>
</dl>
<h3>Dynamic Properties (Inputs)</h3>
<p>Any of the following can be appended to a <code>msg.ui_update</code> in order to override or set properties on this node at runtime.</p>
<dl class="message-properties">
<dt class="optional">allowConfirm<span class="property-type">boolean</span></dt>
<dd>Whether or not to show a button that will allow the user to confirm the notification.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">allowDismiss<span class="property-type">boolean</span></dt>
<dd>Whether or not to show a button that will allow the user to dismiss the notification.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">color<span class="property-type">string</span></dt>
<dd>The color that should be used for the notification border.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">confirmText<span class="property-type">string</span></dt>
<dd>The text that will displayed on the confirmation button.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">dismissText<span class="property-type">string</span></dt>
<dd>The text that will displayed on the dismiss button.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">displayTime<span class="property-type">number</span></dt>
<dd>Number of seconds before the notification will automatically close. Note: this needs to be overridden before the notification becomes visible!</dd>
</dl>
<dl class="message-properties">
<dt class="optional">position<span class="property-type">string</span></dt>
<dd>
The position on the screen whethere the notification will appear.
<ul>
<li><code>top right</code></li>
<li><code>top center</code></li>
<li><code>top left</code></li>
<li><code>bottom right</code></li>
<li><code>bottom center</code></li>
<li><code>bottom left</code></li>
<li><code>center center</code></li>
</ul>
</dd>
</dl>
<dl class="message-properties">
<dt class="optional">raw<span class="property-type">boolean</span></dt>
<dd>Whether you're passing in raw HTML that should be processed client-side.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">show<span class="property-type">boolean</span></dt>
<dd>Whether you want to show (even when no <code>msg.payload</code> available) or hide the notification.</dd>
</dl>
<dl class="message-properties">
<dt class="optional">showCountdown<span class="property-type">boolean</span></dt>
<dd>Whether or not to show a reducing progress bar to indicate the time remaining.</dd>
</dl>
</script>
21 changes: 20 additions & 1 deletion nodes/widgets/ui_notification.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
displayTime: { value: '3' },
showCountdown: { value: true },
outputs: { value: 1 },
allowDismiss: { value: 'OK' },
allowDismiss: { value: true },
dismissText: { value: 'Close' },
allowConfirm: { value: false },
confirmText: { value: 'Confirm' },
raw: { value: false },
className: { value: '' },
name: { value: '' }
Expand Down Expand Up @@ -50,6 +52,15 @@
}
})

$('#node-input-allowConfirm').on('change', function () {
const allowConfirm = $('#node-input-allowConfirm').is(':checked')
if (allowConfirm) {
$('#node-notification-confirmText').show()
} else {
$('#node-notification-confirmText').hide()
}
})

$('#node-input-colorDefault').on('change', function () {
const defaultColor = $('#node-input-colorDefault').is(':checked')
if (defaultColor) {
Expand Down Expand Up @@ -116,6 +127,14 @@
<label for="node-input-dismissText"><i class="fa fa-check"></i> Button Label</label>
<input type="text" id="node-input-dismissText" placeholder="Close">
</div>
<div class="form-row form-row-flex" id="node-notification-allowConfirm">
<input type="checkbox" id="node-input-allowConfirm">
<label for="node-input-allowConfirm"> Allow Manual Confirmation</label>
</div>
<div class="form-row form-row-flex" style="margin-left: 32px;" id="node-notification-confirmText">
<label for="node-input-confirmText"><i class="fa fa-check"></i> Button Label</label>
<input type="text" id="node-input-confirmText" placeholder="Confirm">
</div>
<div class="form-row form-row-flex" id="node-toast-raw">
<input type="checkbox" id="node-input-raw" style="display:inline-block; width:auto; vertical-align:baseline;">
<label style="width:auto" for="node-input-raw"> Accept raw HTML/JavaScript input in msg.payload to format popup.</label>
Expand Down
60 changes: 58 additions & 2 deletions nodes/widgets/ui_notification.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,70 @@
const statestore = require('../store/state.js')

module.exports = function (RED) {
function NotificationNode (config) {
const node = this

RED.nodes.createNode(this, config)

// which group are we rendering this widget
// Which ui are we rendering this widget.
// In contradiction to other ui nodes (which belong to a group), the notification node belongs to a ui instead.
const ui = RED.nodes.getNode(config.ui)

const evts = {
onAction: true,
beforeSend: function (msg) {
if (msg.ui_update) {
const updates = msg.ui_update

const allowedPositions = ['top right', 'top center', 'top left', 'bottom right', 'bottom center', 'bottom left', 'center center']

if (updates) {
if (typeof updates.allowConfirm !== 'undefined') {
// dynamically set "allowConfirm" property
statestore.set(ui, node, msg, 'allowConfirm', updates.allowConfirm)
}
if (typeof updates.allowDismiss !== 'undefined') {
// dynamically set "allowDismiss" property
statestore.set(ui, node, msg, 'allowDismiss', updates.allowDismiss)
}
if (typeof updates.color !== 'undefined') {
// dynamically set "color" property
statestore.set(ui, node, msg, 'color', updates.color)
}
if (typeof updates.confirmText !== 'undefined') {
// dynamically set "confirmText" property
statestore.set(ui, node, msg, 'confirmText', updates.confirmText)
}
if (typeof updates.dismissText !== 'undefined') {
// dynamically set "dismissText" property
statestore.set(ui, node, msg, 'dismissText', updates.dismissText)
}
if (typeof updates.displayTime !== 'undefined') {
// dynamically set "displayTime" property
statestore.set(ui, node, msg, 'displayTime', updates.displayTime)
}
if (typeof updates.position !== 'undefined' && allowedPositions.includes(updates.position)) {
// dynamically set "position" property
statestore.set(ui, node, msg, 'position', updates.position)
}
if (typeof updates.raw !== 'undefined') {
// dynamically set "raw" property
statestore.set(ui, node, msg, 'raw', updates.raw)
}
if (typeof updates.showCountdown !== 'undefined') {
// dynamically set "showCountdown" property
statestore.set(ui, node, msg, 'showCountdown', updates.showCountdown)
}
// Note that update.close will NOT be stored in the data store,
// since it does not need to be remembered
}
}
return msg
}
}

// inform the dashboard UI that we are adding this node
ui.register(null, null, node, config)
ui.register(null, null, node, config, evts)
}
RED.nodes.registerType('ui-notification', NotificationNode)
}
Loading

0 comments on commit ce226ab

Please sign in to comment.