Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#7378: Fix page editor detection #7391

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/__mocks__/@/utils/expectContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@

export function expectContext() {}
export function forbidContext() {}

export { isPageEditor } from "../../../utils/expectContext";
4 changes: 2 additions & 2 deletions src/background/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ async function safelyRunBrick(
}

// This must follow the tab existence checks or else it returns false even if the tab simply doesn't exist
if (!(await canAccessTab(tabId))) {
throw new BusinessError("PixieBrix doesn't have access to the tab");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated bugfix, but should be straightforward

if (!(await canAccessTab({ tabId, frameId }))) {
throw new BusinessError("PixieBrix doesn't have access to the page");
}

throw error;
Expand Down
8 changes: 0 additions & 8 deletions src/contrib/google/sheets/core/useCurrentOrigin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,6 @@ describe("useCurrentOrigin", () => {
expect(result.current).toBe("chrome-extension://abcxyz/");
});

test("if devtools page, should return devtools origin", async () => {
setContext("devToolsPage");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page editor test is below. We have no React code running on devtools_page

const { result } = renderHook(() => useCurrentOrigin());
// Wait for origin to load (async state)
await waitForEffect();
expect(result.current).toBe(DEVTOOLS_ORIGIN);
});

test("if page editor page, should return devtools origin", async () => {
setContext("extension");
location = {
Expand Down
12 changes: 3 additions & 9 deletions src/contrib/google/sheets/core/useCurrentOrigin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import { isDevToolsPage, isOptionsPage } from "webext-detect-page";
import { isOptionsPage } from "webext-detect-page";
import { useEffect } from "react";
import notify from "@/utils/notify";
import useAsyncState from "@/hooks/useAsyncState";
import { isPageEditor } from "@/utils/expectContext";

/**
* Get the current origin for where code is running. Used to set the origin on the
Expand All @@ -40,14 +41,7 @@ function useCurrentOrigin(): string | null {
return browser.runtime.getURL("");
}

if (
// Checks location.pathname against the 'devtools_page' value in manifest.json
// This won't match for dev tools panels created by the devtool
// page (i.e. the Page Editor)
isDevToolsPage() ||
// Check for the page editor pagePath in the location pathname
location.pathname === "/pageEditor.html"
) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been bitten by this before

if (isPageEditor()) {
return "devtools://devtools";
}

Expand Down
2 changes: 1 addition & 1 deletion src/contrib/uipath/LocalProcessOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const LocalProcessOptions: React.FunctionComponent<BlockOptionProps> = ({
}) => {
// Crash the React tree, because it's a programming error to use this configuration outside the dev tools
expectContext(
"devTools",
"pageEditor",
"useLocalRobot only works in the Page Editor due to its `thisTab` usage",
);

Expand Down
2 changes: 1 addition & 1 deletion src/pageEditor/hooks/useCurrentUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const startWatching = once(async () => {
});

export default function useCurrentUrl(): string {
expectContext("devTools");
expectContext("pageEditor");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


const [url, setUrl] = useState(tabUrl);

Expand Down
2 changes: 1 addition & 1 deletion src/pageEditor/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import { CustomFormRenderer } from "@/bricks/renderers/customForm";
import MapValues from "@/bricks/transformers/controlFlow/MapValues";

export async function getCurrentURL(): Promise<string> {
expectContext("devTools");
expectContext("pageEditor");

const tab = await browser.tabs.get(chrome.devtools.inspectedWindow.tabId);
return tab.url;
Expand Down
6 changes: 3 additions & 3 deletions src/telemetry/BackgroundLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@

import { type Logger, type MessageContext } from "@/types/loggerTypes";
import { type JsonObject } from "type-fest";
import { isBackground, isDevToolsPage } from "webext-detect-page";
import { isBackground } from "webext-detect-page";
import {
notifyContextInvalidated,
wasContextInvalidated,
} from "@/errors/contextInvalidated";
import { recordLog } from "@/background/messenger/api";
import { expectContext } from "@/utils/expectContext";
import { expectContext, isPageEditor } from "@/utils/expectContext";
import reportError from "@/telemetry/reportError";

/**
Expand Down Expand Up @@ -73,7 +73,7 @@ class BackgroundLogger implements Logger {
}

async error(error: unknown, data: JsonObject): Promise<void> {
if (wasContextInvalidated() && !isBackground() && !isDevToolsPage()) {
if (wasContextInvalidated() && !isBackground() && !isPageEditor()) {
void notifyContextInvalidated();
}

Expand Down
4 changes: 0 additions & 4 deletions src/testUtils/detectPageMock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ export function isOptionsPage() {
return _context === "options";
}

export function isDevToolsPage() {
return _context === "devToolsPage";
}

export function isBackground() {
return _context === "background";
}
Expand Down
32 changes: 16 additions & 16 deletions src/utils/expectContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ import {
isContentScript,
isExtensionContext,
isWebPage,
contextNames,
} from "webext-detect-page";

function isBrowserSidebar(): boolean {
return isExtensionContext() && location.pathname === "/sidebar.html";
}

export function isPageEditor(): boolean {
return location.pathname === "/pageEditor.html";
}

/**
* Accepts 'This is my error' | new Error('This is my error') | Error;
* The constructor would be used to create a custom error with the default message
Expand All @@ -48,18 +51,15 @@ function createError(
return new errorOrCtor(defaultMessage);
}

// eslint-disable-next-line local-rules/persistBackgroundData -- Static
const contexts = [...contextNames, "sidebar"] as const;

// eslint-disable-next-line local-rules/persistBackgroundData -- Functions
const contextMap = new Map<(typeof contexts)[number], () => boolean>([
["web", isWebPage],
["extension", isExtensionContext],
["background", isBackground],
["contentScript", isContentScript],
["sidebar", isBrowserSidebar],
["devTools", () => "devtools" in chrome],
]);
const contextMap = {
web: isWebPage,
extension: isExtensionContext,
background: isBackground,
pageEditor: isPageEditor,
contentScript: isContentScript,
sidebar: isBrowserSidebar,
} as const;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It turns out we were making a mistake here. Due to the Map type, all the contexts were specified and allowed by TypeScript, but then fail at runtime.


/**
* @example expectContext('extension')
Expand All @@ -68,10 +68,10 @@ const contextMap = new Map<(typeof contexts)[number], () => boolean>([
* @example expectContext('extension', new Error('Wrong context and this is my custom error'))
*/
export function expectContext(
context: (typeof contexts)[number],
context: keyof typeof contextMap,
error?: ErrorBaseType,
): void {
const isContext = contextMap.get(context);
const isContext = contextMap[context];
if (!isContext) {
throw new TypeError(`Context "${context}" not found`);
}
Expand All @@ -91,10 +91,10 @@ export function expectContext(
* @example forbidContext('extension', new Error('Wrong context and this is my custom error'))
*/
export function forbidContext(
context: (typeof contexts)[number],
context: keyof typeof contextMap,
error?: ErrorBaseType,
): void {
const isContext = contextMap.get(context);
const isContext = contextMap[context];
if (!isContext) {
throw new TypeError(`Context "${context}" not found`);
}
Expand Down
Loading