Skip to content

Commit

Permalink
moves rest of exported backgroudn contextMenu functions to separate f…
Browse files Browse the repository at this point in the history
…iles
  • Loading branch information
grahamlangford committed May 1, 2024
1 parent 6e67105 commit f174f1f
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 87 deletions.
2 changes: 1 addition & 1 deletion src/background/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import registerMessenger from "@/background/messenger/registration";
import registerMessengerStrict from "@/background/messenger/strict/registration";
import registerExternalMessenger from "@/background/messenger/external/registration";
import initLocator from "@/background/locator";
import initContextMenus from "@/background/contextMenus";
import initContextMenus from "@/background/contextMenus/initContextMenus";
import initBrowserAction from "@/background/browserAction";
import initInstaller from "@/background/installer";
import initNavigation from "@/background/navigation";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { preloadContextMenus } from "@/background/contextMenus";
import extensionPointRegistry from "@/starterBricks/registry";
import { fromJS } from "@/starterBricks/contextMenu/contextMenu";
import * as backgroundApi from "@/background/messenger/strict/api";
Expand All @@ -31,6 +30,7 @@ import {
type ContextMenuConfig,
} from "@/starterBricks/contextMenu/types";
import { ensureContextMenu } from "@/background/contextMenus/ensureContextMenu";
import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus";

TEST_setContext("background");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,12 @@ import { type Menus, type Tabs } from "webextension-polyfill";
import { handleMenuAction, notify } from "@/contentScript/messenger/strict/api";
import { waitForContentScript } from "@/background/contentScript";
import { expectContext } from "@/utils/expectContext";
import extensionPointRegistry from "@/starterBricks/registry";
import { ContextMenuStarterBrickABC } from "@/starterBricks/contextMenu/contextMenu";
import { getModComponentState } from "@/store/extensionsStorage";
import { resolveExtensionInnerDefinitions } from "@/registry/internal";
import { type UUID } from "@/types/stringTypes";
import {
type ModComponentBase,
type ResolvedModComponent,
} from "@/types/modComponentTypes";
import { allSettled } from "@/utils/promiseUtils";
import { ContextError } from "@/errors/genericErrors";
import { selectEventData } from "@/telemetry/deployments";
import { type ContextMenuConfig } from "@/starterBricks/contextMenu/types";
import { MENU_PREFIX, makeMenuId } from "@/background/contextMenus/makeMenuId";
import { MENU_PREFIX } from "@/background/contextMenus/makeMenuId";
import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus";

// This constant must be high enough to give Chrome time to inject the content script. waitForContentScript can take
// >= 1 seconds because it also waits for the content script to be ready
Expand Down Expand Up @@ -89,64 +81,6 @@ function menuListener(info: Menus.OnClickData, tab: Tabs.Tab) {
}
}

/**
* Uninstall the contextMenu UI for `extensionId` from browser context menu on all tabs.
*
* Safe to call on non-context menu extension ids.
*
* @returns true if the contextMenu was removed, or false if the contextMenu was not found.
*/
export async function uninstallContextMenu({
extensionId,
}: {
extensionId: UUID;
}): Promise<boolean> {
try {
await browser.contextMenus.remove(makeMenuId(extensionId));
console.debug(`Uninstalled context menu ${extensionId}`);
return true;
} catch (error) {
// Will throw if extensionId doesn't refer to a context menu. The callers don't have an easy way to check the type
// without having to resolve the extensionPointId. So instead we'll just expect some of the calls to fail.
console.debug("Could not uninstall context menu %s", extensionId, {
error,
});
return false;
}
}

/**
* Add context menu items to the Chrome context menu on all tabs, in anticipation that on Page Load, the content
* script will register a handler for the item.
* @param extensions the ModComponent to preload.
*/
export async function preloadContextMenus(
extensions: ModComponentBase[],
): Promise<void> {
expectContext("background");
const promises = extensions.map(async (definition) => {
const resolved = await resolveExtensionInnerDefinitions(definition);

const extensionPoint = await extensionPointRegistry.lookup(
resolved.extensionPointId,
);
if (extensionPoint instanceof ContextMenuStarterBrickABC) {
await extensionPoint.registerMenuItem(
definition as unknown as ResolvedModComponent<ContextMenuConfig>,
() => {
throw new ContextError(
"Context menu was preloaded, but no handler was registered",
{
context: selectEventData(resolved),
},
);
},
);
}
});
await allSettled(promises, { catch: "ignore" });
}

async function preloadAllContextMenus(): Promise<void> {
const { extensions } = await getModComponentState();
const { fulfilled } = await allSettled(
Expand Down
61 changes: 61 additions & 0 deletions src/background/contextMenus/preloadContextMenus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*

Check failure on line 1 in src/background/contextMenus/preloadContextMenus.ts

View workflow job for this annotation

GitHub Actions / strictNullChecks

strictNullChecks

src/background/contextMenus/preloadContextMenus.ts was not found in tsconfig.strictNullChecks.json
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { ContextError } from "@/errors/genericErrors";
import { resolveExtensionInnerDefinitions } from "@/registry/internal";
import { ContextMenuStarterBrickABC } from "@/starterBricks/contextMenu/contextMenu";
import { type ContextMenuConfig } from "@/starterBricks/contextMenu/types";
import { selectEventData } from "@/telemetry/deployments";
import {
type ModComponentBase,
type ResolvedModComponent,
} from "@/types/modComponentTypes";
import { expectContext } from "@/utils/expectContext";
import { allSettled } from "@/utils/promiseUtils";
import extensionPointRegistry from "@/starterBricks/registry";

/**
* Add context menu items to the Chrome context menu on all tabs, in anticipation that on Page Load, the content
* script will register a handler for the item.
* @param extensions the ModComponent to preload.
*/
export async function preloadContextMenus(
extensions: ModComponentBase[],
): Promise<void> {
expectContext("background");
const promises = extensions.map(async (definition) => {
const resolved = await resolveExtensionInnerDefinitions(definition);

const extensionPoint = await extensionPointRegistry.lookup(
resolved.extensionPointId,
);
if (extensionPoint instanceof ContextMenuStarterBrickABC) {
await extensionPoint.registerMenuItem(
definition as unknown as ResolvedModComponent<ContextMenuConfig>,
() => {
throw new ContextError(
"Context menu was preloaded, but no handler was registered",
{
context: selectEventData(resolved),
},
);
},
);
}
});
await allSettled(promises, { catch: "ignore" });
}
45 changes: 45 additions & 0 deletions src/background/contextMenus/uninstallContextMenu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2024 PixieBrix, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { makeMenuId } from "@/background/contextMenus/makeMenuId";
import { type UUID } from "@/types/stringTypes";

/**
* Uninstall the contextMenu UI for `extensionId` from browser context menu on all tabs.
*
* Safe to call on non-context menu extension ids.
*
* @returns true if the contextMenu was removed, or false if the contextMenu was not found.
*/
export async function uninstallContextMenu({
extensionId,
}: {
extensionId: UUID;
}): Promise<boolean> {
try {
await browser.contextMenus.remove(makeMenuId(extensionId));
console.debug(`Uninstalled context menu ${extensionId}`);
return true;
} catch (error) {
// Will throw if extensionId doesn't refer to a context menu. The callers don't have an easy way to check the type
// without having to resolve the extensionPointId. So instead we'll just expect some of the calls to fail.
console.debug("Could not uninstall context menu %s", extensionId, {
error,
});
return false;
}
}
5 changes: 0 additions & 5 deletions src/background/messenger/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ export const removeExtensionForEveryTab = getNotifier(

export const clearServiceCache = getMethod("CLEAR_SERVICE_CACHE", bg);

/**
* Uninstall context menu and return whether the context menu was uninstalled.
*/
export const uninstallContextMenu = getMethod("UNINSTALL_CONTEXT_MENU", bg);

export const requestRun = {
inOpener: getMethod("REQUEST_RUN_IN_OPENER", bg),
inTarget: getMethod("REQUEST_RUN_IN_TARGET", bg),
Expand Down
7 changes: 1 addition & 6 deletions src/background/messenger/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@

import { registerMethods } from "webext-messenger";
import { expectContext } from "@/utils/expectContext";
import {
preloadContextMenus,
uninstallContextMenu,
} from "@/background/contextMenus"; // 201 strictNullCheck errors
import {
requestRunInAllFrames,
requestRunInOtherTabs,
Expand All @@ -39,13 +35,13 @@ import { removeExtensionForEveryTab } from "@/background/removeExtensionForEvery
import { debouncedActivateStarterMods as installStarterBlueprints } from "@/background/starterMods"; // 209 strictNullCheck errors

import { setCopilotProcessData } from "@/background/partnerHandlers"; // Depends on contentScript/messenger to pass strictNullCheck
import { preloadContextMenus } from "@/background/contextMenus/preloadContextMenus"; // 197 strictNullCheck errors

expectContext("background");

declare global {
interface MessengerMethods {
PRELOAD_CONTEXT_MENUS: typeof preloadContextMenus;
UNINSTALL_CONTEXT_MENU: typeof uninstallContextMenu;

SET_PARTNER_COPILOT_DATA: typeof setCopilotProcessData;

Expand All @@ -68,7 +64,6 @@ export default function registerMessenger(): void {
INSTALL_STARTER_BLUEPRINTS: installStarterBlueprints,

PRELOAD_CONTEXT_MENUS: preloadContextMenus,
UNINSTALL_CONTEXT_MENU: uninstallContextMenu,

REMOVE_EXTENSION_EVERY_TAB: removeExtensionForEveryTab,

Expand Down
4 changes: 4 additions & 0 deletions src/background/messenger/strict/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,7 @@ export const initTelemetry = getNotifier("INIT_TELEMETRY", bg);
export const sendDeploymentAlert = getNotifier("SEND_DEPLOYMENT_ALERT", bg);

export const ensureContextMenu = getMethod("ENSURE_CONTEXT_MENU", bg);
/**
* Uninstall context menu and return whether the context menu was uninstalled.
*/
export const uninstallContextMenu = getMethod("UNINSTALL_CONTEXT_MENU", bg);
3 changes: 3 additions & 0 deletions src/background/messenger/strict/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import {
sendDeploymentAlert,
} from "@/background/telemetry";
import { ensureContextMenu } from "@/background/contextMenus/ensureContextMenu";
import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu";

expectContext("background");

Expand Down Expand Up @@ -126,6 +127,7 @@ declare global {
SEND_DEPLOYMENT_ALERT: typeof sendDeploymentAlert;

ENSURE_CONTEXT_MENU: typeof ensureContextMenu;
UNINSTALL_CONTEXT_MENU: typeof uninstallContextMenu;
}
}

Expand Down Expand Up @@ -187,5 +189,6 @@ export default function registerMessenger(): void {
SEND_DEPLOYMENT_ALERT: sendDeploymentAlert,

ENSURE_CONTEXT_MENU: ensureContextMenu,
UNINSTALL_CONTEXT_MENU: uninstallContextMenu,
});
}
2 changes: 1 addition & 1 deletion src/background/modUpdater.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import extensionsSlice from "@/store/extensionsSlice";
import { sharingDefinitionFactory } from "@/testUtils/factories/registryFactories";
import type { ModDefinition } from "@/types/modDefinitionTypes";
import type { ActivatedModComponent } from "@/types/modComponentTypes";
import { uninstallContextMenu } from "@/background/contextMenus";
import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu";
import { TEST_deleteFeatureFlagsCache } from "@/auth/featureFlagStorage";

const axiosMock = new MockAdapter(axios);
Expand Down
2 changes: 1 addition & 1 deletion src/background/modUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import type {
} from "@/types/modComponentTypes";
import { collectModOptions } from "@/store/extensionsUtils";
import type { ModComponentState } from "@/store/extensionsTypes";
import { uninstallContextMenu } from "@/background/contextMenus";
import { uninstallContextMenu } from "@/background/contextMenus/uninstallContextMenu";
import collectExistingConfiguredDependenciesForMod from "@/integrations/util/collectExistingConfiguredDependenciesForMod";
import { flagOn } from "@/auth/featureFlagStorage";

Expand Down
2 changes: 1 addition & 1 deletion src/background/removeExtensionForEveryTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import { removeSidebars } from "@/contentScript/messenger/strict/api";
import { forEachTab } from "@/utils/extensionUtils";
import { type UUID } from "@/types/stringTypes";
import { uninstallContextMenu } from "./contextMenus";
import { uninstallContextMenu } from "./contextMenus/uninstallContextMenu";
import { clearExtensionTraces } from "@/telemetry/trace";
import { clearLog } from "@/telemetry/logging";

Expand Down
2 changes: 1 addition & 1 deletion src/contentScript/contentScriptPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import {
openTab,
performConfiguredRequestInBackground,
ensureContextMenu,
uninstallContextMenu,
} from "@/background/messenger/strict/api";
import { getState, setState } from "@/platform/state/stateController";
import quickBarRegistry from "@/components/quickBar/quickBarRegistry";
import { expectContext } from "@/utils/expectContext";
import type { PlatformCapability } from "@/platform/capabilities";
import { getReferenceForElement } from "@/contentScript/elementReference";
import { uninstallContextMenu } from "@/background/messenger/api";
import { ephemeralForm } from "@/contentScript/ephemeralForm";
import { ephemeralPanel } from "@/contentScript/ephemeralPanel";
import type { ElementReference } from "@/types/runtimeTypes";
Expand Down
6 changes: 4 additions & 2 deletions src/starterBricks/contextMenu/contextMenu.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ import { fromJS } from "@/starterBricks/contextMenu/contextMenu";
import { type ResolvedModComponent } from "@/types/modComponentTypes";
import { uuidSequence } from "@/testUtils/factories/stringFactories";
import { RunReason } from "@/types/runtimeTypes";
import { uninstallContextMenu } from "@/background/messenger/api";
import {
uninstallContextMenu,
ensureContextMenu,
} from "@/background/messenger/strict/api";
import { getPlatform } from "@/platform/platformContext";
import {
type ContextMenuDefinition,
type ContextMenuConfig,
} from "@/starterBricks/contextMenu/types";
import { ensureContextMenu } from "@/background/messenger/strict/api";

const uninstallContextMenuMock = jest.mocked(uninstallContextMenu);
const ensureContextMenuMock = jest.mocked(ensureContextMenu);
Expand Down
1 change: 1 addition & 0 deletions src/tsconfig.strictNullChecks.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"./background/contentScript.ts",
"./background/contextMenus/ensureContextMenu.ts",
"./background/contextMenus/makeMenuId.ts",
"./background/contextMenus/uninstallContextMenu.ts",
"./background/dataStore.ts",
"./background/externalProtocol.ts",
"./background/initTheme.ts",
Expand Down

0 comments on commit f174f1f

Please sign in to comment.