mirror of
https://github.com/All-Hands-AI/OpenHands.git
synced 2026-01-08 22:38:05 -05:00
refactor(frontend): Simplify useConversation hook by removing context dependency (#8659)
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
@@ -4,7 +4,6 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ActionSuggestions } from "#/components/features/chat/action-suggestions";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { MOCK_DEFAULT_USER_SETTINGS } from "#/mocks/handlers";
|
||||
import { ConversationProvider } from "#/context/conversation-context";
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock("posthog-js", () => ({
|
||||
@@ -48,11 +47,9 @@ vi.mock("react-router", () => ({
|
||||
const renderActionSuggestions = () =>
|
||||
render(<ActionSuggestions onSuggestionsClick={() => {}} />, {
|
||||
wrapper: ({ children }) => (
|
||||
<ConversationProvider>
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
</ConversationProvider>
|
||||
<QueryClientProvider client={new QueryClient()}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useSelector, useDispatch } from "react-redux";
|
||||
import { RootState } from "#/store";
|
||||
import { BrowserSnapshot } from "./browser-snapshot";
|
||||
import { EmptyBrowserMessage } from "./empty-browser-message";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import {
|
||||
initialState as browserInitialState,
|
||||
setUrl,
|
||||
@@ -14,7 +14,7 @@ export function BrowserPanel() {
|
||||
const { url, screenshotSrc } = useSelector(
|
||||
(state: RootState) => state.browser,
|
||||
);
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { SuggestionItem } from "#/components/features/suggestions/suggestion-item";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { useUserProviders } from "#/hooks/use-user-providers";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { useUserConversation } from "#/hooks/query/use-user-conversation";
|
||||
|
||||
interface ActionSuggestionsProps {
|
||||
@@ -16,7 +16,7 @@ export function ActionSuggestions({
|
||||
}: ActionSuggestionsProps) {
|
||||
const { t } = useTranslation();
|
||||
const { providers } = useUserProviders();
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
const { data: conversation } = useUserConversation(conversationId);
|
||||
|
||||
const [hasPullRequest, setHasPullRequest] = React.useState(false);
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
interface ConversationContextType {
|
||||
conversationId: string;
|
||||
}
|
||||
|
||||
const ConversationContext = React.createContext<ConversationContextType | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
export function ConversationProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { conversationId } = useParams<{ conversationId: string }>();
|
||||
|
||||
if (!conversationId) {
|
||||
throw new Error(
|
||||
"ConversationProvider must be used within a route that has a conversationId parameter",
|
||||
);
|
||||
}
|
||||
|
||||
const value = useMemo(() => ({ conversationId }), [conversationId]);
|
||||
|
||||
return (
|
||||
<ConversationContext.Provider value={value}>
|
||||
{children}
|
||||
</ConversationContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useConversation() {
|
||||
const context = React.useContext(ConversationContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useConversation must be used within a ConversationProvider",
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { Feedback } from "#/api/open-hands.types";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { displayErrorToast } from "#/utils/custom-toast-handlers";
|
||||
|
||||
type SubmitFeedbackArgs = {
|
||||
@@ -9,7 +9,7 @@ type SubmitFeedbackArgs = {
|
||||
};
|
||||
|
||||
export const useSubmitFeedback = () => {
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
return useMutation({
|
||||
mutationFn: ({ feedback }: SubmitFeedbackArgs) =>
|
||||
OpenHands.submitFeedback(conversationId, feedback),
|
||||
|
||||
@@ -5,13 +5,13 @@ import { useSelector } from "react-redux";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { RUNTIME_INACTIVE_STATES } from "#/types/agent-state";
|
||||
import { RootState } from "#/store";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
|
||||
export const useActiveHost = () => {
|
||||
const { curAgentState } = useSelector((state: RootState) => state.agent);
|
||||
const [activeHost, setActiveHost] = React.useState<string | null>(null);
|
||||
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
|
||||
const { data } = useQuery({
|
||||
queryKey: [conversationId, "hosts"],
|
||||
|
||||
@@ -4,12 +4,12 @@ import {
|
||||
useWsClient,
|
||||
WsClientProviderStatus,
|
||||
} from "#/context/ws-client-provider";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
|
||||
export const useConversationConfig = () => {
|
||||
const { status } = useWsClient();
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ["conversation_config", conversationId],
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { GitChangeStatus } from "#/api/open-hands.types";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
|
||||
type UseGetDiffConfig = {
|
||||
filePath: string;
|
||||
@@ -10,7 +10,7 @@ type UseGetDiffConfig = {
|
||||
};
|
||||
|
||||
export const useGitDiff = (config: UseGetDiffConfig) => {
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ["file_diff", conversationId, config.filePath, config.type],
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { GitChange } from "#/api/open-hands.types";
|
||||
import { RootState } from "#/store";
|
||||
import { RUNTIME_INACTIVE_STATES } from "#/types/agent-state";
|
||||
|
||||
export const useGetGitChanges = () => {
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
const [orderedChanges, setOrderedChanges] = React.useState<GitChange[]>([]);
|
||||
const previousDataRef = React.useRef<GitChange[]>(null);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSelector } from "react-redux";
|
||||
import OpenHands from "#/api/open-hands";
|
||||
import { useConversation } from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { RootState } from "#/store";
|
||||
import { RUNTIME_INACTIVE_STATES } from "#/types/agent-state";
|
||||
@@ -16,7 +16,7 @@ interface VSCodeUrlResult {
|
||||
|
||||
export const useVSCodeUrl = () => {
|
||||
const { t } = useTranslation();
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
const { curAgentState } = useSelector((state: RootState) => state.agent);
|
||||
const isRuntimeInactive = RUNTIME_INACTIVE_STATES.includes(curAgentState);
|
||||
|
||||
|
||||
13
frontend/src/hooks/use-conversation-id.ts
Normal file
13
frontend/src/hooks/use-conversation-id.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useParams } from "react-router";
|
||||
|
||||
export function useConversationId() {
|
||||
const { conversationId } = useParams<{ conversationId: string }>();
|
||||
|
||||
if (!conversationId) {
|
||||
throw new Error(
|
||||
"useConversationId must be used within a route that has a conversationId parameter",
|
||||
);
|
||||
}
|
||||
|
||||
return { conversationId };
|
||||
}
|
||||
@@ -8,10 +8,7 @@ import { DiGit } from "react-icons/di";
|
||||
import { VscCode } from "react-icons/vsc";
|
||||
import { I18nKey } from "#/i18n/declaration";
|
||||
import { RUNTIME_INACTIVE_STATES } from "#/types/agent-state";
|
||||
import {
|
||||
ConversationProvider,
|
||||
useConversation,
|
||||
} from "#/context/conversation-context";
|
||||
import { useConversationId } from "#/hooks/use-conversation-id";
|
||||
import { Controls } from "#/components/features/controls/controls";
|
||||
import { clearTerminal } from "#/state/command-slice";
|
||||
import { useEffectOnce } from "#/hooks/use-effect-once";
|
||||
@@ -44,7 +41,7 @@ function AppContent() {
|
||||
useConversationConfig();
|
||||
const { t } = useTranslation();
|
||||
const { data: settings } = useSettings();
|
||||
const { conversationId } = useConversation();
|
||||
const { conversationId } = useConversationId();
|
||||
const { data: conversation, isFetched } = useUserConversation(
|
||||
conversationId || null,
|
||||
);
|
||||
@@ -213,11 +210,7 @@ function AppContent() {
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ConversationProvider>
|
||||
<AppContent />
|
||||
</ConversationProvider>
|
||||
);
|
||||
return <AppContent />;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -10,7 +10,6 @@ import i18n from "i18next";
|
||||
import { vi } from "vitest";
|
||||
import { AxiosError } from "axios";
|
||||
import { AppStore, RootState, rootReducer } from "./src/store";
|
||||
import { ConversationProvider } from "#/context/conversation-context";
|
||||
|
||||
// Mock useParams before importing components
|
||||
vi.mock("react-router", async () => {
|
||||
@@ -72,9 +71,7 @@ export function renderWithProviders(
|
||||
})
|
||||
}
|
||||
>
|
||||
<ConversationProvider>
|
||||
<I18nextProvider i18n={i18n}>{children}</I18nextProvider>
|
||||
</ConversationProvider>
|
||||
<I18nextProvider i18n={i18n}>{children}</I18nextProvider>
|
||||
</QueryClientProvider>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user