From bddb1fa1f8f84359c31d1848ba15bb4b59c16c33 Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Thu, 26 Oct 2023 14:11:25 +0200 Subject: [PATCH] #66 fix & settings page additions (#70) * #66 fix & settings page additions * v3.4.0 bump * update --- README.md | 6 +- package.json | 2 +- src/RemixDevTools/EmbeddedDevTools.tsx | 8 +-- src/RemixDevTools/RemixDevTools.tsx | 18 ++---- src/RemixDevTools/context/rdtReducer.ts | 8 +++ src/RemixDevTools/hooks/useAttachListener.ts | 1 + .../hooks/useDevServerConnection.ts | 13 ++-- src/RemixDevTools/tabs/SettingsTab.tsx | 60 ++++++++++++++++--- src/dev-server/init.ts | 4 ++ src/test-apps/cjs-app/app/root.tsx | 2 +- src/test-apps/cjs-app/app/routes/_index.tsx | 10 +--- 11 files changed, 89 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index db5cff0..f30c565 100644 --- a/README.md +++ b/README.md @@ -306,10 +306,8 @@ const build = withServerDevTools(await import(BUILD_PATH), config) ## RemixDevTools props -The `RemixDevTools` component accepts the following props: -- `requireUrlFlag`: Requires rdt=true to be present in the URL search to open the Remix Development Tools. Defaults to `false`. -- `plugins`: Allows you to provide additional tabs (plugins) to the Remix Development Tools. Defaults to `[]`. -- `wsPort`: Allows you to specify over which port the client dev tools will communicate with the server dev tools. Defaults to `8080`. +The `RemixDevTools` component accepts the following props: +- `plugins`: Allows you to provide additional tabs (plugins) to the Remix Development Tools. Defaults to `[]`. ### Defining the config diff --git a/package.json b/package.json index 185c1de..6cfb6c8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "remix-development-tools", "description": "Remix development tools - a set of tools for developing/debugging Remix.run apps", "author": "Alem Tuzlak", - "version": "3.3.0", + "version": "3.4.0", "license": "MIT", "keywords": [ "remix", diff --git a/src/RemixDevTools/EmbeddedDevTools.tsx b/src/RemixDevTools/EmbeddedDevTools.tsx index 8e67c94..c88eaa8 100644 --- a/src/RemixDevTools/EmbeddedDevTools.tsx +++ b/src/RemixDevTools/EmbeddedDevTools.tsx @@ -8,9 +8,9 @@ import { ContentPanel } from "./layout/ContentPanel.js"; import { MainPanel } from "./layout/MainPanel.js"; import { Tabs } from "./layout/Tabs.js"; import { REMIX_DEV_TOOLS } from "./utils/storage.js"; -import { useLocation } from "@remix-run/react"; import { RDTContextProvider } from "./context/RDTContext.js"; import { useState, useEffect } from "react"; +import { useLocation } from "@remix-run/react"; export interface EmbeddedDevToolsProps extends RemixDevToolsProps { mainPanelClassName?: string; @@ -23,6 +23,8 @@ const Embedded = ({ plugins, mainPanelClassName, className }: EmbeddedDevToolsPr const { settings } = useSettingsContext(); const { position } = settings; const leftSideOriented = position.includes("left"); + const url = useLocation().search; + if (settings.requireUrlFlag && !url.includes(settings.urlFlag)) return null; return (
@@ -46,12 +48,10 @@ function useHydrated() { return hydrated; } -const EmbeddedDevTools = ({ requireUrlFlag, plugins, mainPanelClassName, className }: EmbeddedDevToolsProps) => { +const EmbeddedDevTools = ({ plugins, mainPanelClassName, className }: EmbeddedDevToolsProps) => { const hydrated = useHydrated(); - const url = useLocation().search; if (!hydrated) return null; - if (requireUrlFlag && !url.includes("rdt=true")) return null; return ( diff --git a/src/RemixDevTools/RemixDevTools.tsx b/src/RemixDevTools/RemixDevTools.tsx index eba98b8..faf1aec 100644 --- a/src/RemixDevTools/RemixDevTools.tsx +++ b/src/RemixDevTools/RemixDevTools.tsx @@ -23,22 +23,22 @@ import "../input.css"; import { useDevServerConnection } from "./hooks/useDevServerConnection.js"; import { useOpenElementSource } from "./hooks/useOpenElementSource.js"; -const DevTools = ({ plugins, wsPort }: RemixDevToolsProps) => { +const DevTools = ({ plugins }: RemixDevToolsProps) => { useTimelineHandler(); useResetDetachmentCheck(); useBorderedRoutes(); useSetRouteBoundaries(); useSyncStateWhenDetached(); - useDevServerConnection(wsPort); + useDevServerConnection(); useOpenElementSource(); - + const url = useLocation().search; const { detachedWindowOwner, isDetached, setDetachedWindowOwner } = useDetachedWindowControls(); const { settings } = useSettingsContext(); const { persistOpen } = usePersistOpen(); const { position } = settings; const [isOpen, setIsOpen] = useState(isDetached || settings.defaultOpen || persistOpen); const leftSideOriented = position.includes("left"); - + if (settings.requireUrlFlag && !url.includes(settings.urlFlag)) return null; // If the dev tools are detached, we don't want to render the main panel if (detachedWindowOwner) { return ( @@ -81,24 +81,18 @@ function useHydrated() { } export interface RemixDevToolsProps { - // Whether the dev tools require a url flag to be shown - requireUrlFlag?: boolean; // Additional tabs to add to the dev tools plugins?: Tab[]; - // The port to use for the dev tools websocket that communicates with the backend dev tools - wsPort?: number; } -const RemixDevTools = ({ requireUrlFlag, plugins, wsPort }: RemixDevToolsProps) => { +const RemixDevTools = ({ plugins }: RemixDevToolsProps) => { const hydrated = useHydrated(); - const url = useLocation().search; if (!hydrated) return null; - if (requireUrlFlag && !url.includes("rdt=true")) return null; return ( - + ); }; diff --git a/src/RemixDevTools/context/rdtReducer.ts b/src/RemixDevTools/context/rdtReducer.ts index 4cc7383..5240e7b 100644 --- a/src/RemixDevTools/context/rdtReducer.ts +++ b/src/RemixDevTools/context/rdtReducer.ts @@ -85,6 +85,10 @@ export type RemixDevToolsState = { isHoveringRoute: boolean; routeViewMode: "list" | "tree"; panelLocation: "top" | "bottom"; + withServerDevTools: boolean; + wsPort: number; + requireUrlFlag: boolean; + urlFlag: string; }; htmlErrors: HTMLError[]; server?: ServerInfo; @@ -114,6 +118,10 @@ export const initialState: RemixDevToolsState = { isHoveringRoute: false, routeViewMode: "tree", panelLocation: "bottom", + withServerDevTools: true, + wsPort: 8080, + requireUrlFlag: false, + urlFlag: "rdt", }, htmlErrors: [], persistOpen: false, diff --git a/src/RemixDevTools/hooks/useAttachListener.ts b/src/RemixDevTools/hooks/useAttachListener.ts index d0d97ab..e2e5a8e 100644 --- a/src/RemixDevTools/hooks/useAttachListener.ts +++ b/src/RemixDevTools/hooks/useAttachListener.ts @@ -12,6 +12,7 @@ const getAttachment = (target: ListenerAttachmentTarget) => { return typeof document != "undefined" ? document.body : null; } }; + /** * Helper hook that listens to the document scroll event and triggers a callback function * @param fn Function to be called when the event happens diff --git a/src/RemixDevTools/hooks/useDevServerConnection.ts b/src/RemixDevTools/hooks/useDevServerConnection.ts index f0a2a0c..3586a18 100644 --- a/src/RemixDevTools/hooks/useDevServerConnection.ts +++ b/src/RemixDevTools/hooks/useDevServerConnection.ts @@ -3,7 +3,7 @@ import { useWebSocket } from "../../external/react-use-websocket/use-websocket.j import { useEffect } from "react"; import { tryParseJson } from "../utils/sanitize.js"; import { ActionEvent, LoaderEvent, isRdtEventArray } from "../../dev-server/event-queue.js"; -import { useDetachedWindowControls, useServerInfo } from "../context/useRDTContext.js"; +import { useDetachedWindowControls, useServerInfo, useSettingsContext } from "../context/useRDTContext.js"; import { ServerInfo } from "../context/rdtReducer.js"; import { cutArrayToLastN } from "../utils/common.js"; import { ReadyState } from "../../external/react-use-websocket/constants.js"; @@ -49,13 +49,14 @@ const updateRouteInfo = ( }; }; -const useDevServerConnection = (wsPort: number | undefined = 8080) => { +const useDevServerConnection = () => { const navigation = useNavigation(); + const { settings } = useSettingsContext(); const { server, setServerInfo } = useServerInfo(); - const { detachedWindow } = useDetachedWindowControls(); - + const { detachedWindowOwner, isDetached } = useDetachedWindowControls(); + const shouldConnect = isDetached ? detachedWindowOwner && settings.withServerDevTools : settings.withServerDevTools; const methods = useWebSocket( - `ws://localhost:${wsPort}`, + `ws://localhost:${settings.wsPort}`, { onMessage: (e) => { // Do not do anything with @@ -73,7 +74,7 @@ const useDevServerConnection = (wsPort: number | undefined = 8080) => { } }, }, - wsPort !== undefined || detachedWindow + shouldConnect ); // Pull the event queue from the server when the page is idle diff --git a/src/RemixDevTools/tabs/SettingsTab.tsx b/src/RemixDevTools/tabs/SettingsTab.tsx index 3a97bd5..c44740c 100644 --- a/src/RemixDevTools/tabs/SettingsTab.tsx +++ b/src/RemixDevTools/tabs/SettingsTab.tsx @@ -1,17 +1,18 @@ import { useState } from "react"; -import { Checkbox } from '../components/Checkbox.js'; -import { Input } from '../components/Input.js'; -import { SelectWithOptions } from '../components/Select.js'; -import { Stack } from '../components/Stack.js'; -import { useSettingsContext } from '../context/useRDTContext.js'; -import { RouteBoundaryOptions } from '../context/rdtReducer.js'; -import { uppercaseFirstLetter } from '../utils/string.js'; +import { Checkbox } from "../components/Checkbox.js"; +import { Input } from "../components/Input.js"; +import { SelectWithOptions } from "../components/Select.js"; +import { Stack } from "../components/Stack.js"; +import { useSettingsContext } from "../context/useRDTContext.js"; +import { RouteBoundaryOptions } from "../context/rdtReducer.js"; +import { uppercaseFirstLetter } from "../utils/string.js"; export const SettingsTab = () => { const { settings, setSettings } = useSettingsContext(); const [minHeight, setMinHeight] = useState(settings.minHeight.toString()); const [maxHeight, setMaxHeight] = useState(settings.maxHeight.toString()); const [expansionLevel, setExpansionLevel] = useState(settings.expansionLevel.toString()); + const [wsPort, setWsPort] = useState(settings.wsPort.toString()); return (

@@ -26,6 +27,14 @@ export const SettingsTab = () => { > Open dev tools by default + setSettings({ requireUrlFlag: !settings.requireUrlFlag })} + value={settings.requireUrlFlag} + > + Show dev tools only when URL flag is set + { > Hide the trigger until hovered + setSettings({ withServerDevTools: !settings.withServerDevTools })} + value={settings.withServerDevTools} + > + Connect to server dev tools +
+ {settings.requireUrlFlag && ( + setSettings({ urlFlag: e.target.value ?? "" })} + onBlur={(e) => { + setSettings({ urlFlag: e.target.value.trim() }); + }} + /> + )} + {settings.withServerDevTools && ( + setWsPort(e.target.value ?? "")} + onBlur={(e) => { + const value = parseInt(e.target.value); + if (value && !isNaN(value) && value >= 0) { + setSettings({ wsPort: value }); + } + }} + /> + )} { ws.on("connection", (client) => { client.on("message", (message) => { const data = tryParseJson(message.toString()); + if (!isWsEventType(data)) return; if (data.type === "open-source") { const source = data.data.source; @@ -78,6 +79,9 @@ const installDevToolsGlobals = (config?: DevToolsServerConfig) => { ["SIGINT", "SIGTERM"].forEach((event) => { process.on(event, () => { + ws.clients.forEach((client) => { + client.close(); + }); ws.close(); }); }); diff --git a/src/test-apps/cjs-app/app/root.tsx b/src/test-apps/cjs-app/app/root.tsx index 6e58903..cc2a43d 100644 --- a/src/test-apps/cjs-app/app/root.tsx +++ b/src/test-apps/cjs-app/app/root.tsx @@ -88,4 +88,4 @@ export const action = async () => { ); } -export default withDevTools(App); \ No newline at end of file +export default withDevTools(App ); \ No newline at end of file diff --git a/src/test-apps/cjs-app/app/routes/_index.tsx b/src/test-apps/cjs-app/app/routes/_index.tsx index 0bf83a4..06425d6 100644 --- a/src/test-apps/cjs-app/app/routes/_index.tsx +++ b/src/test-apps/cjs-app/app/routes/_index.tsx @@ -47,14 +47,8 @@ export default function Index() { > FETCHER Action -

- -

- -

- - - + +