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

Use ModComponentRef instead of flat extensionId and blueprintId in panel entries #8756

Merged
merged 13 commits into from
Jul 8, 2024
16 changes: 11 additions & 5 deletions src/bricks/transformers/ephemeralForm/formTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { type BrickConfig } from "@/bricks/types";
import { type FormDefinition } from "@/platform/forms/formTypes";
import { isExpression } from "@/utils/expressionUtils";
import type { PlatformCapability } from "@/platform/capabilities";
import { assertNotNullish } from "@/utils/nullishUtils";

export const TEMPORARY_FORM_SCHEMA: Schema = {
type: "object",
Expand Down Expand Up @@ -135,14 +136,19 @@ export class FormTransformer extends TransformerABC {
controller.abort();
});

if (logger.context.extensionId == null) {
throw new Error(`${this.name} must be run in a mod context`);
}
const { extensionId, blueprintId, extensionPointId } = logger.context;

assertNotNullish(extensionId, `${this.name} must be run in a mod context`);
assertNotNullish(
extensionPointId,
`${this.name} must be run in a starter brick context`,
);

try {
return await platform.form(formDefinition, controller, {
componentId: logger.context.extensionId,
modId: logger.context.blueprintId,
extensionId,
blueprintId,
extensionPointId,
});
} finally {
controller.abort();
Expand Down
23 changes: 9 additions & 14 deletions src/bricks/transformers/temporaryInfo/DisplayTemporaryInfo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import { uuidv4 } from "@/types/helpers";
import ConsoleLogger from "@/utils/ConsoleLogger";
import { tick } from "@/starterBricks/starterBrickTestUtils";
import pDefer from "p-defer";
import { registryIdFactory } from "@/testUtils/factories/stringFactories";
import { type RendererErrorPayload } from "@/types/rendererTypes";
import {
MergeStrategies,
Expand All @@ -60,6 +59,7 @@ import { unary } from "lodash";
import { toExpression } from "@/utils/expressionUtils";
import { showModal } from "@/contentScript/modalDom";
import { isLoadedInIframe } from "@/utils/iframeUtils";
import { modComponentRefFactory } from "@/testUtils/factories/modComponentFactories";

jest.mock("@/contentScript/modalDom");
jest.mock("@/contentScript/sidebarController");
Expand Down Expand Up @@ -92,8 +92,7 @@ describe("DisplayTemporaryInfo", () => {
});

test("it returns run payload for sidebar panel", async () => {
const extensionId = uuidv4();
const blueprintId = registryIdFactory();
const modComponentRef = modComponentRefFactory();

const config = getExampleBrickConfig(renderer.id);
const pipeline = {
Expand All @@ -106,13 +105,12 @@ describe("DisplayTemporaryInfo", () => {

await reducePipeline(pipeline, simpleInput({}), {
...testOptions("v3"),
logger: new ConsoleLogger({ extensionId, blueprintId }),
logger: new ConsoleLogger(modComponentRef),
});

// Show function will be called with a "loading" payload
expect(showTemporarySidebarPanel).toHaveBeenCalledExactlyOnceWith({
blueprintId,
extensionId,
modComponentRef,
nonce: expect.toBeString(),
heading: expect.toBeString(),
payload: expect.objectContaining({
Expand All @@ -122,8 +120,7 @@ describe("DisplayTemporaryInfo", () => {

// Panel will be updated when the real payload is ready
expect(updatePanelDefinition).toHaveBeenCalledExactlyOnceWith({
blueprintId,
extensionId,
modComponentRef,
nonce: expect.toBeString(),
heading: expect.toBeString(),
payload: expect.objectContaining({
Expand Down Expand Up @@ -179,13 +176,11 @@ describe("DisplayTemporaryInfo", () => {
},
};

const extensionId = uuidv4();
const modComponentRef = modComponentRefFactory();

const options = {
...testOptions("v3"),
logger: new ConsoleLogger({
extensionId,
}),
logger: new ConsoleLogger(modComponentRef),
};

await reducePipeline(pipeline, simpleInput({}), options);
Expand All @@ -195,10 +190,10 @@ describe("DisplayTemporaryInfo", () => {

expect(waitForTemporaryPanel).toHaveBeenCalledWith({
nonce: expect.toBeString(),
extensionId,
extensionId: modComponentRef.extensionId,
location: "modal",
entry: expect.objectContaining({
extensionId,
modComponentRef,
heading: "Test Temp Panel",
nonce: expect.toBeString(),
payload: expect.toBeObject(),
Expand Down
10 changes: 7 additions & 3 deletions src/bricks/transformers/temporaryInfo/DisplayTemporaryInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class DisplayTemporaryInfo extends TransformerABC {
}>,
{
logger: {
context: { extensionId, blueprintId },
context: { extensionId, blueprintId, extensionPointId },
},
root = document,
platform,
Expand All @@ -114,6 +114,7 @@ class DisplayTemporaryInfo extends TransformerABC {

const target = isRootAware ? root : document;
assumeNotNullish_UNSAFE(extensionId);
assumeNotNullish_UNSAFE(extensionPointId);
// XXX: blueprintId can actually be nullish if not running on the context of a mod. But assume it's non-nullish
// for passing to the panel for now. The panel can gracefully handle nullish blueprintId.
assumeNotNullish_UNSAFE(blueprintId);
Expand All @@ -123,8 +124,11 @@ class DisplayTemporaryInfo extends TransformerABC {

const panelEntryMetadata: TemporaryPanelEntryMetadata = {
heading: title,
extensionId,
blueprintId,
modComponentRef: {
extensionId,
blueprintId,
extensionPointId,
},
};

const getPayload = async () => {
Expand Down
10 changes: 2 additions & 8 deletions src/bricks/transformers/temporaryInfo/EphemeralPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,7 @@ const EphemeralPanel: React.FC = () => {
<PanelBody
isRootPanel={false}
payload={entry.payload}
context={{
extensionId: entry.extensionId,
blueprintId: entry.blueprintId,
}}
context={entry.modComponentRef}
onAction={(action) => {
resolveTemporaryPanel(target, panelNonce, action);
}}
Expand Down Expand Up @@ -219,10 +216,7 @@ const EphemeralPanel: React.FC = () => {
<PanelBody
isRootPanel={false}
payload={entry.payload}
context={{
extensionId: entry.extensionId,
blueprintId: entry.blueprintId,
}}
context={entry.modComponentRef}
onAction={(action) => {
resolveTemporaryPanel(target, panelNonce, action);
}}
Expand Down
4 changes: 2 additions & 2 deletions src/contentScript/contentScriptPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ class ContentScriptPlatform extends PlatformBase {
override get panels(): PlatformProtocol["panels"] {
return {
isContainerVisible: async () => sidebarController.isSidePanelOpen(),
unregisterExtensionPoint: sidebarController.removeExtensionPoint,
removeComponents: sidebarController.removeExtensions,
unregisterExtensionPoint: sidebarController.removeStarterBrick,
removeComponents: sidebarController.removeModComponents,
reservePanels: sidebarController.reservePanels,
updateHeading: sidebarController.updateHeading,
upsertPanel: sidebarController.upsertPanel,
Expand Down
14 changes: 4 additions & 10 deletions src/contentScript/ephemeralForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ import {
import { uuidv4 } from "@/types/helpers";
import { isLoadedInIframe } from "@/utils/iframeUtils";
import { BusinessError } from "@/errors/businessErrors";
import type { UUID } from "@/types/stringTypes";
import type { RegistryId } from "@/types/registryTypes";
import { getThisFrame } from "webext-messenger";
import { expectContext } from "@/utils/expectContext";
import { showModal } from "@/contentScript/modalDom";
import type { Target } from "@/types/messengerTypes";
import type { ModComponentRef } from "@/types/modComponentTypes";

// The modes for createFrameSource are different from the location argument for FormTransformer. The mode for the frame
// just determines the layout container of the form
Expand All @@ -55,10 +54,7 @@ export async function createFrameSource(
export async function ephemeralForm(
definition: FormDefinition,
controller: AbortController,
{
componentId: extensionId,
modId: blueprintId,
}: { componentId: UUID; modId: RegistryId },
modComponentRef: ModComponentRef,
): Promise<unknown> {
expectContext("contentScript");

Expand All @@ -75,21 +71,19 @@ export async function ephemeralForm(
// Pre-registering the form also allows the sidebar to know a form will be shown in computing the default
// tab to show during sidebar initialization.
const formPromise = registerForm({
extensionId,
nonce: formNonce,
modComponentRef,
definition,
blueprintId,
});

if (definition.location === "sidebar") {
// Ensure the sidebar is visible (which may also be showing persistent panels)
await showSidebar();

await showSidebarForm({
extensionId,
blueprintId,
nonce: formNonce,
form: definition,
modComponentRef,
});

// Two-way binding between sidebar and form. Listen for the user (or an action) closing the sidebar
Expand Down
12 changes: 7 additions & 5 deletions src/contentScript/ephemeralPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export async function ephemeralPanel({
registerEmptyTemporaryPanel({
nonce,
location,
extensionId: panelEntryMetadata.extensionId,
extensionId: panelEntryMetadata.modComponentRef.extensionId,
});

await showSidebar();
Expand All @@ -125,7 +125,7 @@ export async function ephemeralPanel({
nonce,
payload: {
key: uuidv4(),
extensionId: panelEntryMetadata.extensionId,
extensionId: panelEntryMetadata.modComponentRef.extensionId,
loadingMessage: "Loading",
},
});
Expand All @@ -140,13 +140,15 @@ export async function ephemeralPanel({
} else {
// Popover/modal location
// Clear existing to remove stale modals/popovers
await cancelTemporaryPanelsForExtension(panelEntryMetadata.extensionId);
await cancelTemporaryPanelsForExtension(
panelEntryMetadata.modComponentRef.extensionId,
);

// Register empty panel for "loading" state
registerEmptyTemporaryPanel({
nonce,
location,
extensionId: panelEntryMetadata.extensionId,
extensionId: panelEntryMetadata.modComponentRef.extensionId,
});

// Create a source URL for content that will be loaded in the panel iframe
Expand Down Expand Up @@ -233,7 +235,7 @@ export async function ephemeralPanel({
nonce,
location,
entry,
extensionId: entry.extensionId,
extensionId: entry.modComponentRef.extensionId,
onRegister: onReady,
});
return panelAction ?? {};
Expand Down
4 changes: 2 additions & 2 deletions src/contentScript/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export function removeDraftModComponents(

_runningStarterBricks.delete(starterBrick);
_draftModComponentStarterBrickMap.delete(modComponentId);
sidebar.removeExtensions([modComponentId]);
sidebar.removeModComponents([modComponentId]);
} else {
console.debug(
`No draft mod component exists for uuid: ${modComponentId}`,
Expand All @@ -333,7 +333,7 @@ export function removeDraftModComponents(
try {
starterBrick.uninstall({ global: true });
_runningStarterBricks.delete(starterBrick);
sidebar.removeExtensionPoint(starterBrick.id);
sidebar.removeStarterBrick(starterBrick.id);
} catch (error) {
reportError(error);
}
Expand Down
2 changes: 1 addition & 1 deletion src/contentScript/messenger/registration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
showSidebarInTopFrame,
sidebarWasLoaded,
updateSidebar,
removeExtensions as removeSidebars,
removeModComponents as removeSidebars,
getReservedPanelEntries,
} from "@/contentScript/sidebarController";
import { handleMenuAction } from "@/contentScript/contextMenus";
Expand Down
24 changes: 10 additions & 14 deletions src/contentScript/pageEditor/runRendererBrick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ import { HeadlessModeError } from "@/bricks/errors";
import { showTemporarySidebarPanel } from "@/contentScript/sidebarController";
import { waitForTemporaryPanel } from "@/platform/panels/panelController";
import { type UUID } from "@/types/stringTypes";
import { type RegistryId } from "@/types/registryTypes";
import { createFrameSource } from "@/contentScript/ephemeralPanel";
import { showModal } from "@/contentScript/modalDom";
import { runBrickPreview } from "@/contentScript/pageEditor/runBrickPreview";
import { type RunBrickArgs } from "@/contentScript/pageEditor/types";
import { type ModComponentRef } from "@/types/modComponentTypes";

type Location = "modal" | "panel";

Expand All @@ -47,15 +47,13 @@ type Location = "modal" | "panel";
* @see useDocumentPreviewRunBlock
*/
export async function runRendererBrick({
modComponentId,
modId,
modComponentRef,
runId,
title,
args,
location,
}: {
modComponentId: UUID;
modId: RegistryId | null;
modComponentRef: ModComponentRef;
runId: UUID;
title: string;
args: RunBrickArgs;
Expand All @@ -65,7 +63,7 @@ export async function runRendererBrick({

let payload: PanelPayload;
try {
await runBrickPreview({ ...args, modId });
await runBrickPreview({ ...args, modId: modComponentRef.blueprintId });
// We're expecting a HeadlessModeError (or other error) to be thrown in the line above
// noinspection ExceptionCaughtLocallyJS
throw new NoRendererError();
Expand All @@ -76,23 +74,22 @@ export async function runRendererBrick({
blockId: error.blockId,
args: error.args,
ctxt: error.ctxt,
extensionId: modComponentId,
extensionId: modComponentRef.extensionId,
runId,
};
} else {
payload = {
key: nonce,
error: serializeError(error),
extensionId: modComponentId,
extensionId: modComponentRef.extensionId,
runId,
};
}

if (location === "panel") {
await showTemporarySidebarPanel({
// Pass extension id so previous run is cancelled
extensionId: modComponentId,
blueprintId: modId,
// Pass component ref id so previous run is cancelled
modComponentRef,
nonce,
heading: title,
payload,
Expand All @@ -107,10 +104,9 @@ export async function runRendererBrick({
await waitForTemporaryPanel({
nonce,
location,
extensionId: modComponentId,
extensionId: modComponentRef.extensionId,
entry: {
extensionId: modComponentId,
blueprintId: modId,
modComponentRef,
nonce,
heading: title,
payload,
Expand Down
Loading
Loading