mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 05:48:36 +08:00
refactor(frontend): Show branch name and git provider on the conversation cards (#9480)
Co-authored-by: amanape <83104063+amanape@users.noreply.github.com>
This commit is contained in:
parent
12a95fb548
commit
7bfa05d38a
@ -27,9 +27,9 @@ vi.mock("react-i18next", async () => {
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => {
|
||||
const translations: Record<string, string> = {
|
||||
"CONVERSATION$CREATED": "Created",
|
||||
"CONVERSATION$AGO": "ago",
|
||||
"CONVERSATION$UPDATED": "Updated"
|
||||
CONVERSATION$CREATED: "Created",
|
||||
CONVERSATION$AGO: "ago",
|
||||
CONVERSATION$UPDATED: "Updated",
|
||||
};
|
||||
return translations[key] || key;
|
||||
},
|
||||
@ -82,7 +82,9 @@ describe("ConversationCard", () => {
|
||||
expect(card).toHaveTextContent("ago");
|
||||
|
||||
// Use a regex to match the time part since it might have whitespace
|
||||
const timeRegex = new RegExp(formatTimeDelta(new Date("2021-10-01T12:00:00Z")));
|
||||
const timeRegex = new RegExp(
|
||||
formatTimeDelta(new Date("2021-10-01T12:00:00Z")),
|
||||
);
|
||||
expect(card).toHaveTextContent(timeRegex);
|
||||
});
|
||||
|
||||
@ -108,7 +110,11 @@ describe("ConversationCard", () => {
|
||||
onChangeTitle={onChangeTitle}
|
||||
isActive
|
||||
title="Conversation 1"
|
||||
selectedRepository="org/selectedRepository"
|
||||
selectedRepository={{
|
||||
selected_repository: "org/selectedRepository",
|
||||
selected_branch: "main",
|
||||
git_provider: "github",
|
||||
}}
|
||||
lastUpdatedAt="2021-10-01T12:00:00Z"
|
||||
/>,
|
||||
);
|
||||
@ -173,7 +179,11 @@ describe("ConversationCard", () => {
|
||||
isActive
|
||||
onChangeTitle={onChangeTitle}
|
||||
title="Conversation 1"
|
||||
selectedRepository="org/selectedRepository"
|
||||
selectedRepository={{
|
||||
selected_repository: "org/selectedRepository",
|
||||
selected_branch: "main",
|
||||
git_provider: "github",
|
||||
}}
|
||||
lastUpdatedAt="2021-10-01T12:00:00Z"
|
||||
/>,
|
||||
);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { ConversationStatus } from "#/types/conversation-status";
|
||||
import { RuntimeStatus } from "#/types/runtime-status";
|
||||
import { Provider } from "#/types/settings";
|
||||
|
||||
export interface ErrorResponse {
|
||||
error: string;
|
||||
@ -70,6 +71,12 @@ export interface AuthenticateResponse {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface RepositorySelection {
|
||||
selected_repository: string | null;
|
||||
selected_branch: string | null;
|
||||
git_provider: Provider | null;
|
||||
}
|
||||
|
||||
export type ConversationTrigger = "resolver" | "gui" | "suggested_task";
|
||||
|
||||
export interface Conversation {
|
||||
|
||||
@ -4,6 +4,7 @@ import { AgentStatusBar } from "./agent-status-bar";
|
||||
import { SecurityLock } from "./security-lock";
|
||||
import { useActiveConversation } from "#/hooks/query/use-active-conversation";
|
||||
import { ConversationCard } from "../conversation-panel/conversation-card";
|
||||
import { Provider } from "#/types/settings";
|
||||
|
||||
interface ControlsProps {
|
||||
setSecurityOpen: (isOpen: boolean) => void;
|
||||
@ -29,7 +30,11 @@ export function Controls({ setSecurityOpen, showSecurityLock }: ControlsProps) {
|
||||
showOptions
|
||||
title={conversation?.title ?? ""}
|
||||
lastUpdatedAt={conversation?.created_at ?? ""}
|
||||
selectedRepository={conversation?.selected_repository ?? null}
|
||||
selectedRepository={{
|
||||
selected_repository: conversation?.selected_repository ?? null,
|
||||
selected_branch: conversation?.selected_branch ?? null,
|
||||
git_provider: (conversation?.git_provider as Provider) ?? null,
|
||||
}}
|
||||
conversationStatus={conversation?.status}
|
||||
conversationId={conversation?.conversation_id}
|
||||
/>
|
||||
|
||||
@ -19,6 +19,7 @@ import OpenHands from "#/api/open-hands";
|
||||
import { useWsClient } from "#/context/ws-client-provider";
|
||||
import { isSystemMessage } from "#/types/core/guards";
|
||||
import { ConversationStatus } from "#/types/conversation-status";
|
||||
import { RepositorySelection } from "#/api/open-hands.types";
|
||||
|
||||
interface ConversationCardProps {
|
||||
onClick?: () => void;
|
||||
@ -28,7 +29,7 @@ interface ConversationCardProps {
|
||||
showOptions?: boolean;
|
||||
isActive?: boolean;
|
||||
title: string;
|
||||
selectedRepository: string | null;
|
||||
selectedRepository: RepositorySelection | null;
|
||||
lastUpdatedAt: string; // ISO 8601
|
||||
createdAt?: string; // ISO 8601
|
||||
conversationStatus?: ConversationStatus;
|
||||
@ -180,7 +181,7 @@ export function ConversationCard({
|
||||
data-testid="conversation-card"
|
||||
onClick={onClick}
|
||||
className={cn(
|
||||
"h-[100px] w-full px-[18px] py-4 border-b border-neutral-600 cursor-pointer",
|
||||
"h-auto w-full px-[18px] py-4 border-b border-neutral-600 cursor-pointer",
|
||||
variant === "compact" &&
|
||||
"md:w-fit h-auto rounded-xl border border-[#525252]",
|
||||
)}
|
||||
@ -264,11 +265,14 @@ export function ConversationCard({
|
||||
|
||||
<div
|
||||
className={cn(
|
||||
variant === "compact" && "flex items-center justify-between mt-1",
|
||||
variant === "compact" && "flex flex-col justify-between mt-1",
|
||||
)}
|
||||
>
|
||||
{selectedRepository && (
|
||||
<ConversationRepoLink selectedRepository={selectedRepository} />
|
||||
{selectedRepository?.selected_repository && (
|
||||
<ConversationRepoLink
|
||||
selectedRepository={selectedRepository}
|
||||
variant={variant}
|
||||
/>
|
||||
)}
|
||||
<p className="text-xs text-neutral-400">
|
||||
<span>{t(I18nKey.CONVERSATION$CREATED)} </span>
|
||||
|
||||
@ -11,6 +11,7 @@ import { ConfirmStopModal } from "./confirm-stop-modal";
|
||||
import { LoadingSpinner } from "#/components/shared/loading-spinner";
|
||||
import { ExitConversationModal } from "./exit-conversation-modal";
|
||||
import { useClickOutsideElement } from "#/hooks/use-click-outside-element";
|
||||
import { Provider } from "#/types/settings";
|
||||
|
||||
interface ConversationPanelProps {
|
||||
onClose: () => void;
|
||||
@ -114,7 +115,11 @@ export function ConversationPanel({ onClose }: ConversationPanelProps) {
|
||||
onDelete={() => handleDeleteProject(project.conversation_id)}
|
||||
onStop={() => handleStopConversation(project.conversation_id)}
|
||||
title={project.title}
|
||||
selectedRepository={project.selected_repository}
|
||||
selectedRepository={{
|
||||
selected_repository: project.selected_repository,
|
||||
selected_branch: project.selected_branch,
|
||||
git_provider: project.git_provider as Provider,
|
||||
}}
|
||||
lastUpdatedAt={project.last_updated_at}
|
||||
createdAt={project.created_at}
|
||||
conversationStatus={project.status}
|
||||
|
||||
@ -1,16 +1,44 @@
|
||||
import { FaBitbucket, FaGithub, FaGitlab } from "react-icons/fa6";
|
||||
import { RepositorySelection } from "#/api/open-hands.types";
|
||||
|
||||
interface ConversationRepoLinkProps {
|
||||
selectedRepository: string;
|
||||
selectedRepository: RepositorySelection;
|
||||
variant: "compact" | "default";
|
||||
}
|
||||
|
||||
export function ConversationRepoLink({
|
||||
selectedRepository,
|
||||
variant = "default",
|
||||
}: ConversationRepoLinkProps) {
|
||||
if (variant === "compact") {
|
||||
return (
|
||||
<span
|
||||
data-testid="conversation-card-selected-repository"
|
||||
className="text-xs text-neutral-400"
|
||||
>
|
||||
{selectedRepository.selected_repository}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
data-testid="conversation-card-selected-repository"
|
||||
className="text-xs text-neutral-400"
|
||||
>
|
||||
{selectedRepository}
|
||||
</span>
|
||||
<div className="flex items-center gap-1">
|
||||
{selectedRepository.git_provider === "github" && <FaGithub size={14} />}
|
||||
{selectedRepository.git_provider === "gitlab" && <FaGitlab />}
|
||||
{selectedRepository.git_provider === "bitbucket" && <FaBitbucket />}
|
||||
|
||||
<span
|
||||
data-testid="conversation-card-selected-repository"
|
||||
className="text-xs text-neutral-400"
|
||||
>
|
||||
{selectedRepository.selected_repository}
|
||||
</span>
|
||||
<code
|
||||
data-testid="conversation-card-selected-branch"
|
||||
className="text-xs text-neutral-400 border border-neutral-700 rounded px-1 py-0.5 w-fit bg-neutral-800"
|
||||
>
|
||||
{selectedRepository.selected_branch}
|
||||
</code>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -97,6 +97,9 @@ export enum I18nKey {
|
||||
BROWSER$EMPTY_MESSAGE = "BROWSER$EMPTY_MESSAGE",
|
||||
SETTINGS$TITLE = "SETTINGS$TITLE",
|
||||
CONVERSATION$START_NEW = "CONVERSATION$START_NEW",
|
||||
CONVERSATION$REPOSITORY = "CONVERSATION$REPOSITORY",
|
||||
CONVERSATION$BRANCH = "CONVERSATION$BRANCH",
|
||||
CONVERSATION$GIT_PROVIDER = "CONVERSATION$GIT_PROVIDER",
|
||||
ACCOUNT_SETTINGS$TITLE = "ACCOUNT_SETTINGS$TITLE",
|
||||
WORKSPACE$TERMINAL_TAB_LABEL = "WORKSPACE$TERMINAL_TAB_LABEL",
|
||||
WORKSPACE$BROWSER_TAB_LABEL = "WORKSPACE$BROWSER_TAB_LABEL",
|
||||
|
||||
@ -1551,6 +1551,54 @@
|
||||
"de": "Neue Unterhaltung starten",
|
||||
"uk": "Почати нову розмову"
|
||||
},
|
||||
"CONVERSATION$REPOSITORY": {
|
||||
"en": "Repository",
|
||||
"ja": "リポジトリ",
|
||||
"zh-CN": "仓库",
|
||||
"zh-TW": "倉庫",
|
||||
"ko-KR": "저장소",
|
||||
"no": "Repository",
|
||||
"it": "Repository",
|
||||
"pt": "Repositório",
|
||||
"es": "Repositorio",
|
||||
"ar": "المستودع",
|
||||
"fr": "Dépôt",
|
||||
"tr": "Depo",
|
||||
"de": "Repository",
|
||||
"uk": "Репозиторій"
|
||||
},
|
||||
"CONVERSATION$BRANCH": {
|
||||
"en": "Branch",
|
||||
"ja": "ブランチ",
|
||||
"zh-CN": "分支",
|
||||
"zh-TW": "分支",
|
||||
"ko-KR": "브랜치",
|
||||
"no": "Gren",
|
||||
"it": "Ramo",
|
||||
"pt": "Ramo",
|
||||
"es": "Rama",
|
||||
"ar": "الفرع",
|
||||
"fr": "Branche",
|
||||
"tr": "Dal",
|
||||
"de": "Zweig",
|
||||
"uk": "Гілка"
|
||||
},
|
||||
"CONVERSATION$GIT_PROVIDER": {
|
||||
"en": "Git Provider",
|
||||
"ja": "Git プロバイダー",
|
||||
"zh-CN": "Git 提供商",
|
||||
"zh-TW": "Git 提供商",
|
||||
"ko-KR": "Git 제공업체",
|
||||
"no": "Git-leverandør",
|
||||
"it": "Provider Git",
|
||||
"pt": "Provedor Git",
|
||||
"es": "Proveedor Git",
|
||||
"ar": "مزود Git",
|
||||
"fr": "Fournisseur Git",
|
||||
"tr": "Git Sağlayıcısı",
|
||||
"de": "Git-Anbieter",
|
||||
"uk": "Git-провайдер"
|
||||
},
|
||||
"ACCOUNT_SETTINGS$TITLE": {
|
||||
"en": "Account Settings",
|
||||
"ja": "アカウント設定",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user