From 3a3571b37eec2314d3f471d68797b8846c3bcc21 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 25 Apr 2025 15:51:10 +0100 Subject: [PATCH] Consolidate update widgets --- .../@node-red/editor-client/src/js/red.js | 18 +----- .../editor-client/src/js/ui/common/popover.js | 6 ++ .../editor-client/src/js/ui/palette-editor.js | 61 +++++++++++++------ .../@node-red/runtime/lib/telemetry/index.js | 7 +-- 4 files changed, 55 insertions(+), 37 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/src/js/red.js b/packages/node_modules/@node-red/editor-client/src/js/red.js index ab7effd89..99cb8375b 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/red.js +++ b/packages/node_modules/@node-red/editor-client/src/js/red.js @@ -317,7 +317,6 @@ var RED = (function() { function completeLoad(showProjectWelcome) { var persistentNotifications = {}; - let updateAvailableWidget = null RED.comms.subscribe("notification/#",function(topic,msg) { var parts = topic.split("/"); var notificationId = parts[1]; @@ -360,21 +359,8 @@ var RED = (function() { return; } if (notificationId === "update-available") { - if (!updateAvailableWidget) { - updateAvailableWidget = $('').text(RED._("telemetry.updateAvailable")); - updateAvailableWidget.on("click", function (evt) { - window.open(`https://github.com/node-red/node-red/releases/tag/${msg.version}`, "_blank"); - }); - const tooltip = RED.popover.tooltip(updateAvailableWidget, function () { - return RED._("telemetry.updateAvailableDesc", msg) - }); - RED.statusBar.add({ - id: "red-ui-status-update-available", - align: "right", - element: updateAvailableWidget - }); - setTimeout(() => { tooltip.open(); setTimeout(() => tooltip.close(), 7000) }, 1000) - } + // re-emit as an event to be handled in editor-client/src/js/ui/palette-editor.js + RED.events.emit("notification/update-available", msg) } if (msg.text) { msg.default = msg.text; diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js index 308f25f0e..a294bc484 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js @@ -163,13 +163,18 @@ RED.popover = (function() { } var timer = null; + let isOpen = false var active; var div; var contentDiv; var currentStyle; var openPopup = function(instant) { + if (isOpen) { + return + } if (active) { + isOpen = true var existingPopover = target.data("red-ui-popover"); if (options.tooltip && existingPopover) { active = false; @@ -334,6 +339,7 @@ RED.popover = (function() { } var closePopup = function(instant) { + isOpen = false $(document).off('mousedown.red-ui-popover'); if (!active) { if (div) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js index 9ed9e9bb7..7fc31e323 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js @@ -775,6 +775,14 @@ RED.palette.editor = (function() { } } }); + + RED.events.on("notification/update-available", function (msg) { + const updateKnownAbout = updateStatusState.version === msg.version + updateStatusState.version = msg.version + if (updateStatusWidgetPopover && !updateKnownAbout) { + setTimeout(() => { updateStatusWidgetPopover.open(); setTimeout(() => updateStatusWidgetPopover.close(), 20000) }, 1000) + } + }) } function getSettingsPane() { @@ -1509,19 +1517,34 @@ RED.palette.editor = (function() { } const updateStatusWidget = $(''); + let updateStatusWidgetPopover; + const updateStatusState = { moduleCount: 0 } let updateAvailable = []; function addUpdateInfoToStatusBar() { - updateStatusWidget.on("click", function (evt) { - RED.actions.invoke("core:manage-palette", { - view: "nodes", - filter: '"' + updateAvailable.join('", "') + '"' - }); - }); - - RED.popover.tooltip(updateStatusWidget, function () { - const count = updateAvailable.length || 0; - return RED._("palette.editor.updateCount", { count: count }); + updateStatusWidgetPopover = RED.popover.create({ + target: updateStatusWidget, + trigger: "click", + interactive: true, + direction: "bottom", + content: function () { + const count = updateAvailable.length || 0; + const content = $('
'); + if (updateStatusState.version) { + $(`${RED._("telemetry.updateAvailableDesc", updateStatusState)}`).appendTo(content) + } + if (count > 0) { + $(``).on("click", function (evt) { + updateStatusWidgetPopover.close() + RED.actions.invoke("core:manage-palette", { + view: "nodes", + filter: '"' + updateAvailable.join('", "') + '"' + }); + }).appendTo(content) + } + return content + }, + delay: { show: 750, hide: 250 } }); RED.statusBar.add({ @@ -1530,7 +1553,7 @@ RED.palette.editor = (function() { element: updateStatusWidget }); - updateStatus({ count: 0 }); + updateStatus(); } let pendingRefreshTimeout @@ -1553,16 +1576,20 @@ RED.palette.editor = (function() { } } } - - updateStatus({ count: updateAvailable.length }); + updateStatusState.moduleCount = updateAvailable.length; + updateStatus(); }, 200) } - function updateStatus(opts) { - if (opts.count) { - RED.statusBar.show("red-ui-status-package-update"); + function updateStatus() { + if (updateStatusState.moduleCount || updateStatusState.version) { updateStatusWidget.empty(); - $(' ' + opts.count + '').appendTo(updateStatusWidget); + let count = updateStatusState.moduleCount || 0; + if (updateStatusState.version) { + count ++ + } + $(` ${RED._("telemetry.updateAvailable", { count: count })}`).appendTo(updateStatusWidget); + RED.statusBar.show("red-ui-status-package-update"); } else { RED.statusBar.hide("red-ui-status-package-update"); } diff --git a/packages/node_modules/@node-red/runtime/lib/telemetry/index.js b/packages/node_modules/@node-red/runtime/lib/telemetry/index.js index 3ac619639..3c9c5ce4d 100644 --- a/packages/node_modules/@node-red/runtime/lib/telemetry/index.js +++ b/packages/node_modules/@node-red/runtime/lib/telemetry/index.js @@ -4,7 +4,7 @@ const semver = require('semver') const cronosjs = require('cronosjs') const METRICS_DIR = path.join(__dirname, 'metrics') -const INITIAL_PING_DELAY = 1000 * 60 * 30 // 5 minutes from startup +const INITIAL_PING_DELAY = 1000 * 60 * 30 // 30 minutes from startup let runtime @@ -148,9 +148,8 @@ function startTelemetry () { const pingTime = new Date(Date.now() + INITIAL_PING_DELAY) const pingMinutes = pingTime.getMinutes() const pingHours = pingTime.getHours() - // const pingSchedule = `${pingMinutes} ${pingHours} * * *` - // DO NOT COMMIT! - const pingSchedule = `* * * * *` + const pingSchedule = `${pingMinutes} ${pingHours} * * *` + runtime.log.debug(`Telemetry enabled. Schedule: ${pingSchedule}`) scheduleTask = cronosjs.scheduleTask(pingSchedule, () => {