diff --git a/apps/reactotron-app/src/renderer/App.tsx b/apps/reactotron-app/src/renderer/App.tsx index b5778c4b1..ba763f579 100644 --- a/apps/reactotron-app/src/renderer/App.tsx +++ b/apps/reactotron-app/src/renderer/App.tsx @@ -15,6 +15,7 @@ import Overlay from "./pages/reactNative/Overlay" import Storybook from "./pages/reactNative/Storybook" import CustomCommands from "./pages/customCommands" import Help from "./pages/help" +import NetworkPage from "./pages/network" const AppContainer = styled.div` position: absolute; @@ -56,6 +57,8 @@ function App() { {/* Timeline */} } /> + {/* Network */} + } /> {/* State */} } /> diff --git a/apps/reactotron-app/src/renderer/ReactotronBrain.tsx b/apps/reactotron-app/src/renderer/ReactotronBrain.tsx index 170a73741..83437821c 100644 --- a/apps/reactotron-app/src/renderer/ReactotronBrain.tsx +++ b/apps/reactotron-app/src/renderer/ReactotronBrain.tsx @@ -6,6 +6,7 @@ import { CustomCommandsProvider, ReactNativeProvider, TimelineProvider, + NetworkProvider, StateProvider, } from "reactotron-core-ui" @@ -15,6 +16,7 @@ interface Props { commands: Command[] sendCommand: (type: string, payload: any, clientId?: string) => void clearCommands: () => void + clearNetworkCommands: () => void addCommandListener: (callback: (command: Command) => void) => void } @@ -23,6 +25,7 @@ const ReactotronBrain: FunctionComponent> = ({ commands, sendCommand, clearCommands, + clearNetworkCommands, addCommandListener, children, }) => { @@ -31,17 +34,20 @@ const ReactotronBrain: FunctionComponent> = ({ commands={commands} sendCommand={sendCommand} clearCommands={clearCommands} + clearNetworkCommands={clearNetworkCommands} addCommandListener={addCommandListener} > - - - - - {children} - - - - + + + + + + {children} + + + + + ) } diff --git a/apps/reactotron-app/src/renderer/components/SideBar/Sidebar.tsx b/apps/reactotron-app/src/renderer/components/SideBar/Sidebar.tsx index 2ff34b503..0e4d22925 100644 --- a/apps/reactotron-app/src/renderer/components/SideBar/Sidebar.tsx +++ b/apps/reactotron-app/src/renderer/components/SideBar/Sidebar.tsx @@ -7,6 +7,7 @@ import { MdWarning, MdOutlineMobileFriendly, MdMobiledataOff, + MdNetworkCheck, } from "react-icons/md" import { FaMagic } from "react-icons/fa" import styled from "styled-components" @@ -58,6 +59,7 @@ function SideBar({ isOpen, serverStatus }: { isOpen: boolean; serverStatus: Serv + = ({ children }) => { selectedConnection, selectConnection, clearSelectedConnectionCommands, + clearNetworkCommands, serverStarted, serverStopped, connectionEstablished, @@ -89,6 +90,7 @@ const Provider: React.FC<{ children: React.ReactNode }> = ({ children }) => { commands={(selectedConnection || { commands: [] }).commands} sendCommand={sendCommand} clearCommands={clearSelectedConnectionCommands} + clearNetworkCommands={clearNetworkCommands} addCommandListener={addCommandListener} > {children} diff --git a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.test.ts b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.test.ts index 195f0febc..82c7956a6 100644 --- a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.test.ts +++ b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.test.ts @@ -286,7 +286,7 @@ describe("contexts/Standalone/useStandalone", () => { expect(result.current.orphanedCommands[0]).toEqual({ connectionId: 1, payload: true }) }) - it("should clear commands from a connection", () => { + it("should clear commands from a connection but keeping the api ones", () => { const { result } = renderHook(() => useStandalone()) act(() => { @@ -299,15 +299,43 @@ describe("contexts/Standalone/useStandalone", () => { act(() => { result.current.commandReceived({ clientId: "1234", payload: true }) + result.current.commandReceived({ clientId: "1234", payload: true, type: "api.response" }) }) - expect(result.current.connections[0].commands.length).toEqual(1) - expect(result.current.connections[0].commands[0]).toEqual({ clientId: "1234", payload: true }) + expect(result.current.connections[0].commands.length).toEqual(2) + expect(result.current.connections[0].commands[0]).toEqual({ clientId: "1234", payload: true, type: "api.response"}) + expect(result.current.connections[0].commands[1]).toEqual({ clientId: "1234", payload: true }) act(() => { result.current.clearSelectedConnectionCommands() }) + expect(result.current.connections[0].commands.length).toEqual(1) + expect(result.current.connections[0].commands[0]).toEqual({ clientId: "1234", payload: true, type: "api.response"}) + }) + + it("should clear network commands from a connection", () => { + const { result } = renderHook(() => useStandalone()) + + act(() => { + result.current.connectionEstablished({ + clientId: "1234", + id: 0, + platform: "ios", + }) + }) + + act(() => { + result.current.commandReceived({ clientId: "1234", payload: true, type: "api.response" }) + }) + + expect(result.current.connections[0].commands.length).toEqual(1) + expect(result.current.connections[0].commands[0]).toEqual({ clientId: "1234", payload: true, type: "api.response" }) + + act(() => { + result.current.clearNetworkCommands() + }) + expect(result.current.connections[0].commands.length).toEqual(0) }) diff --git a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts index 96c6d5b2e..780d7d39f 100644 --- a/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts +++ b/apps/reactotron-app/src/renderer/contexts/Standalone/useStandalone.ts @@ -1,5 +1,6 @@ import { useCallback, useReducer } from "react" import { produce } from "immer" +import { CommandType } from "reactotron-core-contract" export enum ActionTypes { ServerStarted = "SERVER_STARTED", @@ -7,6 +8,7 @@ export enum ActionTypes { AddConnection = "ADD_CONNECTION", RemoveConnection = "REMOVE_CONNECTION", ClearConnectionCommands = "CLEAR_CONNECTION_COMMANDS", + ClearNetworkCommands = "CLEAR_NETWORK_COMMANDS", CommandReceived = "COMMAND_RECEIVED", ChangeSelectedClientId = "CHANGE_SELECTED_CLIENT_ID", AddCommandHandler = "ADD_COMMAND_HANDLER", @@ -52,6 +54,7 @@ type Action = | { type: ActionTypes.ChangeSelectedClientId; payload: string } | { type: ActionTypes.CommandReceived; payload: any } // TODO: Type this better! | { type: ActionTypes.ClearConnectionCommands } + | { type: ActionTypes.ClearNetworkCommands } | { type: ActionTypes.AddCommandHandler; payload: (command: any) => void } | { type: ActionTypes.PortUnavailable; payload: undefined } @@ -153,7 +156,25 @@ export function reducer(state: State, action: Action) { if (!selectedConnection) return - selectedConnection.commands = [] + // for now we are keeping the api responses until we separate them out + // into their own list + selectedConnection.commands = selectedConnection.commands.filter( + (c) => c.type === CommandType.ApiResponse + ) + }) + case ActionTypes.ClearNetworkCommands: + return produce(state, (draftState) => { + if (!draftState.selectedClientId) return + + const selectedConnection = draftState.connections.find( + (c) => c.clientId === draftState.selectedClientId + ) + + if (!selectedConnection) return + + selectedConnection.commands = selectedConnection.commands.filter( + (c) => c.type !== CommandType.ApiResponse + ) }) case ActionTypes.ChangeSelectedClientId: return produce(state, (draftState) => { @@ -218,6 +239,10 @@ function useStandalone() { dispatch({ type: ActionTypes.ClearConnectionCommands }) }, []) + const clearNetworkCommands = useCallback(() => { + dispatch({ type: ActionTypes.ClearNetworkCommands }) + }, []) + const selectConnection = useCallback((clientId: string) => { dispatch({ type: ActionTypes.ChangeSelectedClientId, payload: clientId }) }, []) @@ -240,6 +265,7 @@ function useStandalone() { connectionDisconnected, commandReceived, clearSelectedConnectionCommands, + clearNetworkCommands, addCommandListener, portUnavailable, } diff --git a/apps/reactotron-app/src/renderer/pages/network/index.tsx b/apps/reactotron-app/src/renderer/pages/network/index.tsx new file mode 100644 index 000000000..9fe70a657 --- /dev/null +++ b/apps/reactotron-app/src/renderer/pages/network/index.tsx @@ -0,0 +1,219 @@ +import React, { useContext, useMemo } from "react" +import { clipboard } from "electron" +import fs from "fs" +import { + Header, + filterCommands, + EmptyState, + ReactotronContext, + NetworkContext, + timelineCommandResolver, +} from "reactotron-core-ui" +import { MdSearch, MdDeleteSweep, MdSwapVert, MdReorder } from "react-icons/md" +import { FaTimes } from "react-icons/fa" +import styled from "styled-components" +import { CommandType } from "reactotron-core-contract" +const Container = styled.div` + display: flex; + flex-direction: column; + width: 100%; +` + +const NetworkPageContainer = styled.div` + height: 100%; + overflow-y: auto; + overflow-x: hidden; +` + +const SearchContainer = styled.div` + display: flex; + align-items: center; + padding-bottom: 10px; + padding-top: 4px; + padding-right: 10px; +` +const SearchLabel = styled.p` + padding: 0 10px; + font-size: 14px; + color: ${(props) => props.theme.foregroundDark}; +` +const SearchInput = styled.input` + border-radius: 4px; + padding: 10px; + flex: 1; + background-color: ${(props) => props.theme.backgroundSubtleDark}; + border: none; + color: ${(props) => props.theme.foregroundDark}; + font-size: 14px; +` +export const ButtonContainer = styled.div` + padding: 10px; + cursor: pointer; +` + +export const NetworkTable = styled.table` + width: 100%; + border-collapse: collapse; + border-spacing: 0; + border: 1px solid ${(props) => props.theme.chromeLine}; + border-radius: 4px; + margin-bottom: 10px; + color: ${(props) => props.theme.foregroundDark}; +` + +export const NetworkTableHeader = styled.thead` + background-color: ${(props) => props.theme.backgroundSubtleDark}; + color: ${(props) => props.theme.foregroundDark}; + font-size: 14px; + font-weight: bold; + text-align: left; +` +export const NetworkTableHeaderCell = styled.th` + padding: 0 10px; +` + +export const NetworkTableHeaderRow = styled.tr` + height: 30px; + "& th": { + padding: 0 10px; + } +` +export const NetworkTableBody = styled.tbody` + font-size: 14px; + color: ${(props) => props.theme.foregroundDark}; + font-weight: normal; + text-align: left; +` +export const NetworkTableRow = styled.tr` + height: 30px; +` + +export const NetworkTableCell = styled.td` + padding: 0 10px; +` + +export const NetworkContainer = styled.div` + height: 100%; + display: flex; + flex-direction: row; + width: 100%; +` +export const NetworkInspector = styled.div` + height: 100%; + overflow-y: auto; + overflow-x: hidden; + width: 400px; + resize: horizontal; + max-width: 600px; +` + +function NetworkPage() { + const { sendCommand,clearNetworkCommands, commands, openDispatchModal } = useContext(ReactotronContext) + const { + isSearchOpen, + toggleSearch, + closeSearch, + setSearch, + search, + isReversed, + toggleReverse, + } = useContext(NetworkContext) + + let filteredCommands = useMemo(() => { + const cmds = filterCommands(commands, search, []).filter((a) => + a.type === CommandType.ApiResponse + ) + return cmds; + }, [commands, search]) + + if (isReversed) { + filteredCommands = filteredCommands.reverse() + } + + return ( + +
{ + toggleSearch() + }, + }, + { + tip: "Reverse Order", + icon: MdSwapVert, + onClick: () => { + toggleReverse() + }, + }, + { + tip: "Clear", + icon: MdDeleteSweep, + onClick: () => { + clearNetworkCommands() + }, + }, + ]} + > + {isSearchOpen && ( + + Search + setSearch(e.target.value)} /> + { + if (search === "") { + closeSearch() + } else { + setSearch("") + } + }} + > + + + + )} +
+ + {filteredCommands.length === 0 ? ( + + Once your app connects and starts sending events, they will appear here. + + ) : ( + + filteredCommands.map((command) => { + const CommandComponent = timelineCommandResolver(command.type) + + if (CommandComponent) { + return ( + { + return new Promise((resolve, reject) => { + fs.readFile(path, "utf-8", (err, data) => { + if (err || !data) reject(new Error("Something failed")) + else resolve(data) + }) + }) + }} + sendCommand={sendCommand} + openDispatchDialog={openDispatchModal} + /> + ) + } + + return null + }) + + )} + +
+ ) +} + +export default NetworkPage diff --git a/lib/reactotron-core-ui/src/contexts/CustomCommands/useCustomCommands.test.tsx b/lib/reactotron-core-ui/src/contexts/CustomCommands/useCustomCommands.test.tsx index 3e9d16f06..3ff0ddca8 100644 --- a/lib/reactotron-core-ui/src/contexts/CustomCommands/useCustomCommands.test.tsx +++ b/lib/reactotron-core-ui/src/contexts/CustomCommands/useCustomCommands.test.tsx @@ -12,6 +12,7 @@ function buildContextValues({ addCommandListener = null } = {}) { commands: [], sendCommand: jest.fn(), clearCommands: jest.fn(), + clearNetworkCommands: jest.fn(), addCommandListener: addCommandListener || jest.fn(), isDispatchModalOpen: false, dispatchModalInitialAction: "", diff --git a/lib/reactotron-core-ui/src/contexts/Network/index.tsx b/lib/reactotron-core-ui/src/contexts/Network/index.tsx new file mode 100644 index 000000000..575db6d75 --- /dev/null +++ b/lib/reactotron-core-ui/src/contexts/Network/index.tsx @@ -0,0 +1,58 @@ +import React, { FunctionComponent } from "react" + +import useNetwork from "./useNetwork" + +interface Context { + isSearchOpen: boolean + toggleSearch: () => void + openSearch: () => void + closeSearch: () => void + search: string + setSearch: (search: string) => void + isReversed: boolean + toggleReverse: () => void +} + +const NetworkContext = React.createContext({ + isSearchOpen: false, + toggleSearch: null, + openSearch: null, + closeSearch: null, + search: "", + setSearch: null, + isReversed: false, + toggleReverse: null, +}) + +const Provider: FunctionComponent = ({ children }) => { + const { + isSearchOpen, + toggleSearch, + openSearch, + closeSearch, + search, + setSearch, + isReversed, + toggleReverse, + } = useNetwork() + + return ( + + {children} + + ) +} + +export default NetworkContext +export const NetworkProvider = Provider diff --git a/lib/reactotron-core-ui/src/contexts/Network/useNetwork.test.ts b/lib/reactotron-core-ui/src/contexts/Network/useNetwork.test.ts new file mode 100644 index 000000000..8dd87cb09 --- /dev/null +++ b/lib/reactotron-core-ui/src/contexts/Network/useNetwork.test.ts @@ -0,0 +1,84 @@ +import { act, renderHook } from "@testing-library/react" + +import useNetwork, { NetworkStorageKey } from "./useNetwork" + +describe("contexts/Network/useNetwork", () => { + beforeEach(() => { + localStorage.removeItem(NetworkStorageKey.ReversedOrder) + localStorage.removeItem(NetworkStorageKey.HiddenCommands) + }) + + describe("Initial Settings", () => { + it("should default to regular order", () => { + const { result } = renderHook(() => useNetwork()) + + expect(result.current.isReversed).toBeFalsy() + }) + + it("should load if user had the timeline reversed", () => { + localStorage.setItem(NetworkStorageKey.ReversedOrder, "reversed") + + const { result } = renderHook(() => useNetwork()) + + expect(result.current.isReversed).toBeTruthy() + }) + + it("should load if user had the timeline regular order", () => { + localStorage.setItem(NetworkStorageKey.ReversedOrder, "regular") + + const { result } = renderHook(() => useNetwork()) + + expect(result.current.isReversed).toBeFalsy() + }) + }) + + describe("actions", () => { + it("should toggle search", () => { + const { result } = renderHook(() => useNetwork()) + + expect(result.current.isSearchOpen).toBeFalsy() + act(() => { + result.current.toggleSearch() + }) + expect(result.current.isSearchOpen).toBeTruthy() + act(() => { + result.current.toggleSearch() + }) + expect(result.current.isSearchOpen).toBeFalsy() + }) + + it("should set the search string", () => { + const { result } = renderHook(() => useNetwork()) + + expect(result.current.search).toEqual("") + act(() => { + result.current.setSearch("H") + }) + expect(result.current.search).toEqual("H") + act(() => { + result.current.setSearch("L") + }) + expect(result.current.search).toEqual("L") + act(() => { + result.current.setSearch("") + }) + expect(result.current.search).toEqual("") + }) + + it("should toggle reverse", () => { + const { result } = renderHook(() => useNetwork()) + + expect(result.current.isReversed).toBeFalsy() + act(() => { + result.current.toggleReverse() + }) + expect(localStorage.getItem(NetworkStorageKey.ReversedOrder)).toEqual("reversed") + expect(result.current.isReversed).toBeTruthy() + act(() => { + result.current.toggleReverse() + }) + expect(localStorage.getItem(NetworkStorageKey.ReversedOrder)).toEqual("regular") + expect(result.current.isReversed).toBeFalsy() + }) + }) +}) diff --git a/lib/reactotron-core-ui/src/contexts/Network/useNetwork.ts b/lib/reactotron-core-ui/src/contexts/Network/useNetwork.ts new file mode 100644 index 000000000..e96090ddb --- /dev/null +++ b/lib/reactotron-core-ui/src/contexts/Network/useNetwork.ts @@ -0,0 +1,121 @@ +import { useReducer, useEffect } from "react" + +import type { CommandTypeKey } from "reactotron-core-contract" + +export enum NetworkStorageKey { + ReversedOrder = "ReactotronNetworkReversedOrder", + HiddenCommands = "ReactotronNetworkHiddenCommands", +} + +interface NetworkState { + isSearchOpen: boolean + search: string + isFilterOpen: boolean + isReversed: boolean + hiddenCommands: CommandTypeKey[] +} + +enum NetworkActionType { + SearchOpen = "SEARCH_OPEN", + SearchClose = "SEARCH_CLOSE", + SearchSet = "SEARCH_SET", + OrderReverse = "ORDER_REVERSE", + OrderRegular = "ORDER_REGULAR", +} + +type Action = + | { + type: + | NetworkActionType.SearchOpen + | NetworkActionType.SearchClose + | NetworkActionType.OrderReverse + | NetworkActionType.OrderRegular + } + | { + type: NetworkActionType.SearchSet + payload: string + } + +function networkReducer(state: NetworkState, action: Action) { + switch (action.type) { + case NetworkActionType.SearchOpen: + return { ...state, isSearchOpen: true } + case NetworkActionType.SearchClose: + return { ...state, isSearchOpen: false } + case NetworkActionType.SearchSet: + return { ...state, search: action.payload } + case NetworkActionType.OrderReverse: + return { ...state, isReversed: true } + case NetworkActionType.OrderRegular: + return { ...state, isReversed: false } + default: + return state + } +} + +function useNetwork() { + const [state, dispatch] = useReducer(networkReducer, { + isSearchOpen: false, + search: "", + isFilterOpen: false, + isReversed: false, + hiddenCommands: [], + }) + + // Load some values + useEffect(() => { + const isReversed = localStorage.getItem(NetworkStorageKey.ReversedOrder) === "reversed" + dispatch({ + type: isReversed ? NetworkActionType.OrderReverse : NetworkActionType.OrderRegular, + }) + }, []) + + // Setup event handlers + const toggleSearch = () => { + dispatch({ + type: state.isSearchOpen ? NetworkActionType.SearchClose : NetworkActionType.SearchOpen, + }) + } + + const openSearch = () => { + dispatch({ + type: NetworkActionType.SearchOpen, + }) + } + + const closeSearch = () => { + dispatch({ + type: NetworkActionType.SearchClose, + }) + } + + const setSearch = (search: string) => { + dispatch({ + type: NetworkActionType.SearchSet, + payload: search, + }) + } + + const toggleReverse = () => { + const isReversed = !state.isReversed + + localStorage.setItem(NetworkStorageKey.ReversedOrder, isReversed ? "reversed" : "regular") + + dispatch({ + type: isReversed ? NetworkActionType.OrderReverse : NetworkActionType.OrderRegular, + }) + } + + return { + isSearchOpen: state.isSearchOpen, + toggleSearch, + openSearch, + closeSearch, + search: state.search, + setSearch, + isReversed: state.isReversed, + toggleReverse, + } +} + +export default useNetwork diff --git a/lib/reactotron-core-ui/src/contexts/ReactNative/useStorybook.test.tsx b/lib/reactotron-core-ui/src/contexts/ReactNative/useStorybook.test.tsx index 674d6c9d2..64b8d97ff 100644 --- a/lib/reactotron-core-ui/src/contexts/ReactNative/useStorybook.test.tsx +++ b/lib/reactotron-core-ui/src/contexts/ReactNative/useStorybook.test.tsx @@ -12,6 +12,7 @@ function buildContextValues({ addCommandListener = null } = {}) { commands: [], sendCommand: jest.fn(), clearCommands: jest.fn(), + clearNetworkCommands: jest.fn(), addCommandListener: addCommandListener || jest.fn(), isDispatchModalOpen: false, dispatchModalInitialAction: "", diff --git a/lib/reactotron-core-ui/src/contexts/Reactotron/index.tsx b/lib/reactotron-core-ui/src/contexts/Reactotron/index.tsx index b13291ba7..3baf8c5c2 100644 --- a/lib/reactotron-core-ui/src/contexts/Reactotron/index.tsx +++ b/lib/reactotron-core-ui/src/contexts/Reactotron/index.tsx @@ -8,6 +8,7 @@ interface Props { commands: Command[] sendCommand: (type: string, payload: any, clientId?: string) => void clearCommands: () => void + clearNetworkCommands: () => void addCommandListener: (callback: (command: Command) => void) => void } @@ -31,6 +32,7 @@ const ReactotronContext = React.createContext({ commands: [], sendCommand: null, clearCommands: null, + clearNetworkCommands: null, addCommandListener: null, isDispatchModalOpen: false, dispatchModalInitialAction: "", @@ -45,6 +47,7 @@ const Provider: FunctionComponent> = ({ commands, sendCommand, clearCommands, + clearNetworkCommands, addCommandListener, children, }) => { @@ -64,6 +67,7 @@ const Provider: FunctionComponent> = ({ commands, sendCommand, clearCommands, + clearNetworkCommands, addCommandListener, isDispatchModalOpen, dispatchModalInitialAction, diff --git a/lib/reactotron-core-ui/src/contexts/State/useSnapshots.test.tsx b/lib/reactotron-core-ui/src/contexts/State/useSnapshots.test.tsx index ae06d5e4c..141b4e9af 100644 --- a/lib/reactotron-core-ui/src/contexts/State/useSnapshots.test.tsx +++ b/lib/reactotron-core-ui/src/contexts/State/useSnapshots.test.tsx @@ -12,6 +12,7 @@ function buildContextValues({ addCommandListener = null } = {}) { commands: [], sendCommand: jest.fn(), clearCommands: jest.fn(), + clearNetworkCommands: jest.fn(), addCommandListener: addCommandListener || jest.fn(), isDispatchModalOpen: false, dispatchModalInitialAction: "", diff --git a/lib/reactotron-core-ui/src/contexts/State/useSubscriptions.test.tsx b/lib/reactotron-core-ui/src/contexts/State/useSubscriptions.test.tsx index ca57c6c5f..4ed9ad29b 100644 --- a/lib/reactotron-core-ui/src/contexts/State/useSubscriptions.test.tsx +++ b/lib/reactotron-core-ui/src/contexts/State/useSubscriptions.test.tsx @@ -11,6 +11,7 @@ function buildContextValues({ addCommandListener = null } = {}) { commands: [], sendCommand: jest.fn(), clearCommands: jest.fn(), + clearNetworkCommands: jest.fn(), addCommandListener: addCommandListener || jest.fn(), isDispatchModalOpen: false, dispatchModalInitialAction: "", diff --git a/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.test.ts b/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.test.ts index a64696f61..86f6c6784 100644 --- a/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.test.ts +++ b/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.test.ts @@ -36,7 +36,7 @@ describe("contexts/Timline/useTimeline", () => { it("should default to no hidden commands", () => { const { result } = renderHook(() => useTimline()) - expect(result.current.hiddenCommands).toEqual([]) + expect(result.current.hiddenCommands).toEqual([CommandType.ApiResponse]) }) it("should have saved hidden commands", () => { @@ -123,7 +123,7 @@ describe("contexts/Timline/useTimeline", () => { it("should set hidden commands", () => { const { result } = renderHook(() => useTimline()) - expect(result.current.hiddenCommands).toEqual([]) + expect(result.current.hiddenCommands).toEqual([CommandType.ApiResponse]) act(() => { result.current.setHiddenCommands([CommandType.ClientIntro]) }) diff --git a/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.ts b/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.ts index 87a75ec19..f0d576bf5 100644 --- a/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.ts +++ b/lib/reactotron-core-ui/src/contexts/Timeline/useTimeline.ts @@ -1,6 +1,6 @@ import { useReducer, useEffect } from "react" -import type { CommandTypeKey } from "reactotron-core-contract" +import { CommandType, type CommandTypeKey } from "reactotron-core-contract" export enum StorageKey { ReversedOrder = "ReactotronTimelineReversedOrder", @@ -80,7 +80,7 @@ function useTimeline() { // Load some values useEffect(() => { const isReversed = localStorage.getItem(StorageKey.ReversedOrder) === "reversed" - const hiddenCommands = JSON.parse(localStorage.getItem(StorageKey.HiddenCommands) || "[]") + const hiddenCommands = JSON.parse(localStorage.getItem(StorageKey.HiddenCommands) || JSON.stringify([CommandType.ApiResponse])) dispatch({ type: isReversed ? TimelineActionType.OrderReverse : TimelineActionType.OrderRegular, diff --git a/lib/reactotron-core-ui/src/index.ts b/lib/reactotron-core-ui/src/index.ts index c456c1646..78d3a26ff 100644 --- a/lib/reactotron-core-ui/src/index.ts +++ b/lib/reactotron-core-ui/src/index.ts @@ -20,6 +20,7 @@ import CustomCommandsContext, { CustomCommandsProvider } from "./contexts/Custom import ReactNativeContext, { ReactNativeProvider } from "./contexts/ReactNative" import StateContext, { StateProvider } from "./contexts/State" import TimelineContext, { TimelineProvider } from "./contexts/Timeline" +import NetworkContext, { NetworkProvider } from "./contexts/Network" // Modals import DispatchActionModal from "./modals/DispatchActionModal" @@ -65,6 +66,8 @@ export { StateProvider, TimelineContext, TimelineProvider, + NetworkContext, + NetworkProvider, } export type { CustomCommand } from "./contexts/CustomCommands/useCustomCommands" diff --git a/lib/reactotron-core-ui/src/modals/TimelineFilterModal/index.tsx b/lib/reactotron-core-ui/src/modals/TimelineFilterModal/index.tsx index 8e5074af5..a94841f95 100644 --- a/lib/reactotron-core-ui/src/modals/TimelineFilterModal/index.tsx +++ b/lib/reactotron-core-ui/src/modals/TimelineFilterModal/index.tsx @@ -20,7 +20,6 @@ const GROUPS = [ items: [ { value: CommandType.ClientIntro, text: "Connection" }, { value: CommandType.Benchmark, text: "Benchmark" }, - { value: CommandType.ApiResponse, text: "API" }, ], }, {