From f5ec02005696c1146817482a418a4535d1afea27 Mon Sep 17 00:00:00 2001 From: Kayla Fitzsimmons Date: Wed, 18 Sep 2024 10:03:17 -0700 Subject: [PATCH 1/3] update public key for prod id generation --- apps/mocksi-lite-next/vite.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/mocksi-lite-next/vite.config.ts b/apps/mocksi-lite-next/vite.config.ts index 3290f6c..ab936b4 100644 --- a/apps/mocksi-lite-next/vite.config.ts +++ b/apps/mocksi-lite-next/vite.config.ts @@ -15,7 +15,7 @@ export default defineConfig(({ mode }) => { let isDev = process.env.__DEV__ === "true"; // Keys are used to create stable extension ids for unpacked builds, only use for unpublished extension builds const PROD_UNPACKED_KEY = - "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA07fIdpHz/cZNpPxNKlUpUDv0HDDfyWfLwVl1lq/YtXVLIjQ9CRGUH8C4CX+MMZSALTE0PZZu1Tclin/hno9cHDm3/Iv9Ijqij6WEs4BDQ5UKy8Q13gmoJr2+4rUPwxeCuI1HLyUSsBSL3GazdQw68/hf3l43uNfQpphb8fxQEhQyeQBi6YzQYf/W7xepENfh3Xlp4etfMS6Xl5OaAqrnUPQmTsJKEJbqs0o5l2EgoRHqvkJHhZ4zeUWZ/GgoqKxy8UahtmywVxDz73zmrBLP3thPaQbiNBRhpKOR/Ldto4P7tm6IdTQgI9CuOCKwZtG9G4j1yXhVX8MfKk17QY4gSwIDAQAB"; + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmVIBAakn1m+kbh9QHDHf7jdbPKkGtlqOMJLsFKUFf9t/IV23Z79ZmcEjDNPxOmRADQQLWQJ3zZ2eMrYhSJuoKX0X8RSj8EqHehk4z2daFmtW3nLm80wiphT72isex4XqOC2Dg9/5Vj9UB2+M4fdiRBi10LZmAT0pkCRT8rJiuUO+MRByPEU+ChfvKEIJQqRSp97hUQmeYfiLZHH/VZHLm/o71L1zKDzQIg6+CvyrAMtzt2XDsT3c4+NsqX/+LgpJmhvpwxNAjyLBl02633XzWEiiu6UifYU7wvA/HeRj5O30WtOd6cXRh1grfKTWJnJmumlzRWdHzLS/WWMm29ucdwIDAQAB"; const DEV_UNPACKED_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtdeTUTUuHZx1xSvDuISF7wJP8nEPwW4vP8zTkdfdtb/1wM0JJ7XFeUHSIiq8l4Cs6/2f8tpK6MspeD7WhwuFWFHA2GWKoLSP0keuuBAhUFKrfISlNwFaNLX5LRkLSZQnr0ujIznvEuRZaXydIYR1e9pdhYTIcp2ToHW4CI02FUBtJVUUVeKGDiKKlKUrxwGtt1ecGZwVrQ1t7dj3DLrKguw1bONtoczFT3cCs9oVYg4l8frzlyI6xfsX8ynd4F+xS6+gYQ3aJBj7phAWHGAxbVRxTAzpzXRkb9A3ne31Ysjy4uYF9x7fK6NvDj/cm+EEfGDb3VmyXvOa3zeerXtdmwIDAQAB"; @@ -55,7 +55,7 @@ export default defineConfig(({ mode }) => { manifest.web_accessible_resources.push({ matches: [""], resources: ["assets/*.js.map"], - }) + }); break; case "staging": From 52be27eac19c6f22768376c59b626f0e8a1f4f71 Mon Sep 17 00:00:00 2001 From: Kayla Fitzsimmons Date: Fri, 20 Sep 2024 10:07:01 -0700 Subject: [PATCH 2/3] adds top toolbar, including undo (#187) * adds top toolbar * remove background change * add long lived connection for top -> main nest component comms * improve source value * add undo doesnt handle empty edits / edge cases * add message to move reactor back into mocksi-extension.tsx * make sure top iframe knows when # edits updates * cleanup logging, make sure edits are passed to extension/top * remove unused listener * coderrabbit PR feedback * save merge conflict resolved --------- Co-authored-by: Kayla Fitzsimmons Co-authored-by: Kayla Fitzsimmons --- .../src/pages/background/index.ts | 96 +++-- .../src/pages/content/main-iframe.tsx | 123 ++++++ .../src/pages/content/mocksi-extension.tsx | 364 +++++++----------- .../src/pages/content/top-iframe.tsx | 67 ++++ apps/mocksi-lite-next/src/pages/events.ts | 3 + 5 files changed, 405 insertions(+), 248 deletions(-) create mode 100644 apps/mocksi-lite-next/src/pages/content/main-iframe.tsx create mode 100644 apps/mocksi-lite-next/src/pages/content/top-iframe.tsx diff --git a/apps/mocksi-lite-next/src/pages/background/index.ts b/apps/mocksi-lite-next/src/pages/background/index.ts index da3affe..9265479 100644 --- a/apps/mocksi-lite-next/src/pages/background/index.ts +++ b/apps/mocksi-lite-next/src/pages/background/index.ts @@ -1,4 +1,9 @@ -import { AppEvents, AuthEvents, LayoutEvents } from "@pages/events"; +import { + AppEvents, + AuthEvents, + DemoEditEvents, + LayoutEvents, +} from "@pages/events"; import { jwtDecode } from "jwt-decode"; console.log("background script loaded"); @@ -109,6 +114,19 @@ addEventListener("install", () => { }); }); +let mainIframeSrcPort: null | chrome.runtime.Port = null; +let topIframeSrcPort: null | chrome.runtime.Port = null; + +chrome.runtime.onConnectExternal.addListener((port) => { + console.log("connecting...", port); + if (port.name === "extension/main") { + mainIframeSrcPort = port; + } + if (port.name === "extension/top") { + topIframeSrcPort = port; + } +}); + // when user clicks toolbar mount extension chrome.action.onClicked.addListener((tab) => { if (!tab?.id) { @@ -131,17 +149,6 @@ chrome.action.onClicked.addListener((tab) => { } }); -chrome.runtime.onMessage.addListener( - (request, _sender, sendResponse): boolean => { - sendResponse({ - data: request.data, - message: request.message, - status: "ok", - }); - return true; - }, -); - chrome.runtime.onMessageExternal.addListener( (request, _sender, sendResponse) => { console.log("on message external: ", request); @@ -149,10 +156,26 @@ chrome.runtime.onMessageExternal.addListener( // execute in async block so that we return true // synchronously, telling chrome to wait for the response (async () => { + if ( + request.source === "extension/top" && + request.message === AppEvents.EDIT_DEMO_STOP + ) { + if (mainIframeSrcPort) { + // notify extension/main that demo edit mode exited in extension/top + mainIframeSrcPort.postMessage({ + ...request, + message: AppEvents.EDIT_DEMO_STOP, + }); + } else { + console.log("mainIframeSrcPort is not connected"); + } + } + if (request.message === AuthEvents.AUTH_ERROR) { await clearAuth(); sendResponse({ message: AuthEvents.RETRY, + source: "background", status: "ok", }); } else if (request.message === AuthEvents.UNAUTHORIZED) { @@ -162,12 +185,14 @@ chrome.runtime.onMessageExternal.addListener( const tab = await getCurrentTab(); sendResponse({ message: { accessToken, email, url: tab?.url }, + source: "background", status: "ok", }); } else { await showAuthTab(true); sendResponse({ message: AuthEvents.AUTHENTICATING, + source: "background", status: "ok", }); } @@ -176,9 +201,11 @@ chrome.runtime.onMessageExternal.addListener( if (!tab?.id) { sendResponse({ message: LayoutEvents.NO_TAB, + source: "background", status: "ok", }); - return; + console.error("No tab found"); + return true; } if ( @@ -201,16 +228,39 @@ chrome.runtime.onMessageExternal.addListener( showDefaultIcon(tab.id); } - chrome.tabs.sendMessage( - tab.id, - { - data: request.data, - message: request.message, - }, - (response) => { - sendResponse(response); - }, - ); + // send message to iframes and reactor in mocksi-extension + chrome.tabs.sendMessage(tab.id, request, async (response) => { + console.log("response from content script in background:", response); + if (response.message === DemoEditEvents.UNDO) { + // pass updated modifications from reactor to extension/main to store + if (mainIframeSrcPort) { + await mainIframeSrcPort.postMessage({ + ...response, + status: "ok", // response handler expects status + }); + } else { + console.log("mainIframeSrcPort is not connected"); + } + } + if ( + request.message === AppEvents.EDIT_DEMO_START || + request.message === DemoEditEvents.NEW_EDIT || + request.message === DemoEditEvents.CHAT_RESPONSE + ) { + // notify extension/top # of edits changed + if (topIframeSrcPort) { + await topIframeSrcPort.postMessage({ + ...response, + status: "ok", + }); + } else { + console.log("topIframeSrcPort is not connected"); + } + } + + sendResponse(response); + }); + return true; } })(); diff --git a/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx b/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx new file mode 100644 index 0000000..f3c0b7f --- /dev/null +++ b/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx @@ -0,0 +1,123 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { LayoutEvents } from "../events"; + +export enum IframePosition { + BOTTOM_CENTER = "BOTTOM_CENTER", + TOP_RIGHT = "TOP_RIGHT", + BOTTOM_RIGHT = "BOTTOM_RIGHT", +} + +export interface IframeResizeArgs { + height: number; + id?: string; + position: + | IframePosition.BOTTOM_CENTER + | IframePosition.BOTTOM_RIGHT + | IframePosition.TOP_RIGHT; + width: number; +} + +function getIframeStyles({ height, position, width }: IframeResizeArgs) { + if (!height || !width || !position) { + console.error( + "Cannot update iframe size / position, make sure 'request.data.iframe' has 'height', 'width', and 'position' set correctly", + ); + return; + } + + const bounds = document.body.getBoundingClientRect(); + + let styles = {}; + switch (position) { + case IframePosition.BOTTOM_CENTER: + styles = { + bottom: "0px", + right: `${bounds.width / 2 - width / 2}px`, + top: "auto", + }; + break; + case IframePosition.BOTTOM_RIGHT: + styles = { + bottom: "10px", + right: "10px", + top: "auto", + }; + break; + case IframePosition.TOP_RIGHT: + styles = { + bottom: "auto", + display: "block", + right: "10px", + top: "10px", + }; + break; + } + + return Object.assign( + { + bottom: "auto", + display: "block", + height: `${height}px`, + left: "auto", + right: "auto", + top: "auto", + width: `${width}px`, + }, + styles, + ); +} + +function MainIframe() { + const iframeRef = React.useRef(null); + + React.useEffect(() => { + chrome.runtime.onMessage.addListener((request) => { + if (iframeRef.current) { + switch (request.message) { + case LayoutEvents.HIDE: + iframeRef.current.style.display = "none"; + break; + case LayoutEvents.RESIZE: + const styles = getIframeStyles(request.data.iframe); + Object.assign(iframeRef.current.style, styles); + break; + case LayoutEvents.SHOW: + iframeRef.current.style.display = "block"; + break; + } + } + return true; + }); + }, []); + + return ( + <> + {ReactDOM.createPortal( +