From 99f38c4e04263ab4f61e1bbf5192c9b1848b106f Mon Sep 17 00:00:00 2001 From: Alem Tuzlak Date: Sat, 2 Dec 2023 12:13:04 +0100 Subject: [PATCH] 77 active page tab stuck once popping rdt out into new window (#80) * #77 - Detached mode location tracking fix * action color change --- package.json | 2 +- src/RemixDevTools/RemixDevTools.tsx | 3 +- src/RemixDevTools/context/RDTContext.tsx | 3 +- src/RemixDevTools/context/rdtReducer.ts | 4 +- .../hooks/detached/useListenToRouteChange.ts | 13 +- src/RemixDevTools/utils/common.ts | 5 + src/dev-server/logger.ts | 2 +- src/dev-server/utils.ts | 13 +- .../remix-vite/app/components/Button.tsx | 15 ++ src/test-apps/remix-vite/app/root.tsx | 2 +- .../remix-vite/app/routes/_index.tsx | 57 +++++++- .../remix-vite/app/routes/_layout.added.tsx | 5 + .../app/routes/_layout.final_test.tsx | 51 +++++++ .../app/routes/_layout.new_route.tsx | 5 + .../app/routes/_layout.one_more_time.tsx | 51 +++++++ ...out.tests.$id.edit.new.$test.$wildcard.tsx | 133 ++++++++++++++++++ .../_layout.tests.$id.edit.new.$test.tsx | 45 ++++++ .../app/routes/_layout.tests.$id.edit.new.tsx | 94 +++++++++++++ .../app/routes/_layout.tests.$id.edit.tsx | 42 ++++++ .../app/routes/_layout.tests.$id.tsx | 48 +++++++ .../remix-vite/app/routes/_layout.tests.tsx | 42 ++++++ .../remix-vite/app/routes/_layout.tsx | 14 ++ .../remix-vite/app/routes/_layout/test.tsx | 13 ++ src/test-apps/remix-vite/app/routes/about.tsx | 17 --- .../remix-vite/app/routes/correct.tsx | 51 +++++++ .../remix-vite/app/routes/dashboard.tsx | 19 +++ .../remix-vite/app/routes/embedded.tsx | 89 ++++++++++++ src/test-apps/remix-vite/app/routes/login.tsx | 15 ++ .../remix-vite/app/routes/logout.tsx | 5 + .../remix-vite/app/routes/other._index.tsx | 3 + .../remix-vite/app/routes/other.page.tsx | 3 + src/test-apps/remix-vite/app/routes/other.tsx | 8 ++ 32 files changed, 834 insertions(+), 38 deletions(-) create mode 100644 src/test-apps/remix-vite/app/components/Button.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.added.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.final_test.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.new_route.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.one_more_time.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.$id.edit.new.$test.$wildcard.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.$id.edit.new.$test.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.$id.edit.new.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.$id.edit.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.$id.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tests.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout.tsx create mode 100644 src/test-apps/remix-vite/app/routes/_layout/test.tsx delete mode 100644 src/test-apps/remix-vite/app/routes/about.tsx create mode 100644 src/test-apps/remix-vite/app/routes/correct.tsx create mode 100644 src/test-apps/remix-vite/app/routes/dashboard.tsx create mode 100644 src/test-apps/remix-vite/app/routes/embedded.tsx create mode 100644 src/test-apps/remix-vite/app/routes/login.tsx create mode 100644 src/test-apps/remix-vite/app/routes/logout.tsx create mode 100644 src/test-apps/remix-vite/app/routes/other._index.tsx create mode 100644 src/test-apps/remix-vite/app/routes/other.page.tsx create mode 100644 src/test-apps/remix-vite/app/routes/other.tsx diff --git a/package.json b/package.json index 811f983..d6feea3 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.5.0", + "version": "3.5.1", "license": "MIT", "keywords": [ "remix", diff --git a/src/RemixDevTools/RemixDevTools.tsx b/src/RemixDevTools/RemixDevTools.tsx index f296253..58b75b1 100644 --- a/src/RemixDevTools/RemixDevTools.tsx +++ b/src/RemixDevTools/RemixDevTools.tsx @@ -25,6 +25,7 @@ import { useOpenElementSource } from "./hooks/useOpenElementSource.js"; import { RdtPlugin } from "../client.js"; import { useAttachBodyListener } from "./hooks/useAttachListener.js"; import { useDebounce } from "./hooks/useDebounce.js"; +import { useListenToRouteChange } from "./hooks/detached/useListenToRouteChange.js"; const DevTools = ({ plugins: pluginArray }: RemixDevToolsProps) => { useTimelineHandler(); @@ -34,7 +35,7 @@ const DevTools = ({ plugins: pluginArray }: RemixDevToolsProps) => { useSyncStateWhenDetached(); useDevServerConnection(); useOpenElementSource(); - + useListenToRouteChange(); const url = useLocation().search; const { detachedWindowOwner, isDetached, setDetachedWindowOwner } = useDetachedWindowControls(); const { settings } = useSettingsContext(); diff --git a/src/RemixDevTools/context/RDTContext.tsx b/src/RemixDevTools/context/RDTContext.tsx index 9af2a15..dcc40d0 100644 --- a/src/RemixDevTools/context/RDTContext.tsx +++ b/src/RemixDevTools/context/RDTContext.tsx @@ -2,7 +2,6 @@ import type { Dispatch } from "react"; import React, { useMemo, createContext, useReducer, useEffect } from "react"; import { RemixDevToolsActions, RemixDevToolsState, rdtReducer, initialState } from "./rdtReducer.js"; import { useRemoveBody } from "../hooks/detached/useRemoveBody.js"; -import { useListenToRouteChange } from "../hooks/detached/useListenToRouteChange.js"; import { setSessionItem, setStorageItem, @@ -84,7 +83,7 @@ export const getExistingStateFromStorage = () => { export const RDTContextProvider = ({ children }: ContextProps) => { const [state, dispatch] = useReducer(rdtReducer, getExistingStateFromStorage()); const value = useMemo(() => ({ state, dispatch }), [state, dispatch]); - useListenToRouteChange(); + useRemoveBody(state); useEffect(() => { diff --git a/src/RemixDevTools/context/rdtReducer.ts b/src/RemixDevTools/context/rdtReducer.ts index 5240e7b..a3c2ed8 100644 --- a/src/RemixDevTools/context/rdtReducer.ts +++ b/src/RemixDevTools/context/rdtReducer.ts @@ -2,7 +2,7 @@ import { TimelineEvent } from "./timeline/types.js"; import type { Tabs } from "../tabs/index.js"; import { Terminal } from "./terminal/types.js"; import { ActionEvent, LoaderEvent } from "../../dev-server/event-queue.js"; -import { cutArrayToLastN } from "../utils/common.js"; +import { cutArrayToFirstN } from "../utils/common.js"; export const defaultServerRouteState: ServerRouteInfo = { highestExecutionTime: 0, @@ -268,7 +268,7 @@ export const rdtReducer = ( case "SET_TIMELINE_EVENT": return { ...state, - timeline: cutArrayToLastN([payload, ...state.timeline], 30), + timeline: cutArrayToFirstN([payload, ...state.timeline], 30), }; case "SET_WHOLE_STATE": { diff --git a/src/RemixDevTools/hooks/detached/useListenToRouteChange.ts b/src/RemixDevTools/hooks/detached/useListenToRouteChange.ts index c088e6e..d6bee7e 100644 --- a/src/RemixDevTools/hooks/detached/useListenToRouteChange.ts +++ b/src/RemixDevTools/hooks/detached/useListenToRouteChange.ts @@ -1,8 +1,9 @@ import { useLocation, useNavigate, useNavigation } from "@remix-run/react"; import { useEffect, useRef } from "react"; -import { useAttachListener } from '../useAttachListener.js'; -import { getStorageItem, setStorageItem } from '../../utils/storage.js'; -import { useDetachedWindowControls } from '../../context/useRDTContext.js'; +import { useAttachListener } from "../useAttachListener.js"; +import { getStorageItem, setStorageItem } from "../../utils/storage.js"; +import { useDetachedWindowControls } from "../../context/useRDTContext.js"; +import { detachedModeSetup } from "../../context/RDTContext.js"; export const LOCAL_STORAGE_ROUTE_KEY = "rdt_route"; @@ -22,8 +23,12 @@ export const useListenToRouteChange = () => { // Used by the owner window only useEffect(() => { + const { detachedWindowOwner } = detachedModeSetup(); + if (!detachedWindowOwner) { + return; + } // If the route changes and this is the original window store the event into local storage - if (route !== locationRoute && detachedWindowOwner) { + if (route !== locationRoute) { setRouteInLocalStorage(locationRoute); } }, [locationRoute, detachedWindowOwner, route]); diff --git a/src/RemixDevTools/utils/common.ts b/src/RemixDevTools/utils/common.ts index 9958e68..1212bfe 100644 --- a/src/RemixDevTools/utils/common.ts +++ b/src/RemixDevTools/utils/common.ts @@ -2,3 +2,8 @@ export const cutArrayToLastN = (arr: T[], n: number) => { if (arr.length < n) return arr; return arr.slice(arr.length - n); }; + +export const cutArrayToFirstN = (arr: T[], n: number) => { + if (arr.length < n) return arr; + return arr.slice(0, n); +}; diff --git a/src/dev-server/logger.ts b/src/dev-server/logger.ts index 756c5da..296a583 100644 --- a/src/dev-server/logger.ts +++ b/src/dev-server/logger.ts @@ -37,7 +37,7 @@ export const actionLog = (message: string) => { if (config.logs?.actions === false) { return; } - log(`${chalk.red.bold("ACTION")} ${message}`); + log(`${chalk.yellowBright.bold("ACTION")} ${message}`); }; export const successLog = (message: string) => { diff --git a/src/dev-server/utils.ts b/src/dev-server/utils.ts index 9f5aca4..d1693c1 100644 --- a/src/dev-server/utils.ts +++ b/src/dev-server/utils.ts @@ -135,16 +135,16 @@ const logTrigger = (id: string, type: "action" | "loader", end: number) => { } }; -const extractHeadersFromResponseOrRequest = (response: Response | Request): Record => { +const extractHeadersFromResponseOrRequest = (response: Response | Request) => { const headers = new Headers(response.headers); return Object.fromEntries(headers.entries()); }; const extractDataFromResponseOrRequest = async (response: Response | Request): Promise => { - const extractable = new Response(response.body, response) - const headers = new Headers(extractable.headers); - const contentType = headers.get("Content-Type"); try { + const extractable = new Response(response.body, response); + const headers = new Headers(extractable.headers); + const contentType = headers.get("Content-Type"); if (contentType?.includes("application/json")) { return extractable.json(); } @@ -170,6 +170,7 @@ const storeAndEmitActionOrLoaderInfo = async ( ) => { const isResponse = response instanceof Response; const responseHeaders = isResponse ? extractHeadersFromResponseOrRequest(response) : null; + const requestHeaders = extractHeadersFromResponseOrRequest(args.request); // create the event const event = { type, @@ -177,9 +178,9 @@ const storeAndEmitActionOrLoaderInfo = async ( id: route.id, executionTime: end, timestamp: new Date().getTime(), - responseHeaders, - requestHeaders: extractHeadersFromResponseOrRequest(args.request), requestData: await extractDataFromResponseOrRequest(args.request), + requestHeaders, + responseHeaders, }, }; const port = diff --git a/src/test-apps/remix-vite/app/components/Button.tsx b/src/test-apps/remix-vite/app/components/Button.tsx new file mode 100644 index 0000000..ce77853 --- /dev/null +++ b/src/test-apps/remix-vite/app/components/Button.tsx @@ -0,0 +1,15 @@ +import { ReactNode } from "react"; + +interface ButtonProps extends React.ButtonHTMLAttributes { + children: ReactNode +} + +const Button = ({ children, ...props }: ButtonProps) => { + return ( + + ); +} + +export { Button }; \ No newline at end of file diff --git a/src/test-apps/remix-vite/app/root.tsx b/src/test-apps/remix-vite/app/root.tsx index e58b922..5d8005f 100644 --- a/src/test-apps/remix-vite/app/root.tsx +++ b/src/test-apps/remix-vite/app/root.tsx @@ -31,7 +31,7 @@ export default function App() {
- + diff --git a/src/test-apps/remix-vite/app/routes/_index.tsx b/src/test-apps/remix-vite/app/routes/_index.tsx index 0b9b1ca..d8f39ac 100644 --- a/src/test-apps/remix-vite/app/routes/_index.tsx +++ b/src/test-apps/remix-vite/app/routes/_index.tsx @@ -1,4 +1,8 @@ +import type { ActionFunctionArgs } from "@remix-run/node"; +import { json, redirect, type LoaderFunctionArgs, defer } from "@remix-run/node"; import type { MetaFunction } from "@remix-run/node"; +import { Link, useFetcher, useSubmit } from "@remix-run/react"; +import { Button } from "../components/Button"; export const meta: MetaFunction = () => { return [ @@ -6,13 +10,60 @@ export const meta: MetaFunction = () => { { name: "description", content: "Welcome to Remix!" }, ]; }; - -export default function Index() { + +export const loader = async ({ request }: LoaderFunctionArgs) => { + + const test = new Promise((resolve) => { + setTimeout(() => { + resolve("test"); + }, 1000); + }) + return defer({ message: "Hello World!", test }); +}; + +export const action = async ({ request }: ActionFunctionArgs) => { + return redirect("/login"); +}; + +export default function Index() { + const lFetcher = useFetcher(); + const pFetcher = useFetcher(); + const submit = useSubmit(); + const data = new FormData(); + data.append("test", "test"); return (

Welcome to Remix

+ + + + + + + + + + Login