refactor(frontend): migration of microagent-management-slice.ts to zustand (#11033)

This commit is contained in:
Hiep Le
2025-09-24 23:58:17 +07:00
committed by GitHub
parent 8f004a1f6d
commit f59ea69b70
21 changed files with 263 additions and 612 deletions

View File

@@ -12,6 +12,7 @@ import GitService from "#/api/git-service/git-service.api";
import { GitRepository } from "#/types/git";
import { RepositoryMicroagent } from "#/types/microagent-management";
import { Conversation } from "#/api/open-hands.types";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
// Mock hooks
const mockUseUserProviders = vi.fn();
@@ -55,20 +56,47 @@ describe("MicroagentManagement", () => {
]);
const renderMicroagentManagement = (config?: QueryClientConfig) =>
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: null,
personalRepositories: [],
organizationRepositories: [],
repositories: [],
selectedMicroagentItem: null,
learnThisRepoModalVisible: false,
},
},
renderWithProviders(<RouterStub />);
// Common test data
const testRepository = {
id: "1",
full_name: "user/test-repo",
git_provider: "github" as const,
is_public: true,
owner_type: "user" as const,
pushed_at: "2021-10-01T12:00:00Z",
};
// Helper function to render with custom Zustand store state
const renderWithCustomStore = (storeOverrides: Partial<any>) => {
useMicroagentManagementStore.setState(storeOverrides);
return renderWithProviders(<RouterStub />);
};
// Helper function to render with update modal visible
const renderWithUpdateModal = (additionalState: Partial<any> = {}) => {
return renderWithCustomStore({
updateMicroagentModalVisible: true,
selectedRepository: testRepository,
...additionalState,
});
};
// Helper function to render with selected microagent
const renderWithSelectedMicroagent = (
microagent: any,
additionalState: Partial<any> = {},
) => {
return renderWithCustomStore({
selectedRepository: testRepository,
selectedMicroagentItem: {
microagent,
conversation: null,
},
...additionalState,
});
};
beforeAll(() => {
vi.mock("react-router", async (importOriginal) => ({
@@ -181,6 +209,23 @@ describe("MicroagentManagement", () => {
vi.clearAllMocks();
vi.restoreAllMocks();
// Reset Zustand store to default state
useMicroagentManagementStore.setState({
// Modal visibility states
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
learnThisRepoModalVisible: false,
// Repository states
selectedRepository: null,
personalRepositories: [],
organizationRepositories: [],
repositories: [],
// Microagent states
selectedMicroagentItem: null,
});
// Setup default hook mocks
mockUseUserProviders.mockReturnValue({
providers: ["github"],
@@ -1342,28 +1387,10 @@ describe("MicroagentManagement", () => {
});
});
it("should render modal when Redux state is set to visible", async () => {
// Render with modal already visible in Redux state
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: null,
addMicroagentModalVisible: true, // Start with modal visible
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
updateMicroagentModalVisible: false,
learnThisRepoModalVisible: false,
},
},
it("should render modal when Zustand state is set to visible", async () => {
// Render with modal already visible in Zustand state
renderWithCustomStore({
addMicroagentModalVisible: true,
});
// Check that modal is rendered
@@ -1633,29 +1660,16 @@ describe("MicroagentManagement", () => {
pr_number: null,
};
const renderMicroagentManagementMain = (selectedMicroagentItem: any) =>
renderWithProviders(<MicroagentManagementMain />, {
preloadedState: {
microagentManagement: {
addMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
selectedMicroagentItem,
updateMicroagentModalVisible: false,
learnThisRepoModalVisible: false,
},
},
const renderMicroagentManagementMain = (selectedMicroagentItem: any) => {
// Set the store with the selected microagent item and a repository
useMicroagentManagementStore.setState({
selectedMicroagentItem,
selectedRepository: testRepository,
});
return renderWithProviders(<MicroagentManagementMain />);
};
it("should render MicroagentManagementDefault when no microagent or conversation is selected", async () => {
renderMicroagentManagementMain(null);
@@ -1980,31 +1994,8 @@ describe("MicroagentManagement", () => {
});
it("should render update microagent modal when updateMicroagentModalVisible is true", async () => {
// Render with update modal visible in Redux state
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true, // Start with update modal visible
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
// Render with update modal visible in Zustand state
renderWithUpdateModal();
// Check that update modal is rendered
expect(screen.getByTestId("add-microagent-modal")).toBeInTheDocument();
@@ -2015,30 +2006,7 @@ describe("MicroagentManagement", () => {
it("should display update microagent title when isUpdate is true", async () => {
// Render with update modal visible and selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Check that the update title is displayed
expect(
@@ -2048,28 +2016,10 @@ describe("MicroagentManagement", () => {
it("should populate form fields with existing microagent data when updating", async () => {
// Render with update modal visible and selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
renderWithUpdateModal({
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: null,
},
});
@@ -2086,30 +2036,7 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
// Render with update modal visible and selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Wait for modal to be rendered
await waitFor(() => {
@@ -2137,30 +2064,7 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
// Render with update modal visible
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Wait for modal to be rendered
await waitFor(() => {
@@ -2183,30 +2087,7 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
// Render with update modal visible
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Wait for modal to be rendered
await waitFor(() => {
@@ -2232,27 +2113,7 @@ describe("MicroagentManagement", () => {
it("should handle update modal with empty microagent data", async () => {
// Render with update modal visible but no microagent data
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: null,
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Check that update modal is still rendered
expect(screen.getByTestId("add-microagent-modal")).toBeInTheDocument();
@@ -2273,30 +2134,7 @@ describe("MicroagentManagement", () => {
});
// Render with update modal visible and microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Wait for the content to be loaded and check that the form field is empty
await waitFor(() => {
@@ -2317,30 +2155,7 @@ describe("MicroagentManagement", () => {
});
// Render with update modal visible and microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForUpdate,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: true,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithUpdateModal();
// Check that the modal is rendered correctly
expect(screen.getByTestId("add-microagent-modal")).toBeInTheDocument();
@@ -2499,30 +2314,7 @@ describe("MicroagentManagement", () => {
it("should render learn something new button in microagent view", async () => {
// Render with selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForLearn,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithSelectedMicroagent(mockMicroagentForLearn);
// Check that the learn something new button is displayed
expect(
@@ -2534,30 +2326,7 @@ describe("MicroagentManagement", () => {
const user = userEvent.setup();
// Render with selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForLearn,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithSelectedMicroagent(mockMicroagentForLearn);
// Find and click the learn something new button
const learnButton = screen.getByText("COMMON$LEARN_SOMETHING_NEW");
@@ -2586,30 +2355,7 @@ describe("MicroagentManagement", () => {
});
// Render with selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForLearn,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithSelectedMicroagent(mockMicroagentForLearn);
// Find and click the learn something new button
const learnButton = screen.getByText("COMMON$LEARN_SOMETHING_NEW");
@@ -2641,30 +2387,7 @@ describe("MicroagentManagement", () => {
});
// Render with selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForLearn,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithSelectedMicroagent(mockMicroagentForLearn);
// Find and click the learn something new button
const learnButton = screen.getByText("COMMON$LEARN_SOMETHING_NEW");
@@ -2694,30 +2417,7 @@ describe("MicroagentManagement", () => {
});
// Render with selected microagent
renderWithProviders(<RouterStub />, {
preloadedState: {
microagentManagement: {
selectedMicroagentItem: {
microagent: mockMicroagentForLearn,
conversation: undefined,
},
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: {
id: "1",
full_name: "user/test-repo",
git_provider: "github",
is_public: true,
owner_type: "user",
pushed_at: "2021-10-01T12:00:00Z",
},
personalRepositories: [],
organizationRepositories: [],
repositories: [],
learnThisRepoModalVisible: false,
},
},
});
renderWithSelectedMicroagent(mockMicroagentForLearn);
// Find and click the learn something new button
const learnButton = screen.getByText("COMMON$LEARN_SOMETHING_NEW");

View File

@@ -1,11 +1,6 @@
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
import { I18nKey } from "#/i18n/declaration";
import {
setAddMicroagentModalVisible,
setSelectedRepository,
} from "#/state/microagent-management-slice";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { GitRepository } from "#/types/git";
interface MicroagentManagementAddMicroagentButtonProps {
@@ -17,16 +12,16 @@ export function MicroagentManagementAddMicroagentButton({
}: MicroagentManagementAddMicroagentButtonProps) {
const { t } = useTranslation();
const { addMicroagentModalVisible } = useSelector(
(state: RootState) => state.microagentManagement,
);
const dispatch = useDispatch();
const {
addMicroagentModalVisible,
setAddMicroagentModalVisible,
setSelectedRepository,
} = useMicroagentManagementStore();
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.stopPropagation();
dispatch(setAddMicroagentModalVisible(!addMicroagentModalVisible));
dispatch(setSelectedRepository(repository));
setAddMicroagentModalVisible(!addMicroagentModalVisible);
setSelectedRepository(repository);
};
return (

View File

@@ -1,15 +1,9 @@
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";
import { MicroagentManagementUpsertMicroagentModal } from "./microagent-management-upsert-microagent-modal";
import { RootState } from "#/store";
import {
setAddMicroagentModalVisible,
setUpdateMicroagentModalVisible,
setLearnThisRepoModalVisible,
} from "#/state/microagent-management-slice";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { useCreateConversationAndSubscribeMultiple } from "#/hooks/use-create-conversation-and-subscribe-multiple";
import {
LearnThisRepoFormData,
@@ -106,14 +100,15 @@ export function MicroagentManagementContent() {
updateMicroagentModalVisible,
selectedRepository,
learnThisRepoModalVisible,
} = useSelector((state: RootState) => state.microagentManagement);
setAddMicroagentModalVisible,
setUpdateMicroagentModalVisible,
setLearnThisRepoModalVisible,
} = useMicroagentManagementStore();
const { providers } = useUserProviders();
const { t } = useTranslation();
const dispatch = useDispatch();
const { createConversationAndSubscribe, isPending } =
useCreateConversationAndSubscribeMultiple();
@@ -130,9 +125,9 @@ export function MicroagentManagementContent() {
const hideUpsertMicroagentModal = (isUpdate: boolean = false) => {
if (isUpdate) {
dispatch(setUpdateMicroagentModalVisible(false));
setUpdateMicroagentModalVisible(false);
} else {
dispatch(setAddMicroagentModalVisible(false));
setAddMicroagentModalVisible(false);
}
};
@@ -264,7 +259,7 @@ export function MicroagentManagementContent() {
};
const hideLearnThisRepoModal = () => {
dispatch(setLearnThisRepoModalVisible(false));
setLearnThisRepoModalVisible(false);
};
const handleLearnThisRepoConfirm = (formData: LearnThisRepoFormData) => {

View File

@@ -1,16 +1,13 @@
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { RootState } from "#/store";
import { I18nKey } from "#/i18n/declaration";
import { BrandButton } from "../settings/brand-button";
import { Loader } from "#/components/shared/loader";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
export function MicroagentManagementConversationStopped() {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useMicroagentManagementStore();
const { conversation } = selectedMicroagentItem ?? {};

View File

@@ -1,16 +1,13 @@
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { RootState } from "#/store";
import { I18nKey } from "#/i18n/declaration";
import { BrandButton } from "../settings/brand-button";
import { Loader } from "#/components/shared/loader";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
export function MicroagentManagementError() {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useMicroagentManagementStore();
const { conversation } = selectedMicroagentItem ?? {};

View File

@@ -1,12 +1,11 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { FaCircleInfo } from "react-icons/fa6";
import { ModalBackdrop } from "#/components/shared/modals/modal-backdrop";
import { ModalBody } from "#/components/shared/modals/modal-body";
import { BrandButton } from "../settings/brand-button";
import { I18nKey } from "#/i18n/declaration";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import XIcon from "#/icons/x.svg?react";
import { cn, getRepoMdCreatePrompt } from "#/utils/utils";
import { LearnThisRepoFormData } from "#/types/microagent-management";
@@ -26,9 +25,7 @@ export function MicroagentManagementLearnThisRepoModal({
const [query, setQuery] = useState<string>("");
const { selectedRepository } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedRepository } = useMicroagentManagementStore();
const onSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();

View File

@@ -1,10 +1,6 @@
import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import {
setLearnThisRepoModalVisible,
setSelectedRepository,
} from "#/state/microagent-management-slice";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { GitRepository } from "#/types/git";
interface MicroagentManagementLearnThisRepoProps {
@@ -14,12 +10,13 @@ interface MicroagentManagementLearnThisRepoProps {
export function MicroagentManagementLearnThisRepo({
repository,
}: MicroagentManagementLearnThisRepoProps) {
const dispatch = useDispatch();
const { setLearnThisRepoModalVisible, setSelectedRepository } =
useMicroagentManagementStore();
const { t } = useTranslation();
const handleClick = () => {
dispatch(setLearnThisRepoModalVisible(true));
dispatch(setSelectedRepository(repository));
setLearnThisRepoModalVisible(true);
setSelectedRepository(repository);
};
return (

View File

@@ -1,5 +1,4 @@
import { useSelector } from "react-redux";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { MicroagentManagementDefault } from "./microagent-management-default";
import { MicroagentManagementOpeningPr } from "./microagent-management-opening-pr";
import { MicroagentManagementReviewPr } from "./microagent-management-review-pr";
@@ -8,9 +7,7 @@ import { MicroagentManagementError } from "./microagent-management-error";
import { MicroagentManagementConversationStopped } from "./microagent-management-conversation-stopped";
export function MicroagentManagementMain() {
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useMicroagentManagementStore();
const { microagent, conversation } = selectedMicroagentItem ?? {};

View File

@@ -1,14 +1,9 @@
import { useMemo } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { RepositoryMicroagent } from "#/types/microagent-management";
import { Conversation } from "#/api/open-hands.types";
import {
setSelectedMicroagentItem,
setSelectedRepository,
} from "#/state/microagent-management-slice";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { cn } from "#/utils/utils";
import { GitRepository } from "#/types/git";
@@ -25,11 +20,11 @@ export function MicroagentManagementMicroagentCard({
}: MicroagentManagementMicroagentCardProps) {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const dispatch = useDispatch();
const {
selectedMicroagentItem,
setSelectedMicroagentItem,
setSelectedRepository,
} = useMicroagentManagementStore();
const {
status: conversationStatus,
@@ -83,20 +78,18 @@ export function MicroagentManagementMicroagentCard({
}, [microagent, conversation, selectedMicroagentItem]);
const onMicroagentCardClicked = () => {
dispatch(
setSelectedMicroagentItem(
microagent
? {
microagent,
conversation: null,
}
: {
microagent: null,
conversation,
},
),
setSelectedMicroagentItem(
microagent
? {
microagent,
conversation: undefined,
}
: {
microagent: undefined,
conversation,
},
);
dispatch(setSelectedRepository(repository));
setSelectedRepository(repository);
};
return (

View File

@@ -1,16 +1,13 @@
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { RootState } from "#/store";
import { I18nKey } from "#/i18n/declaration";
import { BrandButton } from "../settings/brand-button";
import { Loader } from "#/components/shared/loader";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
export function MicroagentManagementOpeningPr() {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useMicroagentManagementStore();
const { conversation } = selectedMicroagentItem ?? {};

View File

@@ -1,14 +1,12 @@
import { useTranslation } from "react-i18next";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Spinner } from "@heroui/react";
import { MicroagentManagementMicroagentCard } from "./microagent-management-microagent-card";
import { MicroagentManagementLearnThisRepo } from "./microagent-management-learn-this-repo";
import { useRepositoryMicroagents } from "#/hooks/query/use-repository-microagents";
import { useMicroagentManagementConversations } from "#/hooks/query/use-microagent-management-conversations";
import { GitRepository } from "#/types/git";
import { RootState } from "#/store";
import { setSelectedMicroagentItem } from "#/state/microagent-management-slice";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { cn } from "#/utils/utils";
import { I18nKey } from "#/i18n/declaration";
@@ -19,11 +17,8 @@ interface MicroagentManagementRepoMicroagentsProps {
export function MicroagentManagementRepoMicroagents({
repository,
}: MicroagentManagementRepoMicroagentsProps) {
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const dispatch = useDispatch();
const { selectedMicroagentItem, setSelectedMicroagentItem } =
useMicroagentManagementStore();
const { t } = useTranslation();
@@ -60,26 +55,22 @@ export function MicroagentManagementRepoMicroagents({
conversation.conversation_id === selectedConversation.conversation_id,
);
if (latestSelectedConversation) {
dispatch(
setSelectedMicroagentItem({
microagent: null,
conversation: latestSelectedConversation,
}),
);
setSelectedMicroagentItem({
microagent: undefined,
conversation: latestSelectedConversation,
});
}
}
}, [conversations]);
useEffect(
() => () => {
dispatch(
setSelectedMicroagentItem({
microagent: null,
conversation: null,
}),
);
setSelectedMicroagentItem({
microagent: undefined,
conversation: undefined,
});
},
[],
[setSelectedMicroagentItem],
);
// Show loading only when both queries are loading

View File

@@ -1,17 +1,14 @@
import { useSelector } from "react-redux";
import { useTranslation } from "react-i18next";
import { I18nKey } from "#/i18n/declaration";
import { BrandButton } from "../settings/brand-button";
import { getProviderName, constructPullRequestUrl } from "#/utils/utils";
import { Provider } from "#/types/settings";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
export function MicroagentManagementReviewPr() {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useMicroagentManagementStore();
const { conversation } = selectedMicroagentItem ?? {};

View File

@@ -1,9 +1,8 @@
import { Tab, Tabs } from "@heroui/react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { MicroagentManagementRepositories } from "./microagent-management-repositories";
import { I18nKey } from "#/i18n/declaration";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
interface MicroagentManagementSidebarTabsProps {
isSearchLoading?: boolean;
@@ -15,7 +14,7 @@ export function MicroagentManagementSidebarTabs({
const { t } = useTranslation();
const { repositories, personalRepositories, organizationRepositories } =
useSelector((state: RootState) => state.microagentManagement);
useMicroagentManagementStore();
return (
<div className="flex w-full flex-col">

View File

@@ -1,5 +1,4 @@
import { useEffect, useState, useMemo } from "react";
import { useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import { Spinner } from "@heroui/react";
import { MicroagentManagementSidebarHeader } from "./microagent-management-sidebar-header";
@@ -7,11 +6,7 @@ import { MicroagentManagementSidebarTabs } from "./microagent-management-sidebar
import { useGitRepositories } from "#/hooks/query/use-git-repositories";
import { useSearchRepositories } from "#/hooks/query/use-search-repositories";
import { GitProviderDropdown } from "#/components/features/home/git-provider-dropdown";
import {
setPersonalRepositories,
setOrganizationRepositories,
setRepositories,
} from "#/state/microagent-management-slice";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { GitRepository } from "#/types/git";
import { Provider } from "#/types/settings";
import { cn } from "#/utils/utils";
@@ -35,7 +30,11 @@ export function MicroagentManagementSidebar({
const [searchQuery, setSearchQuery] = useState("");
const debouncedSearchQuery = useDebounce(searchQuery, 300);
const dispatch = useDispatch();
const {
setPersonalRepositories,
setOrganizationRepositories,
setRepositories,
} = useMicroagentManagementStore();
const { t } = useTranslation();
@@ -96,9 +95,9 @@ export function MicroagentManagementSidebar({
useEffect(() => {
if (!filteredRepositories?.length) {
dispatch(setPersonalRepositories([]));
dispatch(setOrganizationRepositories([]));
dispatch(setRepositories([]));
setPersonalRepositories([]);
setOrganizationRepositories([]);
setRepositories([]);
return;
}
@@ -121,10 +120,16 @@ export function MicroagentManagementSidebar({
}
});
dispatch(setPersonalRepositories(personalRepos));
dispatch(setOrganizationRepositories(organizationRepos));
dispatch(setRepositories(otherRepos));
}, [filteredRepositories, selectedProvider, dispatch]);
setPersonalRepositories(personalRepos);
setOrganizationRepositories(organizationRepos);
setRepositories(otherRepos);
}, [
filteredRepositories,
selectedProvider,
setPersonalRepositories,
setOrganizationRepositories,
setRepositories,
]);
// Handle scroll to bottom for pagination
const handleScroll = (event: React.UIEvent<HTMLDivElement>) => {

View File

@@ -1,12 +1,11 @@
import { useEffect, useState, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import { FaCircleInfo } from "react-icons/fa6";
import { ModalBackdrop } from "#/components/shared/modals/modal-backdrop";
import { ModalBody } from "#/components/shared/modals/modal-body";
import { BrandButton } from "../settings/brand-button";
import { I18nKey } from "#/i18n/declaration";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import XIcon from "#/icons/x.svg?react";
import { cn, extractRepositoryInfo } from "#/utils/utils";
import { BadgeInput } from "#/components/shared/inputs/badge-input";
@@ -32,13 +31,8 @@ export function MicroagentManagementUpsertMicroagentModal({
const [triggers, setTriggers] = useState<string[]>([]);
const [query, setQuery] = useState<string>("");
const { selectedRepository } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedRepository, selectedMicroagentItem } =
useMicroagentManagementStore();
const { microagent } = selectedMicroagentItem ?? {};

View File

@@ -1,6 +1,5 @@
import { useTranslation } from "react-i18next";
import { Spinner } from "@heroui/react";
import { useSelector } from "react-redux";
import Markdown from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkBreaks from "remark-breaks";
@@ -8,20 +7,15 @@ import { code } from "../markdown/code";
import { ul, ol } from "../markdown/list";
import { paragraph } from "../markdown/paragraph";
import { anchor } from "../markdown/anchor";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { useRepositoryMicroagentContent } from "#/hooks/query/use-repository-microagent-content";
import { I18nKey } from "#/i18n/declaration";
import { extractRepositoryInfo } from "#/utils/utils";
export function MicroagentManagementViewMicroagentContent() {
const { t } = useTranslation();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedRepository } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem, selectedRepository } =
useMicroagentManagementStore();
const { microagent } = selectedMicroagentItem ?? {};

View File

@@ -1,22 +1,16 @@
import { useSelector, useDispatch } from "react-redux";
import { useTranslation } from "react-i18next";
import { RootState } from "#/store";
import { BrandButton } from "../settings/brand-button";
import { getProviderName, constructMicroagentUrl } from "#/utils/utils";
import { I18nKey } from "#/i18n/declaration";
import { setUpdateMicroagentModalVisible } from "#/state/microagent-management-slice";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
export function MicroagentManagementViewMicroagentHeader() {
const { t } = useTranslation();
const dispatch = useDispatch();
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedRepository } = useSelector(
(state: RootState) => state.microagentManagement,
);
const {
selectedMicroagentItem,
selectedRepository,
setUpdateMicroagentModalVisible,
} = useMicroagentManagementStore();
const { microagent } = selectedMicroagentItem ?? {};
@@ -32,7 +26,7 @@ export function MicroagentManagementViewMicroagentHeader() {
);
const handleLearnSomethingNew = () => {
dispatch(setUpdateMicroagentModalVisible(true));
setUpdateMicroagentModalVisible(true);
};
return (

View File

@@ -1,16 +1,10 @@
import { useSelector } from "react-redux";
import { RootState } from "#/store";
import { useMicroagentManagementStore } from "#/state/microagent-management-store";
import { MicroagentManagementViewMicroagentHeader } from "./microagent-management-view-microagent-header";
import { MicroagentManagementViewMicroagentContent } from "./microagent-management-view-microagent-content";
export function MicroagentManagementViewMicroagent() {
const { selectedMicroagentItem } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedRepository } = useSelector(
(state: RootState) => state.microagentManagement,
);
const { selectedMicroagentItem, selectedRepository } =
useMicroagentManagementStore();
const { microagent } = selectedMicroagentItem ?? {};

View File

@@ -1,56 +0,0 @@
import { createSlice } from "@reduxjs/toolkit";
import { GitRepository } from "#/types/git";
import { IMicroagentItem } from "#/types/microagent-management";
export const microagentManagementSlice = createSlice({
name: "microagentManagement",
initialState: {
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
selectedRepository: null as GitRepository | null,
personalRepositories: [] as GitRepository[],
organizationRepositories: [] as GitRepository[],
repositories: [] as GitRepository[],
selectedMicroagentItem: null as IMicroagentItem | null,
learnThisRepoModalVisible: false,
},
reducers: {
setAddMicroagentModalVisible: (state, action) => {
state.addMicroagentModalVisible = action.payload;
},
setUpdateMicroagentModalVisible: (state, action) => {
state.updateMicroagentModalVisible = action.payload;
},
setSelectedRepository: (state, action) => {
state.selectedRepository = action.payload;
},
setPersonalRepositories: (state, action) => {
state.personalRepositories = action.payload;
},
setOrganizationRepositories: (state, action) => {
state.organizationRepositories = action.payload;
},
setRepositories: (state, action) => {
state.repositories = action.payload;
},
setSelectedMicroagentItem: (state, action) => {
state.selectedMicroagentItem = action.payload;
},
setLearnThisRepoModalVisible: (state, action) => {
state.learnThisRepoModalVisible = action.payload;
},
},
});
export const {
setAddMicroagentModalVisible,
setUpdateMicroagentModalVisible,
setSelectedRepository,
setPersonalRepositories,
setOrganizationRepositories,
setRepositories,
setSelectedMicroagentItem,
setLearnThisRepoModalVisible,
} = microagentManagementSlice.actions;
export default microagentManagementSlice.reducer;

View File

@@ -0,0 +1,76 @@
import { create } from "zustand";
import { GitRepository } from "#/types/git";
import { IMicroagentItem } from "#/types/microagent-management";
interface MicroagentManagementState {
// Modal visibility states
addMicroagentModalVisible: boolean;
updateMicroagentModalVisible: boolean;
learnThisRepoModalVisible: boolean;
// Repository states
selectedRepository: GitRepository | null;
personalRepositories: GitRepository[];
organizationRepositories: GitRepository[];
repositories: GitRepository[];
// Microagent states
selectedMicroagentItem: IMicroagentItem | null;
}
interface MicroagentManagementActions {
// Modal actions
setAddMicroagentModalVisible: (visible: boolean) => void;
setUpdateMicroagentModalVisible: (visible: boolean) => void;
setLearnThisRepoModalVisible: (visible: boolean) => void;
// Repository actions
setSelectedRepository: (repository: GitRepository | null) => void;
setPersonalRepositories: (repositories: GitRepository[]) => void;
setOrganizationRepositories: (repositories: GitRepository[]) => void;
setRepositories: (repositories: GitRepository[]) => void;
// Microagent actions
setSelectedMicroagentItem: (item: IMicroagentItem | null) => void;
}
type MicroagentManagementStore = MicroagentManagementState &
MicroagentManagementActions;
export const useMicroagentManagementStore = create<MicroagentManagementStore>(
(set) => ({
// Initial state
addMicroagentModalVisible: false,
updateMicroagentModalVisible: false,
learnThisRepoModalVisible: false,
selectedRepository: null,
personalRepositories: [],
organizationRepositories: [],
repositories: [],
selectedMicroagentItem: null,
// Actions
setAddMicroagentModalVisible: (visible: boolean) =>
set({ addMicroagentModalVisible: visible }),
setUpdateMicroagentModalVisible: (visible: boolean) =>
set({ updateMicroagentModalVisible: visible }),
setLearnThisRepoModalVisible: (visible: boolean) =>
set({ learnThisRepoModalVisible: visible }),
setSelectedRepository: (repository: GitRepository | null) =>
set({ selectedRepository: repository }),
setPersonalRepositories: (repositories: GitRepository[]) =>
set({ personalRepositories: repositories }),
setOrganizationRepositories: (repositories: GitRepository[]) =>
set({ organizationRepositories: repositories }),
setRepositories: (repositories: GitRepository[]) => set({ repositories }),
setSelectedMicroagentItem: (item: IMicroagentItem | null) =>
set({ selectedMicroagentItem: item }),
}),
);

View File

@@ -1,12 +1,10 @@
import { combineReducers, configureStore } from "@reduxjs/toolkit";
import agentReducer from "./state/agent-slice";
import { jupyterReducer } from "./state/jupyter-slice";
import microagentManagementReducer from "./state/microagent-management-slice";
export const rootReducer = combineReducers({
agent: agentReducer,
jupyter: jupyterReducer,
microagentManagement: microagentManagementReducer,
});
const store = configureStore({