From 58d67c972cee6adf5df468be7aaa23f6a14cdc4d Mon Sep 17 00:00:00 2001 From: abose Date: Thu, 27 Aug 2026 18:55:51 +0530 Subject: [PATCH] fix: ask about migration at most once and never block after that The dialog could reappear on every boot. Declining wrote nothing, and the done flag was only written on success, so saying no or losing the connection part way meant being asked again the next time the app opened, indefinitely. A prompted flag is now recorded before the question is even answered, so declining, closing the tab on the dialog, or a transfer that broke half way all count as having been asked. The automatic path never raises it again; the Help menu entry remains for a deliberate retry. An interrupted run used to fail silently on the automatic path, because the error was only reported when the user had started it from the menu. Someone who opted in and watched a task appear would then see nothing at all. Failures after the user accepts are now always reported, whichever path started it, and say that what already copied has been kept. Everything after the single question is now a notification rather than another modal: completion, partial failure, interruption, and the nothing-to-migrate and cannot-reach outcomes of a manual run. The completion notification carries the reload action, since copied extensions only load on the next boot. Exactly one modal dialog remains in the whole feature, the initial ask. --- docs/API-Reference/command/Commands.md | 6 ++ .../MigrateAssist/constants.js | 10 ++ .../MigrateAssist/migrator.js | 98 ++++++++++++------- src/nls/root/strings.js | 2 + src/styles/Extn-MigrateAssist.less | 15 +++ 5 files changed, 97 insertions(+), 34 deletions(-) diff --git a/docs/API-Reference/command/Commands.md b/docs/API-Reference/command/Commands.md index 37a71de251..08e2feb9ff 100644 --- a/docs/API-Reference/command/Commands.md +++ b/docs/API-Reference/command/Commands.md @@ -854,6 +854,12 @@ Checks for updates ## HELP\_AUTO\_UPDATE Toggles auto update +**Kind**: global variable + + +## HELP\_MIGRATE\_DATA +Migrates browser data from the legacy web origin + **Kind**: global variable diff --git a/src/extensionsIntegrated/MigrateAssist/constants.js b/src/extensionsIntegrated/MigrateAssist/constants.js index 1db7f0e090..ff366c1410 100644 --- a/src/extensionsIntegrated/MigrateAssist/constants.js +++ b/src/extensionsIntegrated/MigrateAssist/constants.js @@ -72,6 +72,15 @@ define(function (require, exports, module) { */ const MIGRATION_DONE_KEY = "migrateAssist.v1.done"; + /** + * PhStore key recording that the user has already been asked. The automatic path prompts at most + * once, whatever the outcome: declining, closing the tab, or a transfer that broke half way all + * count as having been asked. Re-prompting on every boot after any of those would be a nag, and + * the Help menu entry is always there for a deliberate retry. + * @type {string} + */ + const MIGRATION_PROMPTED_KEY = "migrateAssist.v1.prompted"; + /** * Dev only override, so the whole cross origin flow can be exercised on one dev server. * http://localhost:8000 and http://127.0.0.1:8000 are different origins with separate IndexedDB @@ -203,6 +212,7 @@ define(function (require, exports, module) { exports.SUNSET_DATE = SUNSET_DATE; exports.TWA_STORE_URL = TWA_STORE_URL; exports.MIGRATION_DONE_KEY = MIGRATION_DONE_KEY; + exports.MIGRATION_PROMPTED_KEY = MIGRATION_PROMPTED_KEY; exports.getLegacyOrigin = getLegacyOrigin; exports.getMigrateAssistURL = getMigrateAssistURL; exports.getLegacyDomainName = getLegacyDomainName; diff --git a/src/extensionsIntegrated/MigrateAssist/migrator.js b/src/extensionsIntegrated/MigrateAssist/migrator.js index b7276146bd..c7328cc36a 100644 --- a/src/extensionsIntegrated/MigrateAssist/migrator.js +++ b/src/extensionsIntegrated/MigrateAssist/migrator.js @@ -35,6 +35,7 @@ define(function (require, exports, module) { const Dialogs = require("widgets/Dialogs"), DefaultDialogs = require("widgets/DefaultDialogs"), + NotificationUI = require("widgets/NotificationUI"), Strings = require("strings"), StringUtils = require("utils/StringUtils"), Metrics = require("utils/Metrics"), @@ -51,6 +52,7 @@ define(function (require, exports, module) { const RESULT_MIGRATED = "migrated", RESULT_DECLINED = "declined", + RESULT_INTERRUPTED = "interrupted", RESULT_NOTHING = "nothing", RESULT_UNREACHABLE = "unreachable"; @@ -235,32 +237,39 @@ define(function (require, exports, module) { ).getPromise(); } + /** + * Everything after the single up front question is reported at the bottom of the window rather + * than in another modal. The user opted in and went back to work; interrupting them again to say + * it finished would undo the point of moving progress out of a dialog in the first place. + */ + function _toast(title, message, style, $extra) { + const $content = $("
").append($("
").text(message)); + if ($extra) { + $content.append($extra); + } + return NotificationUI.createToastFromTemplate(title, $content, { + dismissOnClick: false, // there is a close button, and a stray click must not eat the action + toastStyle: style + }); + } + function _showCompletion(migratedFiles, failed) { - const message = failed.length - ? StringUtils.format(Strings.MIGRATE_DONE_MESSAGE, migratedFiles) + "

" - + StringUtils.format(Strings.MIGRATE_DONE_PARTIAL, failed.length) - : StringUtils.format(Strings.MIGRATE_DONE_MESSAGE, migratedFiles); - Dialogs.showModalDialog( - DefaultDialogs.DIALOG_ID_INFO, - Strings.MIGRATE_DONE_TITLE, - message, - [ - { - className: Dialogs.DIALOG_BTN_CLASS_NORMAL, - id: Dialogs.DIALOG_BTN_CANCEL, - text: Strings.MIGRATE_RELOAD_LATER - }, - { - className: Dialogs.DIALOG_BTN_CLASS_PRIMARY, - id: Dialogs.DIALOG_BTN_OK, - text: Strings.MIGRATE_RELOAD_NOW - } - ] - ).done(function (buttonId) { - if (buttonId === Dialogs.DIALOG_BTN_OK) { - CommandManager.execute(Commands.APP_RELOAD); - } + const $actions = $("
").addClass("migrate-assist-toast-actions"); + const $reload = $("