From 27ad7279cd400c1656da844d6b0cd16e9b594d6a Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 27 Apr 2022 10:36:32 +0200 Subject: [PATCH] Rename NotificationController to AnnouncementController (#14389) * Rename NotificationController to AnnouncementController * Fix test * Add test for missing NotificationController state * Bump controllers * Move test to correct file * Rename config key * Add migration 71 to list of migrations * Fix selector after migration --- app/scripts/metamask-controller.js | 18 +-- app/scripts/migrations/071.js | 28 +++++ app/scripts/migrations/071.test.js | 107 ++++++++++++++++++ app/scripts/migrations/index.js | 2 + package.json | 2 +- .../app/whats-new-popup/whats-new-popup.js | 4 +- ui/pages/home/home.container.js | 4 +- ui/selectors/selectors.js | 30 ++--- yarn.lock | 43 ++++++- 9 files changed, 208 insertions(+), 30 deletions(-) create mode 100644 app/scripts/migrations/071.js create mode 100644 app/scripts/migrations/071.test.js diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 258fb0b68..66cff0823 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -30,7 +30,7 @@ import { ControllerMessenger, CurrencyRateController, PhishingController, - NotificationController, + AnnouncementController, GasFeeController, TokenListController, TokensController, @@ -454,9 +454,9 @@ export default class MetamaskController extends EventEmitter { this.phishingController = new PhishingController(); - this.notificationController = new NotificationController( - { allNotifications: UI_NOTIFICATIONS }, - initState.NotificationController, + this.announcementController = new AnnouncementController( + { allAnnouncements: UI_NOTIFICATIONS }, + initState.AnnouncementController, ); // token exchange rate tracker @@ -984,7 +984,7 @@ export default class MetamaskController extends EventEmitter { PermissionLogController: this.permissionLogController.store, SubjectMetadataController: this.subjectMetadataController, ThreeBoxController: this.threeBoxController.store, - NotificationController: this.notificationController, + AnnouncementController: this.announcementController, GasFeeController: this.gasFeeController, TokenListController: this.tokenListController, TokensController: this.tokensController, @@ -1024,7 +1024,7 @@ export default class MetamaskController extends EventEmitter { SwapsController: this.swapsController.store, EnsController: this.ensController.store, ApprovalController: this.approvalController, - NotificationController: this.notificationController, + AnnouncementController: this.announcementController, GasFeeController: this.gasFeeController, TokenListController: this.tokenListController, TokensController: this.tokensController, @@ -1369,7 +1369,7 @@ export default class MetamaskController extends EventEmitter { keyringController, metaMetricsController, networkController, - notificationController, + announcementController, onboardingController, permissionController, preferencesController, @@ -1824,8 +1824,8 @@ export default class MetamaskController extends EventEmitter { }, // Notifications - updateViewedNotifications: notificationController.updateViewed.bind( - notificationController, + updateViewedNotifications: announcementController.updateViewed.bind( + announcementController, ), // GasFeeController diff --git a/app/scripts/migrations/071.js b/app/scripts/migrations/071.js new file mode 100644 index 000000000..9f07ecd93 --- /dev/null +++ b/app/scripts/migrations/071.js @@ -0,0 +1,28 @@ +import { cloneDeep } from 'lodash'; + +const version = 71; + +/** + * Renames NotificationController to AnnouncementController + */ +export default { + version, + async migrate(originalVersionedData) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + const state = versionedData.data; + const newState = transformState(state); + versionedData.data = newState; + return versionedData; + }, +}; + +function transformState(state) { + if (state.NotificationController) { + state.AnnouncementController = { + announcements: state.NotificationController.notifications, + }; + delete state.NotificationController; + } + return state; +} diff --git a/app/scripts/migrations/071.test.js b/app/scripts/migrations/071.test.js new file mode 100644 index 000000000..78a2bded1 --- /dev/null +++ b/app/scripts/migrations/071.test.js @@ -0,0 +1,107 @@ +import migration71 from './071'; + +describe('migration #71', () => { + it('should update the version metadata', async () => { + const oldStorage = { + meta: { + version: 70, + }, + data: {}, + }; + + const newStorage = await migration71.migrate(oldStorage); + expect(newStorage.meta).toStrictEqual({ + version: 71, + }); + }); + + it('should rename NotificationController', async () => { + const oldStorage = { + meta: { + version: 70, + }, + data: { + FooController: { a: 'b' }, + NotificationController: { + notifications: [ + { + date: '2021-03-17', + id: 1, + image: { + height: '230px', + placeImageBelowDescription: true, + src: 'images/mobile-link-qr.svg', + width: '230px', + }, + isShown: false, + }, + { date: '2021-03-08', id: 3, isShown: false }, + { + date: '2021-05-11', + id: 4, + image: { src: 'images/source-logos-bsc.svg', width: '100%' }, + isShown: false, + }, + { date: '2021-06-09', id: 5, isShown: false }, + { date: '2021-05-26', id: 6, isShown: false }, + { date: '2021-09-17', id: 7, isShown: false }, + { date: '2021-11-01', id: 8, isShown: false }, + { + date: '2021-12-07', + id: 9, + image: { src: 'images/txinsights.png', width: '80%' }, + isShown: false, + }, + { + date: '2022-04-18', + id: 10, + image: { src: 'images/token-detection.svg', width: '100%' }, + isShown: false, + }, + { date: '2022-04-18', id: 11, isShown: false }, + { + date: '2022-05-18', + id: 12, + image: { src: 'images/darkmode-banner.png', width: '100%' }, + isShown: true, + }, + ], + }, + }, + }; + + const newStorage = await migration71.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 71, + }, + data: { + FooController: { a: 'b' }, + AnnouncementController: { + announcements: oldStorage.data.NotificationController.notifications, + }, + }, + }); + }); + + it('should handle missing NotificationController', async () => { + const oldStorage = { + meta: { + version: 70, + }, + data: { + FooController: { a: 'b' }, + }, + }; + + const newStorage = await migration71.migrate(oldStorage); + expect(newStorage).toStrictEqual({ + meta: { + version: 71, + }, + data: { + FooController: { a: 'b' }, + }, + }); + }); +}); diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index fe308e302..321b91319 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -74,6 +74,7 @@ import m067 from './067'; import m068 from './068'; import m069 from './069'; import m070 from './070'; +import m071 from './071'; const migrations = [ m002, @@ -145,6 +146,7 @@ const migrations = [ m068, m069, m070, + m071, ]; export default migrations; diff --git a/package.json b/package.json index 708fc7c6f..f438faf46 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "@keystonehq/metamask-airgapped-keyring": "0.2.1", "@material-ui/core": "^4.11.0", "@metamask/contract-metadata": "^1.31.0", - "@metamask/controllers": "^27.0.0", + "@metamask/controllers": "^28.0.0", "@metamask/design-tokens": "^1.5.1", "@metamask/eth-ledger-bridge-keyring": "^0.11.0", "@metamask/eth-token-tracker": "^4.0.0", diff --git a/ui/components/app/whats-new-popup/whats-new-popup.js b/ui/components/app/whats-new-popup/whats-new-popup.js index 4d47ee262..59b171102 100644 --- a/ui/components/app/whats-new-popup/whats-new-popup.js +++ b/ui/components/app/whats-new-popup/whats-new-popup.js @@ -11,7 +11,7 @@ import Popover from '../../ui/popover'; import Typography from '../../ui/typography'; import { updateViewedNotifications } from '../../../store/actions'; import { getTranslatedUINoficiations } from '../../../../shared/notifications'; -import { getSortedNotificationsToShow } from '../../../selectors'; +import { getSortedAnnouncementsToShow } from '../../../selectors'; import { BUILD_QUOTE_ROUTE, ADVANCED_ROUTE, @@ -172,7 +172,7 @@ export default function WhatsNewPopup({ onClose }) { const t = useContext(I18nContext); const history = useHistory(); - const notifications = useSelector(getSortedNotificationsToShow); + const notifications = useSelector(getSortedAnnouncementsToShow); const locale = useSelector(getCurrentLocale); const [seenNotifications, setSeenNotifications] = useState({}); diff --git a/ui/pages/home/home.container.js b/ui/pages/home/home.container.js index 103b40ddb..466b23c51 100644 --- a/ui/pages/home/home.container.js +++ b/ui/pages/home/home.container.js @@ -13,7 +13,7 @@ import { unconfirmedTransactionsCountSelector, getInfuraBlocked, getShowWhatsNewPopup, - getSortedNotificationsToShow, + getSortedAnnouncementsToShow, getShowRecoveryPhraseReminder, getNewNetworkAdded, hasUnsignedQRHardwareTransaction, @@ -124,7 +124,7 @@ const mapStateToProps = (state) => { shouldShowWeb3ShimUsageNotification, pendingConfirmations, infuraBlocked: getInfuraBlocked(state), - notificationsToShow: getSortedNotificationsToShow(state).length > 0, + notificationsToShow: getSortedAnnouncementsToShow(state).length > 0, ///: BEGIN:ONLY_INCLUDE_IN(flask) errorsToShow: metamask.snapErrors, shouldShowErrors: Object.entries(metamask.snapErrors || []).length > 0, diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 49dc9cccc..244545d0e 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -727,12 +727,12 @@ export const getSnapsRouteObjects = createSelector(getSnaps, (snaps) => { ///: END:ONLY_INCLUDE_IN /** - * Get an object of notification IDs and if they are allowed or not. + * Get an object of announcement IDs and if they are allowed or not. * * @param {Object} state * @returns {Object} */ -function getAllowedNotificationIds(state) { +function getAllowedAnnouncementIds(state) { const currentKeyring = getCurrentKeyring(state); const currentKeyringIsLedger = currentKeyring?.type === KEYRING_TYPES.LEDGER; const supportsWebHid = window.navigator.hid !== undefined; @@ -762,28 +762,28 @@ function getAllowedNotificationIds(state) { */ /** - * Notifications are managed by the notification controller and referenced by - * `state.metamask.notifications`. This function returns a list of notifications - * the can be shown to the user. This list includes all notifications that do not + * Announcements are managed by the announcement controller and referenced by + * `state.metamask.announcements`. This function returns a list of announcements + * the can be shown to the user. This list includes all announcements that do not * have a truthy `isShown` property. * - * The returned notifications are sorted by date. + * The returned announcements are sorted by date. * * @param {Object} state - the redux state object - * @returns {Notification[]} An array of notifications that can be shown to the user + * @returns {Announcement[]} An array of announcements that can be shown to the user */ -export function getSortedNotificationsToShow(state) { - const notifications = Object.values(state.metamask.notifications); - const allowedNotificationIds = getAllowedNotificationIds(state); - const notificationsToShow = notifications.filter( - (notification) => - !notification.isShown && allowedNotificationIds[notification.id], +export function getSortedAnnouncementsToShow(state) { + const announcements = Object.values(state.metamask.announcements); + const allowedAnnouncementIds = getAllowedAnnouncementIds(state); + const announcementsToShow = announcements.filter( + (announcement) => + !announcement.isShown && allowedAnnouncementIds[announcement.id], ); - const notificationsSortedByDate = notificationsToShow.sort( + const announcementsSortedByDate = announcementsToShow.sort( (a, b) => new Date(b.date) - new Date(a.date), ); - return notificationsSortedByDate; + return announcementsSortedByDate; } export function getShowRecoveryPhraseReminder(state) { diff --git a/yarn.lock b/yarn.lock index be324d3c0..7c3b1f58b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2770,7 +2770,7 @@ web3 "^0.20.7" web3-provider-engine "^16.0.3" -"@metamask/controllers@^27.0.0", "@metamask/controllers@^27.1.1": +"@metamask/controllers@^27.1.1": version "27.1.1" resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-27.1.1.tgz#b3288bfd05e381e9e32ed60b68a09b2855db1140" integrity sha512-RzQ4zKsqmieYqAiVsIIazLTo9GYMcm9fDhYPJklP1M+bzm1k49GRFnZEfru3w/dPVY+wWgcDo/0ZWlOILbu3hg== @@ -2811,6 +2811,47 @@ web3 "^0.20.7" web3-provider-engine "^16.0.3" +"@metamask/controllers@^28.0.0": + version "28.0.0" + resolved "https://registry.yarnpkg.com/@metamask/controllers/-/controllers-28.0.0.tgz#dbde11df635daeb9d73ff989cb274f94f913ff39" + integrity sha512-ABIZ5OO6g9DzyKrDB0yr1KzyleqVZ4V2d9S8jaToz5AaDZ0tnVkcKptCtRfhzV8xC23xynKjoO7cU9ZkDXBbjw== + dependencies: + "@ethereumjs/common" "^2.3.1" + "@ethereumjs/tx" "^3.2.1" + "@keystonehq/metamask-airgapped-keyring" "^0.3.0" + "@metamask/contract-metadata" "^1.33.0" + "@metamask/metamask-eth-abis" "3.0.0" + "@metamask/types" "^1.1.0" + "@types/uuid" "^8.3.0" + abort-controller "^3.0.0" + async-mutex "^0.2.6" + babel-runtime "^6.26.0" + deep-freeze-strict "^1.1.1" + eth-ens-namehash "^2.0.8" + eth-json-rpc-infura "^5.1.0" + eth-keyring-controller "^6.2.1" + eth-method-registry "1.1.0" + eth-phishing-detect "^1.1.16" + eth-query "^2.1.2" + eth-rpc-errors "^4.0.0" + eth-sig-util "^3.0.0" + ethereumjs-util "^7.0.10" + ethereumjs-wallet "^1.0.1" + ethers "^5.4.1" + ethjs-unit "^0.1.6" + fast-deep-equal "^3.1.3" + immer "^9.0.6" + isomorphic-fetch "^3.0.0" + json-rpc-engine "^6.1.0" + jsonschema "^1.2.4" + multiformats "^9.5.2" + nanoid "^3.1.31" + punycode "^2.1.1" + single-call-balance-checker-abi "^1.0.0" + uuid "^8.3.2" + web3 "^0.20.7" + web3-provider-engine "^16.0.3" + "@metamask/design-tokens@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@metamask/design-tokens/-/design-tokens-1.5.1.tgz#723f10bc5fe03ce14d47b1ad6190a835df62745a"