refactor(frontend): update the styling for the microagent management page. (#10494)

This commit is contained in:
Hiep Le 2025-08-19 19:50:42 +07:00 committed by GitHub
parent f296d7bde5
commit 476954f3a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 217 additions and 32 deletions

View File

@ -444,28 +444,38 @@ describe("MicroagentManagement", () => {
expect(filePath2).toBeInTheDocument();
});
it("should display add microagent button in repository accordion", async () => {
it("should render add microagent button", async () => {
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(screen.getByTestId("repository-name-tooltip")).toBeInTheDocument();
});
// Check that add microagent buttons are present
const addButtons = screen.getAllByTestId("add-microagent-button");
expect(addButtons.length).toBeGreaterThan(0);
});
it("should open add microagent modal when add button is clicked", async () => {
it("should open modal when add button is clicked", async () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(screen.getByTestId("repository-name-tooltip")).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1292,11 +1302,18 @@ describe("MicroagentManagement", () => {
it("should render add microagent button", async () => {
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Check that add microagent buttons are present
const addButtons = screen.getAllByTestId("add-microagent-button");
expect(addButtons.length).toBeGreaterThan(0);
@ -1306,11 +1323,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1361,11 +1385,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1385,11 +1416,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1408,11 +1446,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1441,11 +1486,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1468,11 +1520,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);
@ -1494,11 +1553,18 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
renderMicroagentManagement();
// Wait for repositories to be loaded
// Wait for repositories to be loaded and processed
await waitFor(() => {
expect(mockUseUserRepositories).toHaveBeenCalled();
});
// Wait for repositories to be displayed in the accordion
await waitFor(() => {
expect(
screen.getByTestId("repository-name-tooltip"),
).toBeInTheDocument();
});
// Find and click the first add microagent button
const addButtons = screen.getAllByTestId("add-microagent-button");
await user.click(addButtons[0]);

View File

@ -17,7 +17,7 @@ export function MicroagentManagementAccordionTitle({
<TooltipButton
tooltip={repository.full_name}
ariaLabel={repository.full_name}
className="text-white text-base font-normal bg-transparent p-0 min-w-0 h-auto cursor-pointer truncate max-w-[232px]"
className="text-white text-base font-normal bg-transparent p-0 min-w-0 h-auto cursor-pointer truncate max-w-[200px] translate-y-[-1px]"
testId="repository-name-tooltip"
placement="bottom"
>

View File

@ -7,8 +7,6 @@ import {
} from "#/state/microagent-management-slice";
import { RootState } from "#/store";
import { GitRepository } from "#/types/git";
import PlusIcon from "#/icons/plus.svg?react";
import { TooltipButton } from "#/components/shared/buttons/tooltip-button";
interface MicroagentManagementAddMicroagentButtonProps {
repository: GitRepository;
@ -25,23 +23,22 @@ export function MicroagentManagementAddMicroagentButton({
const dispatch = useDispatch();
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
dispatch(setAddMicroagentModalVisible(!addMicroagentModalVisible));
dispatch(setSelectedRepository(repository));
};
return (
<div onClick={handleClick}>
<TooltipButton
tooltip={t(I18nKey.COMMON$ADD_MICROAGENT)}
ariaLabel={t(I18nKey.COMMON$ADD_MICROAGENT)}
className="p-0 min-w-0 h-6 w-6 flex items-center justify-center bg-transparent cursor-pointer"
testId="add-microagent-button"
placement="bottom"
>
<PlusIcon width={22} height={22} />
</TooltipButton>
</div>
<button
type="button"
onClick={handleClick}
className="translate-y-[-1px]"
data-testid="add-microagent-button"
>
<span className="text-sm font-normal leading-5 text-[#8480FF] cursor-pointer hover:text-[#6C63FF] transition-colors duration-200">
{t(I18nKey.COMMON$ADD_MICROAGENT)}
</span>
</button>
);
}

View File

@ -1,4 +1,5 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { MicroagentManagementSidebar } from "./microagent-management-sidebar";
import { MicroagentManagementMain } from "./microagent-management-main";
@ -25,6 +26,12 @@ import { GitRepository } from "#/types/git";
import { queryClient } from "#/query-client-config";
import { Provider } from "#/types/settings";
import { MicroagentManagementLearnThisRepoModal } from "./microagent-management-learn-this-repo-modal";
import {
displaySuccessToast,
displayErrorToast,
} from "#/utils/custom-toast-handlers";
import { getFirstPRUrl } from "#/utils/parse-pr-url";
import { I18nKey } from "#/i18n/declaration";
// Handle error events
const isErrorEvent = (evt: unknown): evt is { error: true; message: string } =>
@ -112,6 +119,8 @@ export function MicroagentManagementContent() {
learnThisRepoModalVisible,
} = useSelector((state: RootState) => state.microagentManagement);
const { t } = useTranslation();
const dispatch = useDispatch();
const { createConversationAndSubscribe, isPending } =
@ -159,6 +168,37 @@ export function MicroagentManagementContent() {
? (selectedRepository as GitRepository).full_name
: "";
// Check if agent is running and ready to work
if (
isOpenHandsEvent(socketEvent) &&
isAgentStateChangeObservation(socketEvent) &&
socketEvent.extras.agent_state === AgentState.RUNNING
) {
displaySuccessToast(
t(I18nKey.MICROAGENT_MANAGEMENT$OPENING_PR_TO_CREATE_MICROAGENT),
);
}
// Check if agent has finished and we have a PR
if (isOpenHandsEvent(socketEvent) && isFinishAction(socketEvent)) {
const prUrl = getFirstPRUrl(socketEvent.args.final_thought || "");
if (prUrl) {
displaySuccessToast(
t(I18nKey.MICROAGENT_MANAGEMENT$PR_READY_FOR_REVIEW),
);
} else {
// Agent finished but no PR found
displaySuccessToast(t(I18nKey.MICROAGENT_MANAGEMENT$PR_NOT_CREATED));
}
}
// Handle error events
if (isErrorEvent(socketEvent) || isAgentStatusError(socketEvent)) {
displayErrorToast(
t(I18nKey.MICROAGENT_MANAGEMENT$ERROR_CREATING_MICROAGENT),
);
}
if (shouldInvalidateConversationsList(socketEvent)) {
invalidateConversationsList(repositoryName);
}

View File

@ -65,6 +65,18 @@ export function MicroagentManagementRepoMicroagents({
}
}, [conversations]);
useEffect(
() => () => {
dispatch(
setSelectedMicroagentItem({
microagent: null,
conversation: null,
}),
);
},
[],
);
// Show loading only when both queries are loading
const isLoading = isLoadingMicroagents || isLoadingConversations;
@ -82,7 +94,7 @@ export function MicroagentManagementRepoMicroagents({
// If there's an error with microagents, show the learn this repo component
if (isError) {
return (
<div className="pb-4">
<div>
<MicroagentManagementLearnThisRepo repository={repository} />
</div>
);
@ -93,7 +105,7 @@ export function MicroagentManagementRepoMicroagents({
const totalItems = numberOfMicroagents + numberOfConversations;
return (
<div className="pb-4">
<div>
{totalItems === 0 && (
<MicroagentManagementLearnThisRepo repository={repository} />
)}

View File

@ -97,8 +97,10 @@ export function MicroagentManagementRepositories({
variant="splitted"
className="w-full px-0 gap-3"
itemClasses={{
base: "shadow-none bg-transparent border border-[#ffffff40] rounded-[6px] cursor-pointer",
trigger: "cursor-pointer gap-1",
base: "shadow-none bg-transparent cursor-pointer px-0",
trigger: "cursor-pointer gap-2 py-3",
indicator:
"flex items-center justify-center p-0.5 pr-[3px] text-white hover:bg-[#454545] rounded transition-colors duration-200 rotate-180",
}}
selectionMode="multiple"
>

View File

@ -23,7 +23,7 @@ export function ModalBackdrop({ children, onClose }: ModalBackdropProps) {
<div className="fixed inset-0 flex items-center justify-center z-20">
<div
onClick={handleClick}
className="fixed inset-0 bg-black bg-opacity-80"
className="fixed inset-0 bg-black opacity-60"
/>
<div className="relative">{children}</div>
</div>

View File

@ -810,4 +810,8 @@ export enum I18nKey {
PROJECT_MANAGEMENT$CONFIGURE_MODAL_DESCRIPTION = "PROJECT_MANAGEMENT$CONFIGURE_MODAL_DESCRIPTION",
PROJECT_MANAGEMENT$IMPORTANT_WORKSPACE_INTEGRATION = "PROJECT_MANAGEMENT$IMPORTANT_WORKSPACE_INTEGRATION",
SETTINGS = "SETTINGS",
MICROAGENT_MANAGEMENT$OPENING_PR_TO_CREATE_MICROAGENT = "MICROAGENT_MANAGEMENT$OPENING_PR_TO_CREATE_MICROAGENT",
MICROAGENT_MANAGEMENT$PR_READY_FOR_REVIEW = "MICROAGENT_MANAGEMENT$PR_READY_FOR_REVIEW",
MICROAGENT_MANAGEMENT$PR_NOT_CREATED = "MICROAGENT_MANAGEMENT$PR_NOT_CREATED",
MICROAGENT_MANAGEMENT$ERROR_CREATING_MICROAGENT = "MICROAGENT_MANAGEMENT$ERROR_CREATING_MICROAGENT",
}

View File

@ -12958,5 +12958,69 @@
"tr": "A server with this URL already exists for the selected type",
"de": "A server with this URL already exists for the selected type",
"uk": "A server with this URL already exists for the selected type"
},
"MICROAGENT_MANAGEMENT$OPENING_PR_TO_CREATE_MICROAGENT": {
"en": "Opening a PR to create the microagent for you...",
"ja": "マイクロエージェントを作成するためのプルリクエストを作成しています...",
"zh-CN": "正在为您创建微代理的拉取请求...",
"zh-TW": "正在為您建立微代理的拉取請求...",
"ko-KR": "마이크로에이전트를 생성하기 위한 PR을 열고 있습니다...",
"no": "Åpner en PR for å opprette mikroagenten for deg...",
"it": "Apertura di una PR per creare il microagente per te...",
"pt": "Abrindo um PR para criar o microagente para você...",
"es": "Abriendo un PR para crear el microagente para ti...",
"ar": "يتم فتح طلب سحب لإنشاء الوكيل الدقيق من أجلك...",
"fr": "Ouverture d'une PR pour créer le microagent pour vous...",
"tr": "Sizin için mikro ajanı oluşturmak üzere bir PR açılıyor...",
"de": "Es wird ein PR geöffnet, um den Microagent für Sie zu erstellen...",
"uk": "Відкривається PR для створення мікроагента для вас..."
},
"MICROAGENT_MANAGEMENT$PR_READY_FOR_REVIEW": {
"en": "PR is ready for review! The microagent has been created successfully.",
"ja": "PRのレビューが可能ですマイクロエージェントが正常に作成されました。",
"zh-CN": "PR已准备好审核微代理已成功创建。",
"zh-TW": "PR 已準備好審查!微代理已成功建立。",
"ko-KR": "PR이 검토를 위해 준비되었습니다! 마이크로에이전트가 성공적으로 생성되었습니다.",
"no": "PR er klar for gjennomgang! Mikroagenten har blitt opprettet.",
"it": "La PR è pronta per la revisione! Il microagente è stato creato con successo.",
"pt": "PR pronto para revisão! O microagente foi criado com sucesso.",
"es": "¡La PR está lista para revisión! El microagente se ha creado correctamente.",
"ar": "طلب السحب جاهز للمراجعة! تم إنشاء الوكيل الدقيق بنجاح.",
"fr": "La PR est prête pour révision ! Le microagent a été créé avec succès.",
"tr": "PR incelemeye hazır! Mikro ajan başarıyla oluşturuldu.",
"de": "PR ist bereit zur Überprüfung! Der Microagent wurde erfolgreich erstellt.",
"uk": "PR готовий до перегляду! Мікроагента успішно створено."
},
"MICROAGENT_MANAGEMENT$PR_NOT_CREATED": {
"en": "The agent has finished its task but was unable to create a PR.",
"ja": "エージェントはタスクを完了しましたが、PRを作成できませんでした。",
"zh-CN": "代理已完成任务,但无法创建 PR。",
"zh-TW": "代理已完成任務,但無法建立 PR。",
"ko-KR": "에이전트가 작업을 완료했지만 PR을 생성할 수 없었습니다.",
"no": "Agenten har fullført oppgaven, men klarte ikke å opprette en PR.",
"it": "L'agente ha terminato il suo compito ma non è riuscito a creare una PR.",
"pt": "O agente concluiu sua tarefa, mas não conseguiu criar um PR.",
"es": "El agente ha terminado su tarea pero no pudo crear un PR.",
"ar": "أكمل الوكيل مهمته لكنه لم يتمكن من إنشاء طلب سحب (PR).",
"fr": "L'agent a terminé sa tâche mais n'a pas pu créer de PR.",
"tr": "Ajan görevini tamamladı ancak bir PR oluşturamadı.",
"de": "Der Agent hat seine Aufgabe abgeschlossen, konnte aber keinen PR erstellen.",
"uk": "Агент завершив завдання, але не зміг створити PR."
},
"MICROAGENT_MANAGEMENT$ERROR_CREATING_MICROAGENT": {
"en": "Something went wrong. Try initiating the microagent again.",
"ja": "問題が発生しました。もう一度マイクロエージェントを開始してください。",
"zh-CN": "出现了问题。请重试启动微代理。",
"zh-TW": "發生錯誤。請再次嘗試啟動微代理。",
"ko-KR": "문제가 발생했습니다. 마이크로에이전트를 다시 시작해 보세요.",
"no": "Noe gikk galt. Prøv å starte mikroagenten på nytt.",
"it": "Qualcosa è andato storto. Prova a iniziare di nuovo il microagente.",
"pt": "Algo deu errado. Tente iniciar o microagente novamente.",
"es": "Algo salió mal. Intenta iniciar el microagente de nuevo.",
"ar": "حدث خطأ ما. حاول بدء تشغيل الوكيل الدقيق مرة أخرى.",
"fr": "Une erreur s'est produite. Essayez de relancer le microagent.",
"tr": "Bir şeyler ters gitti. Mikro ajanı tekrar başlatmayı deneyin.",
"de": "Etwas ist schiefgelaufen. Versuchen Sie, den Microagenten erneut zu starten.",
"uk": "Щось пішло не так. Спробуйте ініціювати мікроагента ще раз."
}
}