diff --git a/src/background/RemotePontoon.ts b/src/background/RemotePontoon.ts index 7474b88d..642e4ba9 100644 --- a/src/background/RemotePontoon.ts +++ b/src/background/RemotePontoon.ts @@ -18,12 +18,10 @@ import { pontoonUserData, bugzillaTeamComponents, } from './apiEndpoints'; -import type { GetProjectsInfoResponse } from './httpClients'; -import { - pontoonHttpClient, - httpClient, - pontoonGraphqlClient, -} from './httpClients'; +import { httpClient } from './httpClients/httpClient'; +import type { GetProjectsInfoResponse } from './httpClients/pontoonGraphqlClient'; +import { pontoonGraphqlClient } from './httpClients/pontoonGraphqlClient'; +import { pontoonHttpClient } from './httpClients/pontoonHttpClient'; import { projectsListData } from './data/projectsListData'; type GetProjectsInfoProject = GetProjectsInfoResponse['projects'][number]; @@ -59,7 +57,7 @@ function parseDOM(pageContent: string) { return new DOMParser().parseFromString(pageContent, 'text/html'); } -export function listenToMessagesFromClients() { +export function initMessageListeners() { listenToMessages<'PAGE_LOADED'>('pontoon-page-loaded', ({ documentHTML }) => updateNotificationsIfThereAreNew(documentHTML), ); diff --git a/src/background/addressBarIcon.ts b/src/background/addressBarIcon.ts index 2df595f5..89e565e5 100644 --- a/src/background/addressBarIcon.ts +++ b/src/background/addressBarIcon.ts @@ -10,7 +10,7 @@ import { import { getPontoonProjectForPageUrl } from './RemotePontoon'; -export function setupAddressBarIcon() { +export function init() { listenToStorageChange('projectsList', async () => { updatePageActions(await getAllTabs()); }); diff --git a/src/background/contextButtons.ts b/src/background/contextButtons.ts index b101f07a..9e443f5a 100644 --- a/src/background/contextButtons.ts +++ b/src/background/contextButtons.ts @@ -10,7 +10,7 @@ import { import { getOneOption, getOptions } from '@commons/options'; import { openNewPontoonTab } from '@commons/utils'; -export function setupPageContextButtons() { +export function init() { listenToMessagesFromContentScript(); } diff --git a/src/background/contextMenu.ts b/src/background/contextMenu.ts index de3c2ee9..58eb6283 100644 --- a/src/background/contextMenu.ts +++ b/src/background/contextMenu.ts @@ -29,7 +29,7 @@ const NON_SELECTION_CONTEXTS: Menus.ContextType[] = [ ]; const SELECTION_CONTEXTS: Menus.ContextType[] = ['selection']; -export function setupPageContextMenus() { +export function init() { listenToStorageChange('projectsList', () => createContextMenuItems()); listenToStorageChange('teamsList', () => createContextMenuItems()); listenToOptionChange('pontoon_base_url', () => createContextMenuItems()); diff --git a/src/background/dataRefresh.ts b/src/background/dataRefresh.ts index c3313314..d25be67e 100644 --- a/src/background/dataRefresh.ts +++ b/src/background/dataRefresh.ts @@ -13,11 +13,11 @@ import { getOptions, listenToOptionChange, } from '@commons/options'; -import type { BackgroundClientMessageWithoutResponse } from '@commons/BackgroundClientMessageType'; +import type { BackgroundMessagesWithoutResponse } from '@commons/backgroundMessaging'; import { refreshData } from './RemotePontoon'; -export function setupDataRefresh() { +export function init() { listenToOptionChange( 'data_update_interval', ({ newValue: periodInMinutes }) => { @@ -87,7 +87,7 @@ function registerLiveDataProvider() { contextualIdentity !== tab.cookieStoreId && typeof tab.id !== 'undefined' ) { - const message: BackgroundClientMessageWithoutResponse['DISABLE_NOTIFICATIONS_BELL_SCRIPT']['message'] = + const message: BackgroundMessagesWithoutResponse['DISABLE_NOTIFICATIONS_BELL_SCRIPT']['message'] = { type: 'disable-notifications-bell-script', }; diff --git a/src/background/httpClients/httpClient.ts b/src/background/httpClients/httpClient.ts new file mode 100644 index 00000000..1465ad93 --- /dev/null +++ b/src/background/httpClients/httpClient.ts @@ -0,0 +1,5 @@ +export const httpClient = { + fetch: async (url: string): Promise => { + return await fetch(url, { credentials: 'omit' }); + }, +}; diff --git a/src/background/httpClients/pontoonGraphqlClient.ts b/src/background/httpClients/pontoonGraphqlClient.ts new file mode 100644 index 00000000..e876d8e4 --- /dev/null +++ b/src/background/httpClients/pontoonGraphqlClient.ts @@ -0,0 +1,68 @@ +import { gql } from 'graphql-tag'; +import { GraphQLClient } from 'graphql-request'; + +import { getOneOption } from '@commons/options'; + +import type { DeepNonNullable, DeepRequired } from '../typeUtils'; +import { pontoonGraphQL } from '../apiEndpoints'; +import type { + GetProjectsInfoQuery, + GetTeamsInfoQuery, +} from '../../generated/pontoon.graphql'; +import { getSdk } from '../../generated/pontoon.graphql'; + +const _getTeamsInfoQuery = gql` + query getTeamsInfo { + locales { + code + name + approvedStrings + pretranslatedStrings + stringsWithWarnings + stringsWithErrors + missingStrings + unreviewedStrings + totalStrings + } + } +`; + +interface GetTeamsInfoResponse { + locales: DeepRequired>; +} + +const _getProjectsInfoQuery = gql` + query getProjectsInfo { + projects { + slug + name + } + } +`; + +export interface GetProjectsInfoResponse { + projects: DeepRequired>; +} + +function getGraphQLClient(pontoonBaseUrl: string) { + return getSdk( + new GraphQLClient(pontoonGraphQL(pontoonBaseUrl), { + method: 'GET', + }), + ); +} + +async function getPontoonBaseUrl(): Promise { + return await getOneOption('pontoon_base_url'); +} + +export const pontoonGraphqlClient = { + getTeamsInfo: async (): Promise => { + const client = getGraphQLClient(await getPontoonBaseUrl()); + return (await client.getTeamsInfo()) as GetTeamsInfoResponse; + }, + getProjectsInfo: async (): Promise => { + const client = getGraphQLClient(await getPontoonBaseUrl()); + return (await client.getProjectsInfo()) as GetProjectsInfoResponse; + }, +}; diff --git a/src/background/httpClients.ts b/src/background/httpClients/pontoonHttpClient.ts similarity index 56% rename from src/background/httpClients.ts rename to src/background/httpClients/pontoonHttpClient.ts index d7a2b975..d18d14a7 100644 --- a/src/background/httpClients.ts +++ b/src/background/httpClients/pontoonHttpClient.ts @@ -1,7 +1,5 @@ import type { WebRequest } from 'webextension-polyfill'; import { v4 as uuidv4 } from 'uuid'; -import { gql } from 'graphql-tag'; -import { GraphQLClient } from 'graphql-request'; import { browser } from '@commons/webExtensionsApi'; import { @@ -10,14 +8,7 @@ import { listenToOptionChange, } from '@commons/options'; -import type { - GetProjectsInfoQuery, - GetTeamsInfoQuery, -} from '../generated/pontoon.graphql'; -import { getSdk } from '../generated/pontoon.graphql'; - -import { pontoonGraphQL } from './apiEndpoints'; - +const PONTOON_REQUEST_TOKEN_HEADER = 'pontoon-addon-token'; const PONTOON_REQUEST_TOKEN_STORAGE_KEY_PREFIX = 'pontoon_req_token_'; const PONTOON_REQUEST_TOKEN_VALIDITY_SECONDS = 60; @@ -25,15 +16,26 @@ interface TokenInfo { issued: string; // ISO date } -async function listenForRequestsToPontoon(pontoonBaseUrl?: string) { +export async function init() { + await listenToOptionChange( + 'pontoon_base_url', + async ({ newValue: pontoonBaseUrl }) => { + await listenForRequestsToPontoon(pontoonBaseUrl); + }, + ); + await listenForRequestsToPontoon(await getPontoonBaseUrl()); +} + +async function getPontoonBaseUrl(): Promise { + return await getOneOption('pontoon_base_url'); +} + +async function listenForRequestsToPontoon(pontoonBaseUrl: string) { if (browser.webRequest) { - if (typeof pontoonBaseUrl === 'undefined') { - pontoonBaseUrl = await getOneOption('pontoon_base_url'); - } - browser.webRequest.onBeforeSendHeaders.removeListener( + await browser.webRequest.onBeforeSendHeaders.removeListener( setSessionCookieForPontoonRequest, ); - browser.webRequest.onBeforeSendHeaders.addListener( + await browser.webRequest.onBeforeSendHeaders.addListener( setSessionCookieForPontoonRequest, { urls: [`${pontoonBaseUrl}/*`] }, ['blocking', 'requestHeaders'], @@ -42,7 +44,7 @@ async function listenForRequestsToPontoon(pontoonBaseUrl?: string) { } async function fetchFromPontoonSession(url: string): Promise { - const pontoonBaseUrl = await getOneOption('pontoon_base_url'); + const pontoonBaseUrl = await getPontoonBaseUrl(); if (!url.startsWith(`${pontoonBaseUrl}/`)) { throw new Error( `Attempted to fetch '${url}' with Pontoon session for '${pontoonBaseUrl}'.`, @@ -54,11 +56,14 @@ async function fetchFromPontoonSession(url: string): Promise { if (browser.webRequest) { browser.webRequest.onBeforeSendHeaders.hasListener( setSessionCookieForPontoonRequest, - ) || (await listenForRequestsToPontoon()); - headers.append('pontoon-addon-token', await issueNewPontoonRequestToken()); - return fetch(url, { credentials: 'omit', headers: headers }); + ) || (await listenForRequestsToPontoon(pontoonBaseUrl)); + headers.append( + PONTOON_REQUEST_TOKEN_HEADER, + await issueNewPontoonRequestToken(), + ); + return fetch(url, { credentials: 'omit', headers }); } else { - return fetch(url, { credentials: 'include', headers: headers }); + return fetch(url, { credentials: 'include', headers }); } } @@ -102,7 +107,7 @@ async function verifyPontoonRequestToken( async function setSessionCookieForPontoonRequest( details: WebRequest.OnBeforeSendHeadersDetailsType, ): Promise { - const pontoonBaseUrl = await getOneOption('pontoon_base_url'); + const pontoonBaseUrl = await getPontoonBaseUrl(); if (!details.url.startsWith(`${pontoonBaseUrl}/`)) { console.warn( `Observed a request to '${details.url}', but Pontoon is at '${pontoonBaseUrl}'. Request passed unchanged.`, @@ -111,7 +116,9 @@ async function setSessionCookieForPontoonRequest( } const tokens = (details.requestHeaders ?? []) - .filter((header) => header.name.toLowerCase() === 'pontoon-addon-token') + .filter( + (header) => header.name.toLowerCase() === PONTOON_REQUEST_TOKEN_HEADER, + ) .map((header) => header.value); const isMarked = tokens.length > 0 && @@ -134,7 +141,9 @@ async function setSessionCookieForPontoonRequest( storeId: contextualIdentity, }); const requestHeaders = (details.requestHeaders ?? []) - .filter((header) => header.name.toLowerCase() !== 'pontoon-addon-token') + .filter( + (header) => header.name.toLowerCase() !== PONTOON_REQUEST_TOKEN_HEADER, + ) .filter((header) => header.name.toLowerCase() !== 'cookie') .concat( ...(cookie @@ -153,85 +162,6 @@ async function setSessionCookieForPontoonRequest( } } -listenToOptionChange('pontoon_base_url', ({ newValue: pontoonBaseUrl }) => { - listenForRequestsToPontoon(pontoonBaseUrl); -}); -listenForRequestsToPontoon(); - export const pontoonHttpClient = { fetchFromPontoonSession, }; - -export const httpClient = { - fetch: async (url: string): Promise => { - return await fetch(url, { credentials: 'omit' }); - }, -}; - -type DeepRequired = T extends object - ? Required<{ - [P in keyof T]: DeepRequired; - }> - : Required; - -type DeepNonNullable = T extends object - ? NonNullable<{ - [P in keyof T]: DeepNonNullable; - }> - : NonNullable; - -const _getTeamsInfoQuery = gql` - query getTeamsInfo { - locales { - code - name - approvedStrings - pretranslatedStrings - stringsWithWarnings - stringsWithErrors - missingStrings - unreviewedStrings - totalStrings - } - } -`; - -interface GetTeamsInfoResponse { - locales: DeepRequired>; -} - -const _getProjectsInfoQuery = gql` - query getProjectsInfo { - projects { - slug - name - } - } -`; - -export interface GetProjectsInfoResponse { - projects: DeepRequired>; -} - -function getGraphQLClient(pontoonBaseUrl: string) { - return getSdk( - new GraphQLClient(pontoonGraphQL(pontoonBaseUrl), { - method: 'GET', - }), - ); -} - -export const pontoonGraphqlClient = { - getTeamsInfo: async (): Promise => { - const client = getGraphQLClient(await getPontoonBaseUrl()); - return (await client.getTeamsInfo()) as GetTeamsInfoResponse; - }, - getProjectsInfo: async (): Promise => { - const client = getGraphQLClient(await getPontoonBaseUrl()); - return (await client.getProjectsInfo()) as GetProjectsInfoResponse; - }, -}; - -async function getPontoonBaseUrl(): Promise { - return await getOneOption('pontoon_base_url'); -} diff --git a/src/background/index.ts b/src/background/index.ts index 6bef7596..e5693756 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -8,30 +8,32 @@ import { supportsAddressBar, } from '@commons/webExtensionsApi'; -import { listenToMessagesFromClients } from './RemotePontoon'; -import { setupSystemNotifications } from './systemNotifications'; -import { setupToolbarButton } from './toolbarButton'; -import { setupAddressBarIcon } from './addressBarIcon'; -import { setupPageContextMenus } from './contextMenu'; -import { setupPageContextButtons } from './contextButtons'; -import { setupIntegrationWithPontoonAddonPromotion } from './pontoonAddonPromotion'; -import { setupDataRefresh } from './dataRefresh'; +import { init as initPontoonHttpClient } from './httpClients/pontoonHttpClient'; +import { initMessageListeners } from './RemotePontoon'; +import { init as initSystemNotifications } from './systemNotifications'; +import { init as initToolbarButton } from './toolbarButton'; +import { init as init } from './addressBarIcon'; +import { init as initPageContextMenu } from './contextMenu'; +import { init as initPageContextButtons } from './contextButtons'; +import { init as initPontoonAddonPromotion } from './pontoonAddonPromotion'; +import { init as initDataRefresh } from './dataRefresh'; -listenToMessagesFromClients(); +initPontoonHttpClient(); +initMessageListeners(); // native system -setupSystemNotifications(); +initSystemNotifications(); // browser UI -setupToolbarButton(); +initToolbarButton(); if (supportsAddressBar()) { - setupAddressBarIcon(); + init(); } -setupPageContextMenus(); +initPageContextMenu(); // pages content -setupPageContextButtons(); -setupIntegrationWithPontoonAddonPromotion(); +initPageContextButtons(); +initPontoonAddonPromotion(); // inject content scripts after installation // kudos to https://github.com/fregante/webext-inject-on-install @@ -64,6 +66,6 @@ browser.runtime.onInstalled.addListener((details) => { } }); -setupDataRefresh(); +initDataRefresh(); console.info('Background context initialized.'); diff --git a/src/background/pontoonAddonPromotion.ts b/src/background/pontoonAddonPromotion.ts index e80fa81c..6e714068 100644 --- a/src/background/pontoonAddonPromotion.ts +++ b/src/background/pontoonAddonPromotion.ts @@ -8,7 +8,7 @@ import { getOneOption, listenToOptionChange } from '@commons/options'; const CONTENT_SCRIPT = 'content-scripts/pontoon-addon-promotion-content-script.js'; -export function setupIntegrationWithPontoonAddonPromotion() { +export function init() { listenToOptionChange('pontoon_base_url', ({ newValue: pontoonBaseUrl }) => { registerContentScript(pontoonBaseUrl); }); diff --git a/src/background/systemNotifications.ts b/src/background/systemNotifications.ts index e9d7393a..78eca121 100644 --- a/src/background/systemNotifications.ts +++ b/src/background/systemNotifications.ts @@ -14,7 +14,7 @@ import { import { getOneOption, getOptions } from '@commons/options'; import { openNewPontoonTab } from '@commons/utils'; -export function setupSystemNotifications() { +export function init() { listenToStorageChange( 'notificationsData', async ({ newValue: notificationsData }) => { diff --git a/src/background/toolbarButton.ts b/src/background/toolbarButton.ts index a541297b..e1427787 100644 --- a/src/background/toolbarButton.ts +++ b/src/background/toolbarButton.ts @@ -33,7 +33,7 @@ import { refreshData } from './RemotePontoon'; const DEFAULT_TITLE = 'Pontoon notifications'; -export function setupToolbarButton() { +export function init() { registerBadgeChanges(); registerClickAction(); diff --git a/src/background/typeUtils.d.ts b/src/background/typeUtils.d.ts new file mode 100644 index 00000000..def14c00 --- /dev/null +++ b/src/background/typeUtils.d.ts @@ -0,0 +1,11 @@ +export type DeepRequired = T extends object + ? Required<{ + [P in keyof T]: DeepRequired; + }> + : Required; + +export type DeepNonNullable = T extends object + ? NonNullable<{ + [P in keyof T]: DeepNonNullable; + }> + : NonNullable; diff --git a/src/commons/BackgroundClientMessageType.ts b/src/commons/BackgroundClientMessageType.ts deleted file mode 100644 index 5c15c98a..00000000 --- a/src/commons/BackgroundClientMessageType.ts +++ /dev/null @@ -1,77 +0,0 @@ -import type { StorageContent } from './webExtensionsApi'; - -export type BackgroundClientMessageWithResponse = { - UPDATE_TEAMS_LIST: { - message: { - type: 'update-teams-list'; - }; - response: StorageContent['teamsList']; - }; - GET_TEAM_FROM_PONTOON: { - message: { - type: 'get-team-from-pontoon'; - }; - response: string | undefined; - }; - GET_CURRENT_TAB_PROJECT: { - message: { - type: 'get-current-tab-project'; - }; - response: StorageContent['projectsList'][string] | undefined; - }; - NOTIFICATIONS_BELL_SCRIPT_LOADED: { - message: { - type: 'notifications-bell-script-loaded'; - }; - response: { - type: - | BackgroundClientMessageWithoutResponse['ENABLE_NOTIFICATIONS_BELL_SCRIPT']['message']['type'] - | BackgroundClientMessageWithoutResponse['DISABLE_NOTIFICATIONS_BELL_SCRIPT']['message']['type']; - }; - }; -}; - -export type BackgroundClientMessageWithoutResponse = { - PAGE_LOADED: { - message: { - type: 'pontoon-page-loaded'; - documentHTML: string; - }; - response: void; - }; - NOTIFICATIONS_READ: { - message: { - type: 'notifications-read'; - }; - response: void; - }; - SEARCH_TEXT_IN_PONTOON: { - message: { - type: 'search-text-in-pontoon'; - text: string; - }; - response: void; - }; - REPORT_TRANSLATED_TEXT_TO_BUGZILLA: { - message: { - type: 'report-translated-text-to-bugzilla'; - text: string; - }; - response: void; - }; - ENABLE_NOTIFICATIONS_BELL_SCRIPT: { - message: { - type: 'enable-notifications-bell-script'; - }; - response: void; - }; - DISABLE_NOTIFICATIONS_BELL_SCRIPT: { - message: { - type: 'disable-notifications-bell-script'; - }; - response: void; - }; -}; - -export type BackgroundClientMessage = BackgroundClientMessageWithResponse & - BackgroundClientMessageWithoutResponse; diff --git a/src/background/__mocks__/backgroundClient.ts b/src/commons/__mocks__/backgroundMessaging.ts similarity index 100% rename from src/background/__mocks__/backgroundClient.ts rename to src/commons/__mocks__/backgroundMessaging.ts diff --git a/src/background/backgroundClient.ts b/src/commons/backgroundMessaging/index.ts similarity index 52% rename from src/background/backgroundClient.ts rename to src/commons/backgroundMessaging/index.ts index 3279c1e8..023cc8c0 100644 --- a/src/background/backgroundClient.ts +++ b/src/commons/backgroundMessaging/index.ts @@ -3,10 +3,92 @@ import { pontoonSettings, pontoonNotifications, toPontoonTeamSpecificProjectUrl, -} from '@commons/webLinks'; -import { browser } from '@commons/webExtensionsApi'; -import { getOneOption } from '@commons/options'; -import type { BackgroundClientMessage } from '@commons/BackgroundClientMessageType'; +} from '../webLinks'; +import type { StorageContent } from '../webExtensionsApi'; +import { browser } from '../webExtensionsApi'; +import { getOneOption } from '../options'; + +export type BackgroundMessagesWithResponse = { + UPDATE_TEAMS_LIST: { + message: { + type: 'update-teams-list'; + }; + response: StorageContent['teamsList']; + }; + GET_TEAM_FROM_PONTOON: { + message: { + type: 'get-team-from-pontoon'; + }; + response: string | undefined; + }; + GET_CURRENT_TAB_PROJECT: { + message: { + type: 'get-current-tab-project'; + }; + response: StorageContent['projectsList'][string] | undefined; + }; + NOTIFICATIONS_BELL_SCRIPT_LOADED: { + message: { + type: 'notifications-bell-script-loaded'; + }; + response: { + type: + | BackgroundMessagesWithoutResponse['ENABLE_NOTIFICATIONS_BELL_SCRIPT']['message']['type'] + | BackgroundMessagesWithoutResponse['DISABLE_NOTIFICATIONS_BELL_SCRIPT']['message']['type']; + }; + }; +}; + +export type BackgroundMessagesWithoutResponse = { + PAGE_LOADED: { + message: { + type: 'pontoon-page-loaded'; + documentHTML: string; + }; + response: void; + }; + NOTIFICATIONS_READ: { + message: { + type: 'notifications-read'; + }; + response: void; + }; + SEARCH_TEXT_IN_PONTOON: { + message: { + type: 'search-text-in-pontoon'; + text: string; + }; + response: void; + }; + REPORT_TRANSLATED_TEXT_TO_BUGZILLA: { + message: { + type: 'report-translated-text-to-bugzilla'; + text: string; + }; + response: void; + }; + ENABLE_NOTIFICATIONS_BELL_SCRIPT: { + message: { + type: 'enable-notifications-bell-script'; + }; + response: void; + }; + DISABLE_NOTIFICATIONS_BELL_SCRIPT: { + message: { + type: 'disable-notifications-bell-script'; + }; + response: void; + }; +}; + +export type BackgroundMessage = BackgroundMessagesWithResponse & + BackgroundMessagesWithoutResponse; + +async function sendMessage( + message: BackgroundMessage[T]['message'], +): Promise { + return await browser.runtime.sendMessage(message); +} async function getTeam(): Promise<{ code: string }> { return { @@ -35,12 +117,6 @@ export async function getSignInURL(): Promise { return pontoonFxaSignIn(await getPontoonBaseUrl()); } -async function sendMessage( - message: BackgroundClientMessage[T]['message'], -): Promise { - return await browser.runtime.sendMessage(message); -} - export async function updateTeamsList() { return await sendMessage<'UPDATE_TEAMS_LIST'>({ type: 'update-teams-list', diff --git a/src/background/backgroundClient.spec.ts b/src/commons/backgroundMessaging/spec.ts similarity index 81% rename from src/background/backgroundClient.spec.ts rename to src/commons/backgroundMessaging/spec.ts index 1a8c3c92..6944fd0c 100644 --- a/src/background/backgroundClient.spec.ts +++ b/src/commons/backgroundMessaging/spec.ts @@ -2,9 +2,9 @@ import type { MockzillaDeep } from 'mockzilla'; import 'mockzilla-webextension'; -import { getOneOption } from '@commons/options'; -import type { BackgroundClientMessage } from '@commons/BackgroundClientMessageType'; +import { getOneOption } from '../options'; +import type { BackgroundMessage } from '.'; import { getNotificationsUrl, getPontoonProjectForTheCurrentTab, @@ -18,7 +18,7 @@ import { reportTranslatedTextToBugzilla, searchTextInPontoon, updateTeamsList, -} from './backgroundClient'; +} from '.'; jest.mock('@commons/webExtensionsApi/browser'); jest.mock('@commons/options'); @@ -38,15 +38,15 @@ afterEach(() => { jest.clearAllMocks(); }); -function mockBrowserSendMessage() { +function mockBrowserSendMessage() { return mockBrowser.runtime.sendMessage as unknown as MockzillaDeep<{ ( - message: BackgroundClientMessage[T]['message'], - ): Promise; + message: BackgroundMessage[T]['message'], + ): Promise; }>; } -describe('backgroundClient', () => { +describe('messagingClient', () => { it('getNotificationsUrl', async () => { const url = await getNotificationsUrl(); @@ -74,23 +74,22 @@ describe('backgroundClient', () => { }); it('updateTeamsList', async () => { - const mockTeamsList: BackgroundClientMessage['UPDATE_TEAMS_LIST']['response'] = - { - cs: { - code: 'cs', - name: 'Czech', - bz_component: 'BZ / Czech', - strings: { - approvedStrings: 0, - pretranslatedStrings: 0, - stringsWithWarnings: 0, - stringsWithErrors: 0, - missingStrings: 0, - unreviewedStrings: 0, - totalStrings: 0, - }, + const mockTeamsList: BackgroundMessage['UPDATE_TEAMS_LIST']['response'] = { + cs: { + code: 'cs', + name: 'Czech', + bz_component: 'BZ / Czech', + strings: { + approvedStrings: 0, + pretranslatedStrings: 0, + stringsWithWarnings: 0, + stringsWithErrors: 0, + missingStrings: 0, + unreviewedStrings: 0, + totalStrings: 0, }, - }; + }, + }; mockBrowserSendMessage<'UPDATE_TEAMS_LIST'>() .expect({ type: 'update-teams-list' }) .andResolve(mockTeamsList); @@ -111,7 +110,7 @@ describe('backgroundClient', () => { }); it('getPontoonProjectForTheCurrentTab', async () => { - const mockProject: BackgroundClientMessage['GET_CURRENT_TAB_PROJECT']['response'] = + const mockProject: BackgroundMessage['GET_CURRENT_TAB_PROJECT']['response'] = { slug: 'firefox', name: 'Firefox', diff --git a/src/commons/webExtensionsApi/index.ts b/src/commons/webExtensionsApi/index.ts index c54ae196..27a11bd3 100644 --- a/src/commons/webExtensionsApi/index.ts +++ b/src/commons/webExtensionsApi/index.ts @@ -7,9 +7,9 @@ import type { } from 'webextension-polyfill'; import type { - BackgroundClientMessageWithResponse, - BackgroundClientMessageWithoutResponse, -} from '@commons/BackgroundClientMessageType'; + BackgroundMessagesWithResponse, + BackgroundMessagesWithoutResponse, +} from '../backgroundMessaging'; import { default as browserObj } from './browser'; @@ -298,17 +298,17 @@ export function callDelayed( } export function listenToMessages< - T extends keyof BackgroundClientMessageWithoutResponse, + T extends keyof BackgroundMessagesWithoutResponse, >( - type: BackgroundClientMessageWithoutResponse[T]['message']['type'], + type: BackgroundMessagesWithoutResponse[T]['message']['type'], action: ( - message: BackgroundClientMessageWithoutResponse[T]['message'], + message: BackgroundMessagesWithoutResponse[T]['message'], sender: Pick, ) => void | Promise, ) { browser.runtime.onMessage.addListener((message, sender) => { const typedMessade = - message as BackgroundClientMessageWithoutResponse[T]['message']; + message as BackgroundMessagesWithoutResponse[T]['message']; if (typedMessade.type === type) { // no return to allow all listeners to react on the message action(typedMessade, sender); @@ -319,17 +319,17 @@ export function listenToMessages< } export function listenToMessagesAndRespond< - T extends keyof BackgroundClientMessageWithResponse, + T extends keyof BackgroundMessagesWithResponse, >( - type: BackgroundClientMessageWithResponse[T]['message']['type'], + type: BackgroundMessagesWithResponse[T]['message']['type'], action: ( - message: BackgroundClientMessageWithResponse[T]['message'], + message: BackgroundMessagesWithResponse[T]['message'], sender: Pick, - ) => Promise, + ) => Promise, ) { browser.runtime.onMessage.addListener((message, sender) => { const typedMessade = - message as BackgroundClientMessageWithResponse[T]['message']; + message as BackgroundMessagesWithResponse[T]['message']; if (typedMessade.type === type) { // only one listener can send a response return action(typedMessade, sender); diff --git a/src/content-scripts/context-buttons.ts b/src/content-scripts/context-buttons.ts index b66f3aaa..b4029e52 100644 --- a/src/content-scripts/context-buttons.ts +++ b/src/content-scripts/context-buttons.ts @@ -3,7 +3,7 @@ import bugImage from '@assets/img/bug.svg'; import { reportTranslatedTextToBugzilla, searchTextInPontoon, -} from '@background/backgroundClient'; +} from '@commons/backgroundMessaging'; import { colors } from '@frontend/commons/const'; const contextButtonWidth = 24; diff --git a/src/content-scripts/live-data-provider.ts b/src/content-scripts/live-data-provider.ts index 0e7343c6..4ee6c0fe 100644 --- a/src/content-scripts/live-data-provider.ts +++ b/src/content-scripts/live-data-provider.ts @@ -1,3 +1,3 @@ -import { pageLoaded } from '@background/backgroundClient'; +import { pageLoaded } from '@commons/backgroundMessaging'; pageLoaded(document.documentElement.innerHTML); diff --git a/src/content-scripts/notifications-bell-icon.ts b/src/content-scripts/notifications-bell-icon.ts index 41c1109f..aeff5566 100644 --- a/src/content-scripts/notifications-bell-icon.ts +++ b/src/content-scripts/notifications-bell-icon.ts @@ -1,7 +1,7 @@ import { markAllNotificationsAsRead, notificationBellIconScriptLoaded, -} from '@background/backgroundClient'; +} from '@commons/backgroundMessaging'; import { listenToMessages, listenToStorageChange, diff --git a/src/frontend/address-bar/App/index.tsx b/src/frontend/address-bar/App/index.tsx index d12a0a27..16d6b393 100644 --- a/src/frontend/address-bar/App/index.tsx +++ b/src/frontend/address-bar/App/index.tsx @@ -13,7 +13,7 @@ import { pontoonProjectTranslationView, pontoonTeamsProject, } from '@commons/webLinks'; -import { getPontoonProjectForTheCurrentTab } from '@background/backgroundClient'; +import { getPontoonProjectForTheCurrentTab } from '@commons/backgroundMessaging'; import { openNewPontoonTab } from '@commons/utils'; import { PanelSection } from '../PanelSection'; diff --git a/src/frontend/address-bar/App/spec.tsx b/src/frontend/address-bar/App/spec.tsx index 9dbd0f8c..75ddbf93 100644 --- a/src/frontend/address-bar/App/spec.tsx +++ b/src/frontend/address-bar/App/spec.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { render, screen, act } from '@testing-library/react'; import flushPromises from 'flush-promises'; -import { getPontoonProjectForTheCurrentTab } from '@background/backgroundClient'; +import { getPontoonProjectForTheCurrentTab } from '@commons/backgroundMessaging'; import { getActiveTab, getOneFromStorage, @@ -21,7 +21,7 @@ import { App } from '.'; jest.mock('@commons/webExtensionsApi'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); const openNewPontoonTabSpy = jest .spyOn(UtilsApiModule, 'openNewPontoonTab') diff --git a/src/frontend/index.spec.ts b/src/frontend/index.spec.ts index f7ff1fc7..9389efa9 100644 --- a/src/frontend/index.spec.ts +++ b/src/frontend/index.spec.ts @@ -7,13 +7,13 @@ import { getOneFromStorage, } from '@commons/webExtensionsApi'; import { getOptions } from '@commons/options'; -import { getPontoonProjectForTheCurrentTab } from '@background/backgroundClient'; +import { getPontoonProjectForTheCurrentTab } from '@commons/backgroundMessaging'; import { render as index } from './index'; jest.mock('@commons/webExtensionsApi'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); afterEach(() => { jest.resetAllMocks(); diff --git a/src/frontend/options/LocaleSelection/index.tsx b/src/frontend/options/LocaleSelection/index.tsx index dbb15a91..ff79b4ac 100644 --- a/src/frontend/options/LocaleSelection/index.tsx +++ b/src/frontend/options/LocaleSelection/index.tsx @@ -5,7 +5,7 @@ import { getOneFromStorage } from '@commons/webExtensionsApi'; import { updateTeamsList, getUsersTeamFromPontoon, -} from '@background/backgroundClient'; +} from '@commons/backgroundMessaging'; import { getOneOption, setOption } from '@commons/options'; import type { OptionsContent } from '@commons/data/defaultOptions'; import { Button } from '@frontend/commons/components/pontoon/Button'; diff --git a/src/frontend/options/ToolbarButtonActionSelection/index.tsx b/src/frontend/options/ToolbarButtonActionSelection/index.tsx index 6ef0b3b5..e0bbd015 100644 --- a/src/frontend/options/ToolbarButtonActionSelection/index.tsx +++ b/src/frontend/options/ToolbarButtonActionSelection/index.tsx @@ -1,7 +1,7 @@ import type { ChangeEvent } from 'react'; import React, { useCallback, useEffect, useState } from 'react'; -import { getSettingsUrl } from '@background/backgroundClient'; +import { getSettingsUrl } from '@commons/backgroundMessaging'; import { getOneOption, setOption } from '@commons/options'; import type { OptionsContent } from '@commons/data/defaultOptions'; import { openNewPontoonTab } from '@commons/utils'; diff --git a/src/frontend/toolbar-button/NotificationsList/index.tsx b/src/frontend/toolbar-button/NotificationsList/index.tsx index 6761cc63..b8e273c6 100644 --- a/src/frontend/toolbar-button/NotificationsList/index.tsx +++ b/src/frontend/toolbar-button/NotificationsList/index.tsx @@ -5,7 +5,7 @@ import type { StorageContent } from '@commons/webExtensionsApi'; import { getNotificationsUrl, markAllNotificationsAsRead, -} from '@background/backgroundClient'; +} from '@commons/backgroundMessaging'; import { openNewPontoonTab } from '@commons/utils'; import { colors } from '@frontend/commons/const'; diff --git a/src/frontend/toolbar-button/NotificationsList/spec.tsx b/src/frontend/toolbar-button/NotificationsList/spec.tsx index e8356be9..fca4162f 100644 --- a/src/frontend/toolbar-button/NotificationsList/spec.tsx +++ b/src/frontend/toolbar-button/NotificationsList/spec.tsx @@ -7,13 +7,13 @@ import * as UtilsApiModule from '@commons/utils'; import { getNotificationsUrl, markAllNotificationsAsRead, -} from '@background/backgroundClient'; +} from '@commons/backgroundMessaging'; import { NotificationsList } from '.'; jest.mock('@commons/webExtensionsApi/browser'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); const windowCloseSpy = jest.spyOn(window, 'close').mockReturnValue(undefined); const openNewPontoonTabSpy = jest diff --git a/src/frontend/toolbar-button/NotificationsListError/index.tsx b/src/frontend/toolbar-button/NotificationsListError/index.tsx index 65f95232..bde902dc 100644 --- a/src/frontend/toolbar-button/NotificationsListError/index.tsx +++ b/src/frontend/toolbar-button/NotificationsListError/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { css } from '@emotion/react'; -import { getSignInURL } from '@background/backgroundClient'; +import { getSignInURL } from '@commons/backgroundMessaging'; import { openNewPontoonTab } from '@commons/utils'; import { colors, sizes } from '@frontend/commons/const'; import { Link } from '@frontend/commons/components/pontoon/Link'; diff --git a/src/frontend/toolbar-button/NotificationsListError/spec.tsx b/src/frontend/toolbar-button/NotificationsListError/spec.tsx index f4559719..b65fa7c7 100644 --- a/src/frontend/toolbar-button/NotificationsListError/spec.tsx +++ b/src/frontend/toolbar-button/NotificationsListError/spec.tsx @@ -4,13 +4,13 @@ import { render, screen, act } from '@testing-library/react'; import flushPromises from 'flush-promises'; import * as UtilsApiModule from '@commons/utils'; -import { getSignInURL } from '@background/backgroundClient'; +import { getSignInURL } from '@commons/backgroundMessaging'; import { NotificationsListError } from '.'; jest.mock('@commons/webExtensionsApi/browser'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); const windowCloseSpy = jest.spyOn(window, 'close').mockReturnValue(undefined); const openNewPontoonTabSpy = jest diff --git a/src/frontend/toolbar-button/NotificationsListItem/index.tsx b/src/frontend/toolbar-button/NotificationsListItem/index.tsx index 98956f0e..898d8341 100644 --- a/src/frontend/toolbar-button/NotificationsListItem/index.tsx +++ b/src/frontend/toolbar-button/NotificationsListItem/index.tsx @@ -11,7 +11,7 @@ import type { HTMLReactParserOptions, DOMNode } from 'html-react-parser'; import parse, { domToReact, Element } from 'html-react-parser'; import type { StorageContent } from '@commons/webExtensionsApi'; -import { getTeamProjectUrl } from '@background/backgroundClient'; +import { getTeamProjectUrl } from '@commons/backgroundMessaging'; import { openNewPontoonTab } from '@commons/utils'; import { Link } from '@frontend/commons/components/pontoon/Link'; import { NativeLink } from '@frontend/commons/components/pontoon/NativeLink'; diff --git a/src/frontend/toolbar-button/NotificationsListItem/spec.tsx b/src/frontend/toolbar-button/NotificationsListItem/spec.tsx index 07c7282b..3a088fec 100644 --- a/src/frontend/toolbar-button/NotificationsListItem/spec.tsx +++ b/src/frontend/toolbar-button/NotificationsListItem/spec.tsx @@ -4,13 +4,13 @@ import { render, screen, within, act } from '@testing-library/react'; import flushPromises from 'flush-promises'; import * as UtilsApiModule from '@commons/utils'; -import { getTeamProjectUrl } from '@background/backgroundClient'; +import { getTeamProjectUrl } from '@commons/backgroundMessaging'; import { NotificationsListItem } from '.'; jest.mock('@commons/webExtensionsApi/browser'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); jest.spyOn(window, 'close').mockReturnValue(undefined); const openNewPontoonTabSpy = jest diff --git a/src/frontend/toolbar-button/TeamInfo/index.tsx b/src/frontend/toolbar-button/TeamInfo/index.tsx index 760a19ab..fd45f28e 100644 --- a/src/frontend/toolbar-button/TeamInfo/index.tsx +++ b/src/frontend/toolbar-button/TeamInfo/index.tsx @@ -18,7 +18,7 @@ import { pontoonTeam, pontoonTeamsProject, } from '@commons/webLinks'; -import { getPontoonProjectForTheCurrentTab } from '@background/backgroundClient'; +import { getPontoonProjectForTheCurrentTab } from '@commons/backgroundMessaging'; import { openNewPontoonTab } from '@commons/utils'; import { colors } from '@frontend/commons/const'; import { Heading3 } from '@frontend/commons/components/pontoon/Heading3'; diff --git a/src/frontend/toolbar-button/TeamInfo/spec.tsx b/src/frontend/toolbar-button/TeamInfo/spec.tsx index 894f24c0..83d219a1 100644 --- a/src/frontend/toolbar-button/TeamInfo/spec.tsx +++ b/src/frontend/toolbar-button/TeamInfo/spec.tsx @@ -18,13 +18,13 @@ import { pontoonTeamsProject, } from '@commons/webLinks'; import * as UtilsApiModule from '@commons/utils'; -import { getPontoonProjectForTheCurrentTab } from '@background/backgroundClient'; +import { getPontoonProjectForTheCurrentTab } from '@commons/backgroundMessaging'; import { TeamInfo } from '.'; jest.mock('@commons/webExtensionsApi'); jest.mock('@commons/options'); -jest.mock('@background/backgroundClient'); +jest.mock('@commons/backgroundMessaging'); jest.spyOn(window, 'close').mockReturnValue(undefined); const openNewPontoonTabSpy = jest