diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json index 2a1e16f1d..33747b96d 100755 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -112,6 +112,7 @@ "editPalette":"Manage palette", "other": "Other", "showTips": "Show tips", + "showWelcomeTours": "Show guided tours for new versions", "help": "Node-RED website", "projects": "Projects", "projects-new": "New", 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 ad68ea612..d9ef01021 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 @@ -535,19 +535,18 @@ var RED = (function() { setTimeout(function() { loader.end(); + checkFirstRun(); },100); } - function showAbout() { - $.get('red/about', function(data) { - // data will be strictly markdown. Any HTML should be escaped. - data = RED.utils.sanitize(data); - var aboutHeader = '
'+ - ''+ - '
'; - - RED.sidebar.help.set(aboutHeader+RED.utils.renderMarkdown(data)); - }); + function checkFirstRun() { + if (RED.settings.theme("tours") === false) { + return; + } + if (!RED.settings.get("editor.view.view-show-welcome-tours", true)) { + return; + } + RED.actions.invoke("core:show-welcome-tour", RED.settings.get("editor.tours.welcome")); } function buildMainMenu() { @@ -696,9 +695,6 @@ var RED = (function() { $("#red-ui-main-container").show(); - - RED.actions.add("core:show-about", showAbout); - loadPluginList(); } diff --git a/packages/node_modules/@node-red/editor-client/src/js/settings.js b/packages/node_modules/@node-red/editor-client/src/js/settings.js index 467c5b569..1c6513c43 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/settings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/settings.js @@ -19,7 +19,6 @@ RED.settings = (function () { var loadedSettings = {}; var userSettings = {}; - var settingsDirty = false; var pendingSave; var hasLocalStorage = function () { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js index 6add6abe9..ed891c114 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tab-help.js @@ -25,7 +25,6 @@ RED.sidebar.help = (function() { var tocPanel; var helpIndex = {}; - function resizeStack() { var h = $(content).parent().height() - toolbar.outerHeight(); panels.resize(h) @@ -93,9 +92,28 @@ RED.sidebar.help = (function() { $(''+RED._("sidebar.help.noHelp")+'').appendTo(helpSection); treeList = $("
").css({width: "100%"}).appendTo(tocPanel).treeList({data: []}) + var pendingContentLoad; treeList.on('treelistselect', function(e,item) { + pendingContentLoad = item; if (item.nodeType) { - showHelp(item.nodeType); + showNodeTypeHelp(item.nodeType); + } else if (item.content) { + helpSection.empty(); + if (typeof item.content === "string") { + setInfoText(item.label, item.content); + } else if (typeof item.content === "function") { + if (item.content.length === 0) { + setInfoText(item.label, item.content()); + } else { + setInfoText(item.label, '
',helpSection) + item.content(function(content) { + if (pendingContentLoad === item) { + helpSection.empty(); + setInfoText(item.label, content); + } + }) + } + } } }) @@ -174,21 +192,28 @@ RED.sidebar.help = (function() { var moduleNames = Object.keys(modules); moduleNames.sort(); - var helpData = [{ + var nodeHelp = { label: RED._("sidebar.help.nodeHelp"), children: [], expanded: true - }] - + } + var helpData = [ + { + id: 'changelog', + label: "Node-RED v"+RED.settings.version, + content: getChangelog + }, + nodeHelp + ] var subflows = RED.nodes.registry.getNodeTypes().filter(function(t) {return /subflow/.test(t)}); if (subflows.length > 0) { - helpData[0].children.push({ + nodeHelp.children.push({ label: RED._("menu.label.subflows"), children: [] }) subflows.forEach(function(nodeType) { var sf = RED.nodes.getType(nodeType); - helpData[0].children[0].children.push({ + nodeHelp.children[0].children.push({ id:"node-type:"+nodeType, nodeType: nodeType, subflowLabel: sf.label().toLowerCase(), @@ -218,7 +243,7 @@ RED.sidebar.help = (function() { nodeTypes.sort(function(A,B) { return A.nodeType.localeCompare(B.nodeType) }) - helpData[0].children.push({ + nodeHelp.children.push({ id: moduleName, icon: "fa fa-cube", label: moduleName, @@ -244,7 +269,7 @@ RED.sidebar.help = (function() { return div; } - function showHelp(nodeType) { + function showNodeTypeHelp(nodeType) { helpSection.empty(); var helpText; var title; @@ -265,7 +290,7 @@ RED.sidebar.help = (function() { } } } - setInfoText(title, helpText, helpSection); + setInfoText(title, helpText); var ratio = panels.ratio(); if (ratio > 0.7) { @@ -282,7 +307,7 @@ RED.sidebar.help = (function() { } if (type) { // hideTOC(); - showHelp(type); + showNodeTypeHelp(type); } resizeStack(); } @@ -298,11 +323,12 @@ RED.sidebar.help = (function() { return el; } - function setInfoText(title, infoText,target) { + function setInfoText(title, infoText) { + helpSection.empty(); if (title) { - $("

",{class:"red-ui-help-title"}).text(title).appendTo(target); + $("

",{class:"red-ui-help-title"}).text(title).appendTo(helpSection); } - var info = addTargetToExternalLinks($('
'+infoText+'
')).appendTo(target); + var info = addTargetToExternalLinks($('
'+infoText+'
')).appendTo(helpSection); info.find(".red-ui-text-bidi-aware").contents().filter(function() { return this.nodeType === 3 && this.textContent.trim() !== "" }).wrap( "" ); var foldingHeader = "H3"; info.find(foldingHeader).wrapInner('') @@ -316,12 +342,12 @@ RED.sidebar.help = (function() { } $(this).toggleClass('expanded',!isExpanded); }) - target.parent().scrollTop(0); + helpSection.parent().scrollTop(0); } function set(html,title) { $(helpSection).empty(); - setInfoText(title,html,helpSection); + setInfoText(title,html); hideTOC(); show(); } @@ -336,13 +362,83 @@ RED.sidebar.help = (function() { if (node.type === "subflow" && node.direction) { // ignore subflow virtual ports } else if (node.type !== 'group'){ - showHelp(node.type); + showNodeTypeHelp(node.type); } } } } RED.events.on("view:selection-changed",refreshSelection); + function getChangelog(done) { + $.get('red/about', function(data) { + // data will be strictly markdown. Any HTML should be escaped. + data = RED.utils.sanitize(data); + RED.tourGuide.load("./tours/welcome.js", function(err, tour) { + var tourHeader = '
'; + if (tour) { + var currentVersionParts = RED.settings.version.split("."); + var tourVersionParts = tour.version.split("."); + if (tourVersionParts[0] === currentVersionParts[0] && tourVersionParts[1] === currentVersionParts[1]) { + tourHeader = '
' + } + } + var aboutHeader = '
'+tourHeader+'
' + done(aboutHeader+RED.utils.renderMarkdown(data)) + }); + + }); + } + function showAbout() { + treeList.treeList("show","changelog") + treeList.treeList("select","changelog"); + show(); + } + function showWelcomeTour(lastSeenVersion) { + RED.tourGuide.load("./tours/welcome.js", function(err, tour) { + if (err) { + console.warn("Failed to load welcome tour",err); + return; + } + var currentVersionParts = RED.settings.version.split("."); + var tourVersionParts = tour.version.split("."); + + // Only display the tour if its MAJ.MIN versions the current version + // This means if we update MAJ/MIN without updating the tour, the old tour won't get shown + if (tourVersionParts[0] !== currentVersionParts[0] || tourVersionParts[1] !== currentVersionParts[1]) { + return; + } + + if (lastSeenVersion) { + // Previously displayed a welcome tour. + if (lastSeenVersion === RED.settings.version) { + // Exact match - don't show the tour + return; + } + var lastSeenParts = lastSeenVersion.split("."); + if (currentVersionParts[0] < lastSeenParts[0] || (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] < lastSeenParts[1])) { + // Running an *older* version than last displayed tour. + return; + } + if (currentVersionParts[0] === lastSeenParts[0] && currentVersionParts[1] === lastSeenParts[1]) { + if (lastSeenParts.length === 3 && currentVersionParts.length === 3) { + // Matching non-beta MAJ.MIN - don't repeat tour + return; + } + if (currentVersionParts.length === 4 && (lastSeenParts.length === 3 || currentVersionParts[3] < lastSeenParts[3])) { + // Running an *older* beta than last displayed tour. + return + } + } + } + RED.tourGuide.run("./tours/welcome.js", function(err) { + RED.settings.set("editor.tours.welcome", RED.settings.version) + }) + }) + + } + RED.actions.add("core:show-about", showAbout); + RED.actions.add("core:show-welcome-tour", showWelcomeTour); + return { init: init, show: show, diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js b/packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js index 9044e5980..019a14d4d 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/tour/tourGuide.js @@ -15,17 +15,27 @@ RED.tourGuide = (function() { console.error(err); } }; + loadTour(tourPath, function(err, tour) { + if (err) { + console.warn("Error loading tour:",err); + return; + } + runTour(tour, done); + }) + + } + + function loadTour(tourPath, done) { if (tourCache[tourPath]) { - runTour(tourCache[tourPath],done); + done(null, tourCache[tourPath]); } else { /* jshint ignore:start */ // jshint<2.13 doesn't support dynamic imports. Once grunt-contrib-jshint // has been updated with the new jshint, we can stop ignoring this block import(tourPath).then(function(module) { tourCache[tourPath] = module.default; - runTour(tourCache[tourPath],done); + done(null, tourCache[tourPath]); }).catch(function(err) { - console.warn("Error loading tour:",err); done(err); }) /* jshint ignore:end */ @@ -357,7 +367,11 @@ RED.tourGuide = (function() { } return { - run: run + load: loadTour, + run: run, + reset: function() { + RED.settings.set("editor.tours.welcome",''); + } } diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js b/packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js index 2bdae4b13..3c1e295d2 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js @@ -139,7 +139,8 @@ RED.userSettings = (function() { { title: "menu.label.other", options: [ - {setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"} + {setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}, + {setting:"view-show-welcome-tours",label:"menu.label.showWelcomeTours",toggle:true,default:true} ] } ]; diff --git a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss index b397e05b7..eb0582ba1 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss @@ -295,7 +295,7 @@ $group-default-stroke: #999; $group-default-stroke-opacity: 1; $group-default-label-color: #a4a4a4; -$tourGuide-shade: rgba(100, 70, 70, 0.6); +$tourGuide-shade: $shade-color; $tourGuide-border: #a22222; $tourGuide-heading-color: #a22222; diff --git a/packages/node_modules/@node-red/editor-client/src/tours/welcome-2-1.js b/packages/node_modules/@node-red/editor-client/src/tours/welcome.js similarity index 93% rename from packages/node_modules/@node-red/editor-client/src/tours/welcome-2-1.js rename to packages/node_modules/@node-red/editor-client/src/tours/welcome.js index 33f6a1a88..1a4f59f9d 100644 --- a/packages/node_modules/@node-red/editor-client/src/tours/welcome-2-1.js +++ b/packages/node_modules/@node-red/editor-client/src/tours/welcome.js @@ -1,4 +1,5 @@ export default { + version: "2.1.0", steps: [ { titleIcon: "fa fa-map-o", @@ -11,11 +12,11 @@ export default { "

You can choose not to see this tour in the future by disabling it under the View tab of User Settings.

", }, { - prepare:function() { + prepare() { $("#red-ui-header-button-sidemenu").trigger("click"); $("#menu-item-edit-menu").parent().addClass("open") }, - complete: function() { + complete() { $("#menu-item-edit-menu").parent().removeClass("open") }, element: "#menu-item-edit-menu-submenu", @@ -27,11 +28,11 @@ export default { }, { - prepare: function() { + prepare() { $("#red-ui-header-button-sidemenu").trigger("click"); $("#menu-item-arrange-menu").parent().addClass("open") }, - complete: function() { + complete() { $("#menu-item-arrange-menu").parent().removeClass("open") }, element: "#menu-item-arrange-menu-submenu", @@ -46,7 +47,7 @@ export default { description: "

Flows and Groups can now have their own environment variables that can be referenced by nodes inside them.

", }, { - prepare: function(done) { + prepare(done) { RED.editor.editFlow(RED.nodes.workspace(RED.workspaces.active()),"editor-tab-envProperties"); setTimeout(done,800); }, @@ -57,7 +58,7 @@ export default { element: ".node-input-env-container-row .red-ui-editableList-addButton", direction: "top", description: '

The environment variables are listed in this table and new ones can be added by clicking the button.

', - complete: function() { + complete() { $("#node-dialog-cancel").trigger("click"); } },