Skip to content

Commit 958032a

Browse files
feat: improve windows managemet when switching to popup [LW 12347] (#1728)
* feat: improve logging * feat: improve windows managemet when switching to popup
1 parent 222f5ac commit 958032a

File tree

10 files changed

+60
-30
lines changed

10 files changed

+60
-30
lines changed

apps/browser-extension-wallet/src/components/MainMenu/DropdownMenuOverlay/DropdownMenuOverlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const DropdownMenuOverlay: VFC<Props> = ({
120120
if (activated) {
121121
await posthog.sendEvent(PostHogAction.SettingsSwitchToNamiClick);
122122
try {
123-
await backgroundServices.handleOpenPopup();
123+
await backgroundServices.closeAllTabsAndOpenPopup();
124124
} catch (error) {
125125
logger.warn(error);
126126
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { closeAllLaceWindows } from '@lib/scripts/background/util';
1+
import { closeAllLaceOrNamiTabs } from '@lib/scripts/background/util';
22
import { MessageSender, NamiMessages } from '../shared/types';
33
import { logger } from '@lace/common';
44

@@ -8,7 +8,7 @@ export const createLaceMigrationOpenListener =
88
logger.debug('[NAMI MIGRATION] createLaceMigrationOpenListener', message, sender);
99
if (message === NamiMessages.open && sender.id === namiExtensionId) {
1010
// First close all open lace tabs
11-
await closeAllLaceWindows();
11+
await closeAllLaceOrNamiTabs();
1212
createTab({ url: `chrome-extension://${laceExtensionId}/app.html` });
1313
}
1414
};

apps/browser-extension-wallet/src/hooks/useFatalError.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ObservableWallet } from '@cardano-sdk/wallet';
2-
import { useObservable } from '@lace/common';
2+
import { logger, useObservable } from '@lace/common';
33
import { useBackgroundServiceAPIContext } from '@providers';
44
import { useWalletStore } from '@src/stores';
55
import { useMemo } from 'react';
@@ -57,11 +57,11 @@ export const useFatalError = (): FatalError | undefined => {
5757
const walletError = useObservable(walletError$);
5858

5959
if (unhandledServiceWorkerError) {
60-
console.error('useFatalError (service worker):', unhandledServiceWorkerError);
60+
logger.error('useFatalError (service worker):', unhandledServiceWorkerError);
6161
}
6262

6363
if (walletError) {
64-
console.error('useFatalError (wallet):', walletError);
64+
logger.error('useFatalError (wallet):', walletError);
6565
}
6666

6767
return unhandledServiceWorkerError || walletError;

apps/browser-extension-wallet/src/lib/scripts/background/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const backgroundServiceProperties: RemoteApiProperties<BackgroundService>
2020
},
2121
handleOpenBrowser: RemoteApiPropertyType.MethodReturningPromise,
2222
handleOpenNamiBrowser: RemoteApiPropertyType.MethodReturningPromise,
23-
handleOpenPopup: RemoteApiPropertyType.MethodReturningPromise,
23+
closeAllTabsAndOpenPopup: RemoteApiPropertyType.MethodReturningPromise,
2424
handleChangeTheme: RemoteApiPropertyType.MethodReturningPromise,
2525
handleChangeMode: RemoteApiPropertyType.MethodReturningPromise,
2626
clearBackgroundStorage: RemoteApiPropertyType.MethodReturningPromise,

apps/browser-extension-wallet/src/lib/scripts/background/services/utilityServices.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable no-magic-numbers */
2-
import { runtime, tabs, storage as webStorage } from 'webextension-polyfill';
2+
import { runtime, tabs, storage as webStorage, windows, action, Tabs, Windows } from 'webextension-polyfill';
33
import {
44
BackgroundService,
55
BaseChannels,
@@ -22,12 +22,13 @@ import { backgroundServiceProperties } from '../config';
2222
import { exposeApi } from '@cardano-sdk/web-extension';
2323
import { Cardano } from '@cardano-sdk/core';
2424
import { config } from '@src/config';
25-
import { getADAPriceFromBackgroundStorage, closeAllLaceWindows } from '../util';
25+
import { getADAPriceFromBackgroundStorage, closeAllLaceOrNamiTabs } from '../util';
2626
import { currencies as currenciesMap, currencyCode } from '@providers/currency/constants';
2727
import { clearBackgroundStorage, getBackgroundStorage, setBackgroundStorage } from '../storage';
2828
import { laceFeaturesApiProperties, LACE_FEATURES_CHANNEL } from '../injectUtil';
2929
import { getErrorMessage } from '@src/utils/get-error-message';
3030
import { logger } from '@lace/common';
31+
import { POPUP_WINDOW_NAMI_TITLE } from '@utils/constants';
3132

3233
export const requestMessage$ = new Subject<Message>();
3334
export const backendFailures$ = new BehaviorSubject(0);
@@ -109,18 +110,43 @@ const handleOpenNamiBrowser = async (data: OpenNamiBrowserData) => {
109110
await tabs.create({ url: `popup.html#${data.path}` }).catch((error) => logger.error(error));
110111
};
111112

112-
const handleOpenPopup = async () => {
113-
if (typeof chrome.action.openPopup !== 'function') return;
113+
const enrichWithTabsDataIfMissing = (browserWindows: Windows.Window[]) => {
114+
const promises = browserWindows.map(async (w) => ({
115+
...w,
116+
tabs: w.tabs || (await tabs.query({ windowId: w.id }))
117+
}));
118+
return Promise.all(promises);
119+
};
120+
121+
// Yes, Nami mode can be rendered as tab
122+
const isLaceOrNamiTab = (tab: Tabs.Tab) => ['Lace', POPUP_WINDOW_NAMI_TITLE].includes(tab.title);
123+
124+
type WindowWithTabsNotOptional = Windows.Window & {
125+
tabs: Tabs.Tab[];
126+
};
127+
const doesWindowHaveOtherTabs = (browserWindow: WindowWithTabsNotOptional) =>
128+
browserWindow.tabs.some((t) => !isLaceOrNamiTab(t));
129+
130+
const closeAllTabsAndOpenPopup = async () => {
114131
try {
115-
const [currentWindow] = await tabs.query({ currentWindow: true, title: 'Lace' });
116-
await closeAllLaceWindows();
117-
// behaves inconsistently if executed without setTimeout
118-
setTimeout(async () => {
119-
if (currentWindow?.windowId) {
120-
await chrome.windows.update(currentWindow.windowId, { focused: true });
121-
await chrome.action.openPopup();
122-
}
123-
}, 30);
132+
const allWindows = await enrichWithTabsDataIfMissing(await windows.getAll());
133+
if (allWindows.length === 0) return;
134+
135+
const windowsWith3rdPartyTabs = allWindows.filter((w) => doesWindowHaveOtherTabs(w));
136+
const candidateWindowsWithPreferenceForCurrentlyFocused = windowsWith3rdPartyTabs.sort(
137+
(w1, w2) => Number(w2.focused) - Number(w1.focused)
138+
);
139+
140+
let nextFocusedWindow = candidateWindowsWithPreferenceForCurrentlyFocused[0];
141+
const noSingleWindowWith3rdPartyTabsOpen = !nextFocusedWindow;
142+
if (noSingleWindowWith3rdPartyTabsOpen) {
143+
nextFocusedWindow = allWindows[0];
144+
await tabs.create({ active: true, windowId: nextFocusedWindow.id });
145+
}
146+
147+
await windows.update(nextFocusedWindow.id, { focused: true });
148+
await closeAllLaceOrNamiTabs();
149+
await action.openPopup();
124150
} catch (error) {
125151
// unable to programatically open the popup again
126152
logger.error(error);
@@ -225,9 +251,9 @@ const toUnhandledError = (error: unknown, type: UnhandledError['type']): Unhandl
225251
message: getErrorMessage(error)
226252
});
227253
const unhandledError$ = merge(
228-
fromEvent(globalThis, 'error').pipe(map((e: ErrorEvent): UnhandledError => toUnhandledError(e, 'error'))),
254+
fromEvent(globalThis, 'error').pipe(map((e: ErrorEvent): UnhandledError => toUnhandledError(e.error, 'error'))),
229255
fromEvent(globalThis, 'unhandledrejection').pipe(
230-
map((e: PromiseRejectionEvent): UnhandledError => toUnhandledError(e, 'unhandledrejection'))
256+
map((e: PromiseRejectionEvent): UnhandledError => toUnhandledError(e.reason, 'unhandledrejection'))
231257
)
232258
);
233259

@@ -238,7 +264,7 @@ exposeApi<BackgroundService>(
238264
api$: of({
239265
handleOpenBrowser,
240266
handleOpenNamiBrowser,
241-
handleOpenPopup,
267+
closeAllTabsAndOpenPopup,
242268
requestMessage$,
243269
migrationState$,
244270
coinPrices,

apps/browser-extension-wallet/src/lib/scripts/background/util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export const getActiveWallet = async ({
124124
return { wallet, account };
125125
};
126126

127-
export const closeAllLaceWindows = async (shouldRemoveTab?: (url: string) => boolean): Promise<void> => {
127+
export const closeAllLaceOrNamiTabs = async (shouldRemoveTab?: (url: string) => boolean): Promise<void> => {
128128
const openTabs = await tabs.query({ title: 'Lace' });
129129
const namiTabs = await tabs.query({ title: POPUP_WINDOW_NAMI_TITLE });
130130
openTabs.push(...namiTabs);
@@ -135,7 +135,7 @@ export const closeAllLaceWindows = async (shouldRemoveTab?: (url: string) => boo
135135
};
136136

137137
export const ensureUiIsOpenAndLoaded = async (url?: string): Promise<Tabs.Tab> => {
138-
await closeAllLaceWindows((tabUrl) => DAPP_CONNECTOR_REGEX.test(tabUrl));
138+
await closeAllLaceOrNamiTabs((tabUrl) => DAPP_CONNECTOR_REGEX.test(tabUrl));
139139

140140
const tab = await launchCip30Popup(url);
141141

apps/browser-extension-wallet/src/lib/scripts/types/background-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export type UnhandledError = {
9797

9898
export type BackgroundService = {
9999
handleOpenBrowser: (data: OpenBrowserData, urlSearchParams?: string) => Promise<void>;
100-
handleOpenPopup: () => Promise<void>;
100+
closeAllTabsAndOpenPopup: () => Promise<void>;
101101
handleOpenNamiBrowser: (data: OpenNamiBrowserData) => Promise<void>;
102102
requestMessage$: Subject<Message>;
103103
migrationState$: BehaviorSubject<MigrationState | undefined>;

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/services/api/categories/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useState, useEffect, useMemo } from 'react';
22
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
33
import { cacheRequest } from '@views/browser/features/dapp/explorer/services/cache';
4+
import { logger } from '@lace/common';
45

56
type FetchCategoriesResult = {
67
loading: boolean;
@@ -48,7 +49,7 @@ export const useCategoriesFetcher = (): FetchCategoriesResult => {
4849
return result.categories;
4950
});
5051
} catch (error) {
51-
console.error('Failed to fetch dapp categories.', error);
52+
logger.error('Failed to fetch dapp categories.', error);
5253
}
5354

5455
categories = categories.filter((category) => !disallowedDappCategories.has(category));

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/services/api/d-app/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
22
import { ISectionCardItem } from '@views/browser/features/dapp/explorer/services/helpers/apis-formatter/types';
33
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
44
import { cacheRequest } from '@views/browser/features/dapp/explorer/services/cache';
5+
import { logger } from '@lace/common';
56

67
const dappRadarApiUrl = process.env.DAPP_RADAR_API_URL;
78
const dappRadarApiKey = process.env.DAPP_RADAR_API_KEY;
@@ -145,7 +146,7 @@ const useDAppFetcher = ({
145146
return parsedResponse.results;
146147
});
147148
} catch (error) {
148-
console.error('Failed to fetch dapp list.', error);
149+
logger.error('Failed to fetch dapp list.', error);
149150
}
150151

151152
setData(results);
@@ -155,7 +156,7 @@ const useDAppFetcher = ({
155156

156157
// eslint-disable-next-line unicorn/consistent-function-scoping
157158
const fetchMore = () => {
158-
console.error('Pagination not implemented!');
159+
logger.error('Pagination not implemented!');
159160
};
160161

161162
return {

apps/browser-extension-wallet/src/views/browser-view/features/dapp/explorer/services/cache.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { logger } from '@lace/common';
2+
13
type CacheEntry<Data> = {
24
data: Data;
35
timestamp: number;
@@ -25,7 +27,7 @@ const parseRawCacheRepo = (rawCacheRepo: string) => {
2527
cacheRepo = JSON.parse(rawCacheRepo);
2628
}
2729
} catch (error) {
28-
console.error('Failed to parse dapp explorer data cache', error);
30+
logger.error('Failed to parse dapp explorer data cache', error);
2931
}
3032
return cacheRepo;
3133
};

0 commit comments

Comments
 (0)