From e6360f85137eb097e3370fad45119c25ff782681 Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 13 May 2026 20:20:16 +0530 Subject: [PATCH 1/4] fix(tour): run guided-tour orchestration once on every boot The Phoenix onboarding tour and the newly-added-features markdown were both wired up in ways that left users in non-default native projects silently un-onboarded. Two specific gaps: - new-project.js only called guidedTour.startTourIfNeeded() from closeDialogue() (fires when the new-project dialog is opened and then dismissed via openFolder) and from init() when the welcome screen pref was off. On a native app with a non-default project open, _shouldNotShowDialog() returned true and the dialog was never shown, so startTourIfNeeded() was never reached and the tour could not fire on any subsequent boot either. - newly-added-features.init() was called directly from main.js regardless of project context, so the "what's new" markdown could open under a user's current project tabs instead of the welcome project. Move all post-boot orchestration to guided-tour.js, fire it from a single _bootDonePromise.then() in new-project.js, and gate the "newly added features" surfacing on a real higher-version change (detected via semver vs the new userAlreadyDidAction.lastSeenAppVersion). On a higher version we switch to the welcome project first so the markdown lands in the onboarding context. Downgrades are a no-op and leave state untouched so a future re-upgrade to a previously-seen version does not re-fire. PhoenixTour stays a once-per-lifetime overlay tour gated by its own CURRENT_TOUR_VERSION constant. --- .../Phoenix/guided-tour.js | 78 ++++++++++++++++++- src/extensionsIntegrated/Phoenix/main.js | 2 - .../Phoenix/new-project.js | 14 +++- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/extensionsIntegrated/Phoenix/guided-tour.js b/src/extensionsIntegrated/Phoenix/guided-tour.js index 03e81533d4..54b6050dc7 100644 --- a/src/extensionsIntegrated/Phoenix/guided-tour.js +++ b/src/extensionsIntegrated/Phoenix/guided-tour.js @@ -1,7 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-only // Copyright (c) 2021 - present core.ai. All rights reserved. -/*global logger*/ +/*global logger, jsPromise*/ define(function (require, exports, module) { const KernalModeTrust = window.KernalModeTrust; @@ -21,9 +21,80 @@ define(function (require, exports, module) { Mustache = require("thirdparty/mustache/mustache"), SurveyTemplate = require("text!./html/survey-template.html"), PhoenixTour = require("./phoenix-tour"), + newFeature = require("./newly-added-features"), + ProjectManager = require("project/ProjectManager"), + semver = require("thirdparty/semver.browser"), NOTIFICATION_BACKOFF = 10000, GUIDED_TOUR_LOCAL_STORAGE_KEY = "guidedTourActions"; + function _currentAppVersion() { + return window.AppConfig && window.AppConfig.apiVersion; + } + + function _isNewerVersion(v1, v2) { + try { + return semver.gt(v1, v2); + } catch (e) { + return false; + } + } + + /** + * Switch to the welcome project if we're not already there. Returns a + * native Promise that resolves once the switch completes (or + * immediately if no switch is needed). openProject returns a jQuery + * deferred, so we adapt via jsPromise and swallow rejections so + * downstream onboarding still runs against whatever project ended up + * open. + */ + function _switchToWelcomeProject() { + const welcomePath = ProjectManager.getWelcomeProjectPath(); + const currentPath = ProjectManager.getProjectRoot().fullPath; + if (currentPath === welcomePath) { + return Promise.resolve(); + } + console.log("Guided tour: switching to welcome project for onboarding"); + return jsPromise(ProjectManager.openProject(welcomePath)).catch(function () { }); + } + + /** + * If the app was bumped to a newer version since we last recorded a + * boot, switch to the welcome project and surface the "newly added + * features" markdown there (the tour's intended onboarding context). + * - First time we see this user: just record current and return; the + * one-shot PhoenixTour handles fresh-user onboarding. + * - Same version as recorded: no-op. + * - Newer version than recorded: switch project + run newFeature.init. + * - Lower version (downgrade): no-op, leave state untouched so a + * future re-upgrade to the recorded version doesn't re-fire. + */ + function _maybeShowNewFeaturesForVersionChange() { + const current = _currentAppVersion(); + if (!current) { + return; + } + const lastSeen = userAlreadyDidAction.lastSeenAppVersion; + if (lastSeen === current) { + return; + } + if (!lastSeen) { + // First time we're recording — no prior to compare against. + userAlreadyDidAction.lastSeenAppVersion = current; + PhStore.setItem(GUIDED_TOUR_LOCAL_STORAGE_KEY, JSON.stringify(userAlreadyDidAction)); + return; + } + if (!_isNewerVersion(current, lastSeen)) { + // Downgrade — don't refresh, don't update state, so a + // future re-upgrade to lastSeen doesn't fire again. + return; + } + _switchToWelcomeProject().then(function () { + newFeature.init(); + userAlreadyDidAction.lastSeenAppVersion = current; + PhStore.setItem(GUIDED_TOUR_LOCAL_STORAGE_KEY, JSON.stringify(userAlreadyDidAction)); + }); + } + const surveyLinksURL = "https://updates.phcode.io/surveys.json"; // All popup notifications will show immediately on boot, we don't want to interrupt user amidst his work @@ -280,6 +351,11 @@ define(function (require, exports, module) { tourStarted = true; _showBeautifyNotification(); _showSurveys(); + // PhoenixTour is a once-per-lifetime overlay tour with its own + // internal _shouldRun gate; safe to call every boot. PhoenixTour.startTour(); + // On a higher-version change, land on the welcome project and + // surface the newly-added-features markdown. + _maybeShowNewFeaturesForVersionChange(); }; }); diff --git a/src/extensionsIntegrated/Phoenix/main.js b/src/extensionsIntegrated/Phoenix/main.js index 3bf88e91e0..7b7fa7419c 100644 --- a/src/extensionsIntegrated/Phoenix/main.js +++ b/src/extensionsIntegrated/Phoenix/main.js @@ -26,7 +26,6 @@ define(function (require, exports, module) { const serverSync = require("./serverSync"), newProject = require("./new-project"), defaultProjects = require("./default-projects"), - newFeature = require("./newly-added-features"), AppInit = require("utils/AppInit"), Strings = require("strings"), Dialogs = require("widgets/Dialogs"), @@ -95,7 +94,6 @@ define(function (require, exports, module) { serverSync.init(); defaultProjects.init(); newProject.init(); - newFeature.init(); _detectUnSupportedBrowser(); _persistBrowserStorage(); }); diff --git a/src/extensionsIntegrated/Phoenix/new-project.js b/src/extensionsIntegrated/Phoenix/new-project.js index 470d36bb94..61156349b3 100644 --- a/src/extensionsIntegrated/Phoenix/new-project.js +++ b/src/extensionsIntegrated/Phoenix/new-project.js @@ -101,7 +101,6 @@ define(function (require, exports, module) { Metrics.countEvent(Metrics.EVENT_TYPE.NEW_PROJECT, "dialogue", "close"); newProjectDialogueObj.close(); exports.trigger(exports.EVENT_NEW_PROJECT_DIALOGUE_CLOSED); - guidedTour.startTourIfNeeded(); } function showErrorDialogue(title, message) { @@ -149,6 +148,18 @@ define(function (require, exports, module) { let _bootDoneDeferred = new $.Deferred(); let _bootDonePromise = jsPromise(_bootDoneDeferred.promise()); + // Fire the guided tour once on every boot, regardless of how the + // new-project dialog flow resolved. Previously this was called from + // a few specific paths (closeDialogue, init when welcome screen + // disabled), which left users in non-default projects on native app + // never seeing the tour. The individual notifications inside + // startTourIfNeeded (beautify hint, surveys, one-shot PhoenixTour + // overlay, newly-added-features markdown on version bump) all have + // their own internal gating so it's safe to call every boot. + _bootDonePromise.then(function () { + guidedTour.startTourIfNeeded(); + }); + function onBootComplete() { return _bootDonePromise; } @@ -158,7 +169,6 @@ define(function (require, exports, module) { const shouldShowWelcome = PhStore.getItem("new-project.showWelcomeScreen") || 'Y'; if(shouldShowWelcome !== 'Y') { Metrics.countEvent(Metrics.EVENT_TYPE.NEW_PROJECT, "dialogue", "disabled"); - guidedTour.startTourIfNeeded(); _bootDoneDeferred.resolve(); return; } From c598538fa472f763f2e38c56854f5f327d3eed31 Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 13 May 2026 20:21:42 +0530 Subject: [PATCH 2/4] chore: update pro deps --- src-node/package-lock.json | 4 ++-- tracking-repos.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src-node/package-lock.json b/src-node/package-lock.json index 287070c6e5..4350321b3d 100644 --- a/src-node/package-lock.json +++ b/src-node/package-lock.json @@ -1,12 +1,12 @@ { "name": "@phcode/node-core", - "version": "5.1.9-0", + "version": "5.1.10-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@phcode/node-core", - "version": "5.1.9-0", + "version": "5.1.10-0", "hasInstallScript": true, "license": "GNU-AGPL3.0", "dependencies": { diff --git a/tracking-repos.json b/tracking-repos.json index 25e55cc2fa..0fab4fccf1 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "11fec38adda6438d047e58ae6b32bced6fb6d48b" + "commitID": "6bac7181bc50b7097c391dc5d423cfc6e69f7f9d" } } From c92990a1773d78c5eb6865975c404c25af943ddf Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 13 May 2026 20:31:47 +0530 Subject: [PATCH 3/4] chore: update pro deps --- tracking-repos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking-repos.json b/tracking-repos.json index 0fab4fccf1..60daecfc82 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "6bac7181bc50b7097c391dc5d423cfc6e69f7f9d" + "commitID": "e2be0be33c19344f7518c098262e7db12daf1e6d" } } From ab114ec4334a6e1f2d8bf928f206bd187ba80660 Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 13 May 2026 21:02:52 +0530 Subject: [PATCH 4/4] chore: update pro deps --- tracking-repos.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tracking-repos.json b/tracking-repos.json index 60daecfc82..b95fadce65 100644 --- a/tracking-repos.json +++ b/tracking-repos.json @@ -1,5 +1,5 @@ { "phoenixPro": { - "commitID": "e2be0be33c19344f7518c098262e7db12daf1e6d" + "commitID": "cc421cb18c699ff30d1a886b952e5518efd79b48" } }