diff --git a/source/background/services/messaging.ts b/source/background/services/messaging.ts index 1df14853..43935676 100644 --- a/source/background/services/messaging.ts +++ b/source/background/services/messaging.ts @@ -35,8 +35,16 @@ import { getRecents, trackRecentUsage } from "./recents.js"; import { openEntryPageInNewTab } from "./entry.js"; import { getAutoLoginForTab, registerAutoLogin } from "./autoLogin.js"; import { extractDomainFromCredentials } from "../library/domain.js"; -import { BackgroundMessage, BackgroundMessageType, BackgroundResponse, LocalStorageItem } from "../types.js"; +import { + BackgroundMessage, + BackgroundMessageType, + BackgroundResponse, + LocalStorageItem, + TabEventType +} from "../types.js"; import { markNotificationRead } from "./notifications.js"; +import { createNewTab, getExtensionURL } from "../../shared/library/extension.js"; +import { sendTabsMessage } from "./tabs.js"; async function handleMessage( msg: BackgroundMessage, @@ -79,6 +87,9 @@ async function handleMessage( const { credentialsID } = msg; log(`clear saved credentials prompt: ${credentialsID}`); stopPromptForID(credentialsID); + await sendTabsMessage({ + type: TabEventType.CloseSaveDialog + }); sendResponse({}); break; } @@ -104,6 +115,9 @@ async function handleMessage( } catch (err) { throw new Layerr(err, "Failed disabling save prompt for domain"); } + await sendTabsMessage({ + type: TabEventType.CloseSaveDialog + }); sendResponse({}); break; } @@ -203,6 +217,7 @@ async function handleMessage( case BackgroundMessageType.InitiateDesktopConnection: { log("start desktop authentication"); await initiateConnection(); + await createNewTab(getExtensionURL("full.html#/connect")); sendResponse({}); break; } @@ -228,6 +243,14 @@ async function handleMessage( sendResponse({ opened: true }); break; } + case BackgroundMessageType.OpenSaveCredentialsPage: { + await createNewTab(getExtensionURL("full.html#/save-credentials")); + await sendTabsMessage({ + type: TabEventType.CloseSaveDialog + }); + sendResponse({}); + break; + } case BackgroundMessageType.PromptLockSource: { const { sourceID } = msg; log(`request lock source: ${sourceID}`); diff --git a/source/background/services/tabs.ts b/source/background/services/tabs.ts new file mode 100644 index 00000000..27eb6b00 --- /dev/null +++ b/source/background/services/tabs.ts @@ -0,0 +1,18 @@ +import { getExtensionAPI } from "../../shared/extension.js"; +import { TabEvent } from "../types.js"; + +export async function sendTabsMessage(payload: TabEvent, tabIDs: Array | null = null): Promise { + const browser = getExtensionAPI(); + const targetTabIDs = Array.isArray(tabIDs) + ? tabIDs + : ( + await browser.tabs.query({ + status: "complete" + }) + ).map((tab) => tab.id); + await Promise.all( + targetTabIDs.map(async (tabID) => { + await browser.tabs.sendMessage(tabID, payload); + }) + ); +} diff --git a/source/popup/components/navigation/Navigator.tsx b/source/popup/components/navigation/Navigator.tsx index c84345a6..80d99b70 100644 --- a/source/popup/components/navigation/Navigator.tsx +++ b/source/popup/components/navigation/Navigator.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useCallback, useState } from "react"; +import React, { useCallback, useState } from "react"; import styled from "styled-components"; import { Classes, Divider, Icon, Intent, Tab, Tabs } from "@blueprintjs/core"; import { VaultsPage, VaultsPageControls } from "../pages/VaultsPage.js"; @@ -7,7 +7,6 @@ import { getToaster } from "../../../shared/services/notifications.js"; import { localisedErrorMessage } from "../../../shared/library/error.js"; import { t } from "../../../shared/i18n/trans.js"; import { clearDesktopConnectionAuth, initiateDesktopConnectionRequest } from "../../queries/desktop.js"; -import { createNewTab, getExtensionURL } from "../../../shared/library/extension.js"; import { OTPsPage } from "../pages/OTPsPage.js"; import { SettingsPage } from "../pages/SettingsPage.js"; import { AboutPage } from "../pages/AboutPage.js"; @@ -63,7 +62,6 @@ export function Navigator(props: NavigatorProps) { const handleConnectClick = useCallback(async () => { try { await initiateDesktopConnectionRequest(); - await createNewTab(getExtensionURL("full.html#/connect")); } catch (err) { console.error(err); getToaster().show({ diff --git a/source/popup/components/pages/EntriesPage.tsx b/source/popup/components/pages/EntriesPage.tsx index 427a163a..275ec1ae 100644 --- a/source/popup/components/pages/EntriesPage.tsx +++ b/source/popup/components/pages/EntriesPage.tsx @@ -149,6 +149,15 @@ function EntriesPageList(props: EntriesPageProps) { /> ); } + if (urlEntries.length <= 0 && recentEntries.length <= 0) { + return ( + + ); + } return ( (false); const handleViewClick = useCallback(async () => { try { - await createNewTab(getExtensionURL("full.html#/save-credentials")); - await sendTabsMessage({ - type: TabEventType.CloseSaveDialog + // Open save page and close dialog + await sendBackgroundMessage({ + type: BackgroundMessageType.OpenSaveCredentialsPage }); } catch (err) { console.error(err); @@ -109,10 +108,8 @@ export function SaveDialogPage() { }, [loginID]); const handleCloseClick = useCallback(async () => { try { + // Clear prompt and close dialog await clearSavedLoginPrompt(loginID); - await sendTabsMessage({ - type: TabEventType.CloseSaveDialog - }); } catch (err) { console.error(err); getToaster().show({ @@ -128,10 +125,8 @@ export function SaveDialogPage() { return; } try { + // Disable domain and close dialog await disableDomainForLogin(loginID); - await sendTabsMessage({ - type: TabEventType.CloseSaveDialog - }); } catch (err) { console.error(err); getToaster().show({ diff --git a/source/shared/extension.ts b/source/shared/extension.ts index a1c231a5..cb94c8aa 100644 --- a/source/shared/extension.ts +++ b/source/shared/extension.ts @@ -1,3 +1,6 @@ export function getExtensionAPI(): typeof chrome { + if (BROWSER === "firefox") { + return browser; + } return self.chrome || self["browser"]; } diff --git a/source/shared/i18n/translations/en.json b/source/shared/i18n/translations/en.json index 1edbc116..5042176d 100644 --- a/source/shared/i18n/translations/en.json +++ b/source/shared/i18n/translations/en.json @@ -125,6 +125,10 @@ "placeholder": "Search..." } }, + "no-entries": { + "description": "No available entries - recent items and results for the current tab will appear here.", + "title": "No Entries" + }, "no-otps": { "description": "No OTP entries found in unlocked vaults.", "title": "No OTP Entries" diff --git a/source/shared/library/version.ts b/source/shared/library/version.ts index 4fd3754b..424091a9 100644 --- a/source/shared/library/version.ts +++ b/source/shared/library/version.ts @@ -1,4 +1,4 @@ // Do not edit this file - it is generated automatically at build time -export const BUILD_DATE = "2024-03-24"; +export const BUILD_DATE = "2024-03-25"; export const VERSION = "3.0.0"; diff --git a/source/shared/services/messaging.ts b/source/shared/services/messaging.ts index d3e75e3a..410532c3 100644 --- a/source/shared/services/messaging.ts +++ b/source/shared/services/messaging.ts @@ -22,19 +22,3 @@ export async function sendBackgroundMessage( }); }); } - -export async function sendTabsMessage(payload: TabEvent, tabIDs: Array | null = null): Promise { - const browser = getExtensionAPI(); - const targetTabIDs = Array.isArray(tabIDs) - ? tabIDs - : ( - await browser.tabs.query({ - status: "complete" - }) - ).map((tab) => tab.id); - await Promise.all( - targetTabIDs.map(async (tabID) => { - await browser.tabs.sendMessage(tabID, payload); - }) - ); -} diff --git a/source/shared/types.ts b/source/shared/types.ts index 581daaa3..e184f9ee 100644 --- a/source/shared/types.ts +++ b/source/shared/types.ts @@ -61,6 +61,7 @@ export enum BackgroundMessageType { GetSavedCredentialsForID = "getCredentialsForID", MarkNotificationRead = "markNotificationRead", OpenEntryPage = "openEntryPage", + OpenSaveCredentialsPage = "openSaveCredentials", PromptLockSource = "promptLockSource", PromptUnlockSource = "promptUnlockSource", ResetSettings = "resetSettings", diff --git a/source/typings/globals.d.ts b/source/typings/globals.d.ts new file mode 100644 index 00000000..283ca203 --- /dev/null +++ b/source/typings/globals.d.ts @@ -0,0 +1,2 @@ +declare var BROWSER: "chrome" | "edge" | "firefox"; +declare var browser: typeof chrome; diff --git a/webpack.config.js b/webpack.config.js index 17683b2a..014f486f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,7 +13,7 @@ import packageInfo from "./package.json" assert { type: "json" }; import manifestV2 from "./resources/manifest.v2.json" assert { type: "json" }; import manifestV3 from "./resources/manifest.v3.json" assert { type: "json" }; -const { BannerPlugin } = webpack; +const { BannerPlugin, DefinePlugin } = webpack; const { BROWSER } = process.env; const V3_BROWSERS = ["chrome", "edge"]; const require = createRequire(import.meta.url); @@ -118,6 +118,12 @@ function getBaseConfig() { maxAssetSize: 768000 }, + plugins: [ + new DefinePlugin({ + BROWSER: JSON.stringify(BROWSER) + }) + ], + resolve: { alias: { iocane: "iocane/web",