diff --git a/apps/mocksi-lite-next/src/pages/background/index.ts b/apps/mocksi-lite-next/src/pages/background/index.ts index 842295f..3f0305d 100644 --- a/apps/mocksi-lite-next/src/pages/background/index.ts +++ b/apps/mocksi-lite-next/src/pages/background/index.ts @@ -114,8 +114,13 @@ addEventListener("install", () => { }); }); +<<<<<<< HEAD let mainIframeSrcPort: null | chrome.runtime.Port = null; let topIframeSrcPort: null | chrome.runtime.Port = null; +======= +let mainIframeSrcPort: chrome.runtime.Port; +let topIframeSrcPort: chrome.runtime.Port; +>>>>>>> MOC-262_undo-button chrome.runtime.onConnectExternal.addListener((port) => { console.log("connecting...", port); @@ -149,17 +154,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); @@ -171,6 +165,7 @@ chrome.runtime.onMessageExternal.addListener( request.source === "extension/top" && request.message === AppEvents.EDIT_DEMO_STOP ) { +<<<<<<< HEAD if (mainIframeSrcPort) { // notify extension/main that demo edit mode exited in extension/top mainIframeSrcPort.postMessage({ @@ -180,12 +175,20 @@ chrome.runtime.onMessageExternal.addListener( } else { console.log("mainIframeSrcPort is not connected"); } +======= + // notify extension/main that demo edit mode exited in extension/top + mainIframeSrcPort.postMessage({ + ...request, + message: AppEvents.EDIT_DEMO_STOP, + }); +>>>>>>> MOC-262_undo-button } if (request.message === AuthEvents.AUTH_ERROR) { await clearAuth(); sendResponse({ message: AuthEvents.RETRY, + source: "background", status: "ok", }); } else if (request.message === AuthEvents.UNAUTHORIZED) { @@ -195,12 +198,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", }); } @@ -209,10 +214,15 @@ chrome.runtime.onMessageExternal.addListener( if (!tab?.id) { sendResponse({ message: LayoutEvents.NO_TAB, + source: "background", status: "ok", }); console.error("No tab found"); +<<<<<<< HEAD return true; +======= + return; +>>>>>>> MOC-262_undo-button } if ( @@ -240,6 +250,7 @@ chrome.runtime.onMessageExternal.addListener( console.log("response from content script in background:", response); if (response.message === DemoEditEvents.UNDO) { // pass updated modifications from reactor to extension/main to store +<<<<<<< HEAD if (mainIframeSrcPort) { await mainIframeSrcPort.postMessage({ ...response, @@ -248,6 +259,12 @@ chrome.runtime.onMessageExternal.addListener( } else { console.log("mainIframeSrcPort is not connected"); } +======= + await mainIframeSrcPort.postMessage({ + ...response, + status: "ok", // response handler expects status + }); +>>>>>>> MOC-262_undo-button } if ( request.message === AppEvents.EDIT_DEMO_START || @@ -255,6 +272,7 @@ chrome.runtime.onMessageExternal.addListener( request.message === DemoEditEvents.CHAT_RESPONSE ) { // notify extension/top # of edits changed +<<<<<<< HEAD if (topIframeSrcPort) { await topIframeSrcPort.postMessage({ ...response, @@ -268,6 +286,16 @@ chrome.runtime.onMessageExternal.addListener( sendResponse(response); }); return true; +======= + await topIframeSrcPort.postMessage({ + ...response, + status: "ok", + }); + } + sendResponse(response); + return true; + }); +>>>>>>> MOC-262_undo-button } })(); diff --git a/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx b/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx index 25fb4c9..f3c0b7f 100644 --- a/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx +++ b/apps/mocksi-lite-next/src/pages/content/main-iframe.tsx @@ -1,9 +1,6 @@ -import type { ModificationRequest } from "@repo/reactor"; -import { Reactor } from "@repo/reactor"; import React from "react"; import ReactDOM from "react-dom"; -import { DemoEditEvents, LayoutEvents } from "../events"; -import { getHighlighter } from "./highlighter"; +import { LayoutEvents } from "../events"; export enum IframePosition { BOTTOM_CENTER = "BOTTOM_CENTER", @@ -71,151 +68,25 @@ function getIframeStyles({ height, position, width }: IframeResizeArgs) { ); } -interface AppMessageRequest { - data: { - edits?: ModificationRequest[]; - uuid: string; - }; - message: string; -} - function MainIframe() { - const prevStartStopDemoEventRef = React.useRef({ - data: { uuid: "" }, - message: "", - }); - const reactor = new Reactor(); - const highlighter = getHighlighter(); const iframeRef = React.useRef(null); - async function handleStartStopDemoEvent( - prevRequest: AppMessageRequest, - request: AppMessageRequest, - ) { - async function startDemo(request: AppMessageRequest) { - if (request.data.edits?.length) { - for (const mod of request.data.edits) { - await reactor.pushModification(mod); - } - } else { - console.log("no edits provided to reactor"); - } - return await reactor.attach(document, highlighter); - } - - // check if app is asking to start or stop PLAY or EDIT - const startRequestRegExp = new RegExp(/_DEMO_START/); - const stopRequestRegExp = new RegExp(/_DEMO_STOP/); - - const requestingStopDemo = stopRequestRegExp.test(request.message); - const requestingStartDemo = startRequestRegExp.test(request.message); - - if (!requestingStartDemo && !requestingStopDemo) { - return prevRequest; - } - - // if a demo is running already we want to avoid mounting the same - // modifications more than once, this is more performant, and edits - // persist in the dom if transitioning between EDIT and PLAY states - if (requestingStartDemo) { - const prevDemoUUID = prevRequest?.data?.uuid || null; - - const demoRunning = - prevDemoUUID && startRequestRegExp.test(prevRequest.message); - - if (!demoRunning) { - await startDemo(request); - } else { - const isDupeEvent = prevRequest.message === request.message; - const isNewDemo = prevDemoUUID !== request.data.uuid; - if (!isDupeEvent && isNewDemo) { - if (reactor.isAttached()) { - await reactor.detach(true); - } - await startDemo(request); - } - } - } - - if (requestingStopDemo) { - await reactor.detach(true); - } - - return request; - } - - async function findReplaceAll(find: string, replace: string, flags: string) { - const modification: ModificationRequest = { - description: `Change ${find} to ${replace}`, - modifications: [ - { - action: "replaceAll", - content: `/${find}/${replace}/${flags}`, - selector: "body", - }, - ], - }; - - const modifications = await reactor.pushModification(modification); - return modifications; - } - React.useEffect(() => { - chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { - // execute in async block so that we return true - // synchronously, telling chrome to wait for the response - (async () => { - let data = null; - - prevStartStopDemoEventRef.current = await handleStartStopDemoEvent( - prevStartStopDemoEventRef.current, - request, - ); - - if (request.message === DemoEditEvents.NEW_EDIT) { - if (request.data) { - const { find, flags, replace } = request.data; - await findReplaceAll(find, replace, flags); - data = Array.from(reactor.getAppliedModifications()).map( - (mod) => mod.modificationRequest, - ); - } - } - - // chat events - if (request.message === DemoEditEvents.CHAT_MESSAGE) { - data = reactor.exportDOM(); - } - - if (request.message === DemoEditEvents.CHAT_RESPONSE) { - await reactor.pushModification(request.data); - data = Array.from(reactor.getAppliedModifications()).map( - (mod) => mod.modificationRequest, - ); + 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; } - - // Resize iframe, how or hide it - 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; - } - } - - sendResponse({ - data, - message: request.message, - status: "ok", - }); - })(); + } return true; }); }, []); diff --git a/apps/mocksi-lite-next/src/pages/content/mocksi-extension.tsx b/apps/mocksi-lite-next/src/pages/content/mocksi-extension.tsx index 2f5fd85..3a089f7 100644 --- a/apps/mocksi-lite-next/src/pages/content/mocksi-extension.tsx +++ b/apps/mocksi-lite-next/src/pages/content/mocksi-extension.tsx @@ -1,5 +1,9 @@ +import type { ModificationRequest } from "@repo/reactor"; +import { Reactor } from "@repo/reactor"; +import React from "react"; import { createRoot } from "react-dom/client"; -import { LayoutEvents } from "../events"; +import { AppEvents, DemoEditEvents, LayoutEvents } from "../events"; +import { getHighlighter } from "./highlighter"; import MainIframe from "./main-iframe"; import TopIframe from "./top-iframe"; @@ -25,6 +29,165 @@ window.addEventListener("message", (event: MessageEvent) => { } }); +interface AppMessageRequest { + data: { + edits?: ModificationRequest[]; + uuid: string; + }; + message: string; +} + +function Extension() { + const prevStartStopDemoEventRef = React.useRef({ + data: { uuid: "" }, + message: "", + }); + + const reactor = new Reactor(); + const highlighter = getHighlighter(); + + async function handleStartStopDemoEvent( + prevRequest: AppMessageRequest, + request: AppMessageRequest, + ) { + async function startDemo(request: AppMessageRequest) { + if (request.data.edits?.length) { + for (const mod of request.data.edits) { + await reactor.pushModification(mod); + } + } else { + console.debug("no edits provided to reactor"); + } + return await reactor.attach(document, highlighter); + } + + // check if app is asking to start or stop PLAY or EDIT + const startRequestRegExp = new RegExp(/_DEMO_START/); + const stopRequestRegExp = new RegExp(/_DEMO_STOP/); + + const requestingStopDemo = stopRequestRegExp.test(request.message); + const requestingStartDemo = startRequestRegExp.test(request.message); + + if (!requestingStartDemo && !requestingStopDemo) { + return prevRequest; + } + + // if a demo is running already we want to avoid mounting the same + // modifications more than once, this is more performant, and edits + // persist in the dom if transitioning between EDIT and PLAY states + if (requestingStartDemo) { + const prevDemoUUID = prevRequest?.data?.uuid || null; + + const demoRunning = + prevDemoUUID && startRequestRegExp.test(prevRequest.message); + + if (!demoRunning) { + await startDemo(request); + } else { + const isDupeEvent = prevRequest.message === request.message; + const isNewDemo = prevDemoUUID !== request.data.uuid; + if (!isDupeEvent && isNewDemo) { + if (reactor.isAttached()) { + await reactor.detach(true); + } + await startDemo(request); + } + } + } + + if (requestingStopDemo) { + await reactor.detach(true); + } + + return request; + } + + async function findReplaceAll(find: string, replace: string, flags: string) { + const modification: ModificationRequest = { + description: `Change ${find} to ${replace}`, + modifications: [ + { + action: "replaceAll", + content: `/${find}/${replace}/${flags}`, + selector: "body", + }, + ], + }; + + const modifications = await reactor.pushModification(modification); + return modifications; + } + + React.useEffect(() => { + chrome.runtime.onMessage.addListener((request, _sender, sendResponse) => { + // execute in async block so that we return true + // synchronously, telling chrome to wait for the response + (async () => { + let data = null; + console.debug("request in mocksi-extension from background: ", request); + prevStartStopDemoEventRef.current = await handleStartStopDemoEvent( + prevStartStopDemoEventRef.current, + request, + ); + + // make sure edits are available to extension/top + if (request.message === AppEvents.EDIT_DEMO_START) { + data = { + edits: Array.from(reactor.getAppliedModifications()).map( + (mod) => mod.modificationRequest, + ), + uuid: request.data.uuid, + }; + } + + if (request.message === DemoEditEvents.NEW_EDIT) { + if (request.data) { + const { find, flags, replace } = request.data; + await findReplaceAll(find, replace, flags); + data = Array.from(reactor.getAppliedModifications()).map( + (mod) => mod.modificationRequest, + ); + } + } + + // chat events + if (request.message === DemoEditEvents.CHAT_MESSAGE) { + data = reactor.exportDOM(); + } + + if (request.message === DemoEditEvents.CHAT_RESPONSE) { + await reactor.pushModification(request.data); + data = Array.from(reactor.getAppliedModifications()).map( + (mod) => mod.modificationRequest, + ); + } + + if (request.message === DemoEditEvents.UNDO) { + await reactor.popModification(); + data = Array.from(reactor.getAppliedModifications()).map( + (mod) => mod.modificationRequest, + ); + } + + // send response back to background which forwards it to extension/x + sendResponse({ + data, + message: request.message, + source: "reactor", + status: "ok", + }); + })(); + return true; + }); + }, []); + return ( + <> + + + + ); +} + chrome.runtime.onMessage.addListener((request) => { if (request.message === LayoutEvents.MOUNT) { const rootContainer = document.querySelector("#__mocksi__root"); @@ -34,18 +197,10 @@ chrome.runtime.onMessage.addListener((request) => { const root = createRoot(rootContainer); - function Iframes() { - return ( - <> - - - - ); - } // avoid remounting react tree try { if (!mounted) { - root.render(); + root.render(); mounted = true; } console.debug("content script loaded, extension iframe mounted"); diff --git a/apps/mocksi-lite-next/src/pages/content/top-iframe.tsx b/apps/mocksi-lite-next/src/pages/content/top-iframe.tsx index eaa249b..28314b5 100644 --- a/apps/mocksi-lite-next/src/pages/content/top-iframe.tsx +++ b/apps/mocksi-lite-next/src/pages/content/top-iframe.tsx @@ -4,43 +4,40 @@ import ReactDOM from "react-dom"; function TopIframe() { const [show, setShow] = React.useState(false); - const [minimized, setMinimized] = React.useState(false); const iframeRef = React.useRef(null); React.useEffect(() => { - chrome.runtime.onMessage.addListener((request, _sender) => { - // execute in async block so that we return true - // synchronously, telling chrome to wait for the response - (async () => { - if (request.message === AppEvents.EDIT_DEMO_START) { - setShow(true); - } + chrome.runtime.onMessage.addListener((request) => { + if (request.message === AppEvents.EDIT_DEMO_START) { + setShow(true); + } + if ( + request.message === AppEvents.EDIT_DEMO_STOP || + request.message === AppEvents.PLAY_DEMO_START + ) { + setShow(false); + } + + if (iframeRef.current) { + const bounds = document.body.getBoundingClientRect(); - if ( - request.message === AppEvents.EDIT_DEMO_STOP || - request.message.PLAY_DEMO_START - ) { - setShow(false); + if (request.message === DemoEditEvents.HIDE_TOOLBAR) { + const width = 65; + Object.assign(iframeRef.current.style, { + height: "35px", + right: `${bounds.width / 2 - width / 2}px`, + width: `${width}px`, + }); } - if (iframeRef.current) { - const bounds = document.body.getBoundingClientRect(); - if (request.message === DemoEditEvents.HIDE_TOOLBAR) { - const width = 65; - Object.assign(iframeRef.current.style, { - height: "35px", - right: `${bounds.width / 2 - width / 2}px`, - width: `${width}px`, - }); - } - if (request.message === DemoEditEvents.SHOW_TOOLBAR) { - Object.assign(iframeRef.current.style, { - height: "80px", - right: "auto", - width: "100vw", - }); - } + + if (request.message === DemoEditEvents.SHOW_TOOLBAR) { + Object.assign(iframeRef.current.style, { + height: "80px", + right: "auto", + width: "100vw", + }); } - })(); + } return true; }); }, []); diff --git a/apps/mocksi-lite-next/src/pages/events.ts b/apps/mocksi-lite-next/src/pages/events.ts index 16ef3b7..c3b3a35 100644 --- a/apps/mocksi-lite-next/src/pages/events.ts +++ b/apps/mocksi-lite-next/src/pages/events.ts @@ -18,6 +18,7 @@ export enum DemoEditEvents { NEW_EDIT = "NEW_EDIT", HIDE_TOOLBAR = "HIDE_TOOLBAR", SHOW_TOOLBAR = "SHOW_TOOLBAR", + UNDO = "UNDO", } export enum LayoutEvents {