diff --git a/autogpt_platform/backend/backend/api/features/executions/review/review_routes_test.py b/autogpt_platform/backend/backend/api/features/executions/review/review_routes_test.py index 9d1df5f999..c4eba0befc 100644 --- a/autogpt_platform/backend/backend/api/features/executions/review/review_routes_test.py +++ b/autogpt_platform/backend/backend/api/features/executions/review/review_routes_test.py @@ -55,7 +55,7 @@ def sample_pending_review(test_user_id: str) -> PendingHumanReviewModel: def test_get_pending_reviews_empty( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, snapshot: Snapshot, test_user_id: str, ) -> None: @@ -73,7 +73,7 @@ def test_get_pending_reviews_empty( def test_get_pending_reviews_with_data( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, snapshot: Snapshot, test_user_id: str, @@ -95,7 +95,7 @@ def test_get_pending_reviews_with_data( def test_get_pending_reviews_for_execution_success( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, snapshot: Snapshot, test_user_id: str, @@ -122,9 +122,8 @@ def test_get_pending_reviews_for_execution_success( assert data[0]["graph_exec_id"] == "test_graph_exec_456" -def test_get_pending_reviews_for_execution_access_denied( - mocker: pytest_mock.MockFixture, - test_user_id: str, +def test_get_pending_reviews_for_execution_not_available( + mocker: pytest_mock.MockerFixture, ) -> None: """Test access denied when user doesn't own the execution""" mock_get_graph_execution = mocker.patch( @@ -134,12 +133,12 @@ def test_get_pending_reviews_for_execution_access_denied( response = client.get("/api/review/execution/test_graph_exec_456") - assert response.status_code == 403 - assert "Access denied" in response.json()["detail"] + assert response.status_code == 404 + assert "not found" in response.json()["detail"] def test_process_review_action_approve_success( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, test_user_id: str, ) -> None: @@ -203,7 +202,7 @@ def test_process_review_action_approve_success( def test_process_review_action_reject_success( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, test_user_id: str, ) -> None: @@ -263,7 +262,7 @@ def test_process_review_action_reject_success( def test_process_review_action_mixed_success( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, test_user_id: str, ) -> None: @@ -370,7 +369,7 @@ def test_process_review_action_mixed_success( def test_process_review_action_empty_request( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, test_user_id: str, ) -> None: """Test error when no reviews provided""" @@ -387,7 +386,7 @@ def test_process_review_action_empty_request( def test_process_review_action_review_not_found( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, test_user_id: str, ) -> None: """Test error when review is not found""" @@ -423,7 +422,7 @@ def test_process_review_action_review_not_found( def test_process_review_action_partial_failure( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, test_user_id: str, ) -> None: @@ -457,7 +456,7 @@ def test_process_review_action_partial_failure( def test_process_review_action_invalid_node_exec_id( - mocker: pytest_mock.MockFixture, + mocker: pytest_mock.MockerFixture, sample_pending_review: PendingHumanReviewModel, test_user_id: str, ) -> None: diff --git a/autogpt_platform/backend/backend/api/features/executions/review/routes.py b/autogpt_platform/backend/backend/api/features/executions/review/routes.py index 4aa4fac49b..88646046da 100644 --- a/autogpt_platform/backend/backend/api/features/executions/review/routes.py +++ b/autogpt_platform/backend/backend/api/features/executions/review/routes.py @@ -67,8 +67,7 @@ async def list_pending_reviews( response_model=List[PendingHumanReviewModel], responses={ 200: {"description": "List of pending reviews for the execution"}, - 400: {"description": "Invalid graph execution ID"}, - 403: {"description": "Access denied to graph execution"}, + 404: {"description": "Graph execution not found"}, 500: {"description": "Server error", "content": {"application/json": {}}}, }, ) @@ -91,7 +90,7 @@ async def list_pending_reviews_for_execution( Raises: HTTPException: - - 403: If user doesn't own the graph execution + - 404: If the graph execution doesn't exist or isn't owned by this user - 500: If authentication fails or database error occurs Note: @@ -105,8 +104,8 @@ async def list_pending_reviews_for_execution( ) if not graph_exec: raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Access denied to graph execution", + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Graph execution #{graph_exec_id} not found", ) return await get_pending_reviews_for_execution(graph_exec_id, user_id) diff --git a/autogpt_platform/backend/backend/api/features/store/routes.py b/autogpt_platform/backend/backend/api/features/store/routes.py index 6a9bb05291..7d4db50d3f 100644 --- a/autogpt_platform/backend/backend/api/features/store/routes.py +++ b/autogpt_platform/backend/backend/api/features/store/routes.py @@ -173,7 +173,9 @@ async def get_agent(username: str, agent_name: str): tags=["store"], dependencies=[fastapi.Security(autogpt_libs.auth.requires_user)], ) -async def get_graph_meta_by_store_listing_version_id(store_listing_version_id: str): +async def get_graph_meta_by_store_listing_version_id( + store_listing_version_id: str, +) -> backend.data.graph.GraphMeta: """ Get Agent Graph from Store Listing Version ID. """ diff --git a/autogpt_platform/frontend/orval.config.ts b/autogpt_platform/frontend/orval.config.ts index de305c1acc..dff857e1b6 100644 --- a/autogpt_platform/frontend/orval.config.ts +++ b/autogpt_platform/frontend/orval.config.ts @@ -41,6 +41,12 @@ export default defineConfig({ useInfiniteQueryParam: "page", }, }, + "getV2List presets": { + query: { + useInfinite: true, + useInfiniteQueryParam: "page", + }, + }, "getV1List graph executions": { query: { useInfinite: true, diff --git a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx index 58960a0cf6..30e1b67090 100644 --- a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx +++ b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/page.tsx @@ -25,7 +25,7 @@ export default function Page() { ready, error, showInput, - agent, + agentGraph, onboarding, storeAgent, runningAgent, @@ -76,19 +76,19 @@ export default function Page() { Input - {Object.entries(agent?.input_schema.properties || {}).map( - ([key, inputSubSchema]) => ( - handleSetAgentInput(key, value)} - /> - ), - )} + {Object.entries( + agentGraph?.input_schema.properties || {}, + ).map(([key, inputSubSchema]) => ( + handleSetAgentInput(key, value)} + /> + ))} ) || undefined @@ -104,7 +104,7 @@ export default function Page() { className="mt-8 w-[136px]" loading={runningAgent} disabled={isRunDisabled({ - agent, + agent: agentGraph, isRunning: runningAgent, agentInputs: (onboarding.state?.agentInput as unknown as InputValues) || diff --git a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/useOnboardingRunStep.tsx b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/useOnboardingRunStep.tsx index 37538a2191..f143c89d44 100644 --- a/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/useOnboardingRunStep.tsx +++ b/autogpt_platform/frontend/src/app/(no-navbar)/onboarding/5-run/useOnboardingRunStep.tsx @@ -1,6 +1,3 @@ -import { CredentialsMetaInput } from "@/app/api/__generated__/models/credentialsMetaInput"; -import { GraphMeta } from "@/app/api/__generated__/models/graphMeta"; -import { StoreAgentDetails } from "@/app/api/__generated__/models/storeAgentDetails"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { useBackendAPI } from "@/lib/autogpt-server-api/context"; import { useOnboarding } from "@/providers/onboarding/onboarding-provider"; @@ -8,20 +5,19 @@ import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { computeInitialAgentInputs } from "./helpers"; import { InputValues } from "./types"; +import { okData, resolveResponse } from "@/app/api/helpers"; +import { postV2AddMarketplaceAgent } from "@/app/api/__generated__/endpoints/library/library"; import { useGetV2GetAgentByVersion, useGetV2GetAgentGraph, } from "@/app/api/__generated__/endpoints/store/store"; -import { resolveResponse } from "@/app/api/helpers"; -import { postV2AddMarketplaceAgent } from "@/app/api/__generated__/endpoints/library/library"; +import { CredentialsMetaInput } from "@/app/api/__generated__/models/credentialsMetaInput"; import { GraphID } from "@/lib/autogpt-server-api"; export function useOnboardingRunStep() { const onboarding = useOnboarding(undefined, "AGENT_CHOICE"); const [showInput, setShowInput] = useState(false); - const [agent, setAgent] = useState(null); - const [storeAgent, setStoreAgent] = useState(null); const [runningAgent, setRunningAgent] = useState(false); const [inputCredentials, setInputCredentials] = useState< @@ -38,12 +34,26 @@ export function useOnboardingRunStep() { const currentAgentVersion = onboarding.state?.selectedStoreListingVersionId ?? ""; - const storeAgentQuery = useGetV2GetAgentByVersion(currentAgentVersion, { - query: { enabled: !!currentAgentVersion }, + const { + data: storeAgent, + error: storeAgentQueryError, + isSuccess: storeAgentQueryIsSuccess, + } = useGetV2GetAgentByVersion(currentAgentVersion, { + query: { + enabled: !!currentAgentVersion, + select: okData, + }, }); - const graphMetaQuery = useGetV2GetAgentGraph(currentAgentVersion, { - query: { enabled: !!currentAgentVersion }, + const { + data: agentGraphMeta, + error: agentGraphQueryError, + isSuccess: agentGraphQueryIsSuccess, + } = useGetV2GetAgentGraph(currentAgentVersion, { + query: { + enabled: !!currentAgentVersion, + select: okData, + }, }); useEffect(() => { @@ -51,29 +61,15 @@ export function useOnboardingRunStep() { }, []); useEffect(() => { - if (storeAgentQuery.data && storeAgentQuery.data.status === 200) { - setStoreAgent(storeAgentQuery.data.data); - } - }, [storeAgentQuery.data]); - - useEffect(() => { - if ( - graphMetaQuery.data && - graphMetaQuery.data.status === 200 && - onboarding.state - ) { - const graphMeta = graphMetaQuery.data.data as GraphMeta; - - setAgent(graphMeta); - - const update = computeInitialAgentInputs( - graphMeta, + if (agentGraphMeta && onboarding.state) { + const initialAgentInputs = computeInitialAgentInputs( + agentGraphMeta, (onboarding.state.agentInput as unknown as InputValues) || null, ); - onboarding.updateState({ agentInput: update }); + onboarding.updateState({ agentInput: initialAgentInputs }); } - }, [graphMetaQuery.data]); + }, [agentGraphMeta]); function handleNewRun() { if (!onboarding.state) return; @@ -95,7 +91,7 @@ export function useOnboardingRunStep() { } async function handleRunAgent() { - if (!agent || !storeAgent || !onboarding.state) { + if (!agentGraphMeta || !storeAgent || !onboarding.state) { toast({ title: "Error getting agent", description: @@ -142,12 +138,12 @@ export function useOnboardingRunStep() { } return { - ready: graphMetaQuery.isSuccess && storeAgentQuery.isSuccess, - error: graphMetaQuery.error || storeAgentQuery.error, - agent, + ready: agentGraphQueryIsSuccess && storeAgentQueryIsSuccess, + error: agentGraphQueryError || storeAgentQueryError, + agentGraph: agentGraphMeta || null, onboarding, showInput, - storeAgent, + storeAgent: storeAgent || null, runningAgent, credentialsValid, credentialsLoaded, diff --git a/autogpt_platform/frontend/src/app/(no-navbar)/share/[token]/page.tsx b/autogpt_platform/frontend/src/app/(no-navbar)/share/[token]/page.tsx index c24f9e11a3..1c37c6c72f 100644 --- a/autogpt_platform/frontend/src/app/(no-navbar)/share/[token]/page.tsx +++ b/autogpt_platform/frontend/src/app/(no-navbar)/share/[token]/page.tsx @@ -1,6 +1,7 @@ "use client"; import { RunOutputs } from "@/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/RunOutputs"; +import { okData } from "@/app/api/helpers"; import { useGetV1GetSharedExecution } from "@/app/api/__generated__/endpoints/default/default"; import { Card, @@ -17,12 +18,11 @@ export default function SharePage() { const token = params.token as string; const { - data: response, + data: executionData, isLoading: loading, error, - } = useGetV1GetSharedExecution(token); + } = useGetV1GetSharedExecution(token, { query: { select: okData } }); - const executionData = response?.status === 200 ? response.data : undefined; const is404 = !loading && !executionData; if (loading) { diff --git a/autogpt_platform/frontend/src/app/(platform)/admin/execution-analytics/components/ExecutionAnalyticsForm.tsx b/autogpt_platform/frontend/src/app/(platform)/admin/execution-analytics/components/ExecutionAnalyticsForm.tsx index fd77628140..5aced56090 100644 --- a/autogpt_platform/frontend/src/app/(platform)/admin/execution-analytics/components/ExecutionAnalyticsForm.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/admin/execution-analytics/components/ExecutionAnalyticsForm.tsx @@ -41,6 +41,7 @@ interface FormData extends Omit { // All other fields use the generated types as-is } import { AnalyticsResultsTable } from "./AnalyticsResultsTable"; +import { okData } from "@/app/api/helpers"; export function ExecutionAnalyticsForm() { const [results, setResults] = useState( @@ -178,7 +179,7 @@ export function ExecutionAnalyticsForm() { data: config, isLoading: configLoading, error: configError, - } = useGetV2GetExecutionAnalyticsConfiguration(); + } = useGetV2GetExecutionAnalyticsConfiguration({ query: { select: okData } }); const generateAnalytics = usePostV2GenerateExecutionAnalytics({ mutation: { @@ -231,10 +232,10 @@ export function ExecutionAnalyticsForm() { // Update form defaults when config loads useEffect(() => { - if (config?.data && config.status === 200 && !formData.model_name) { + if (config && !formData.model_name) { setFormData((prev) => ({ ...prev, - model_name: config.data.recommended_model, + model_name: config.recommended_model, })); } }, [config, formData.model_name]); @@ -307,7 +308,7 @@ export function ExecutionAnalyticsForm() { } // Show error state if config fails to load - if (configError || !config?.data || config.status !== 200) { + if (configError || !config) { return (
Failed to load configuration
@@ -315,8 +316,6 @@ export function ExecutionAnalyticsForm() { ); } - const configData = config.data; - return (
@@ -382,7 +381,7 @@ export function ExecutionAnalyticsForm() { - {configData.available_models.map((model) => ( + {config.available_models.map((model) => ( {model.label} @@ -442,7 +441,7 @@ export function ExecutionAnalyticsForm() { onChange={(e) => handleInputChange("system_prompt", e.target.value) } - placeholder={configData.default_system_prompt} + placeholder={config.default_system_prompt} rows={6} className="resize-y" /> @@ -463,7 +462,7 @@ export function ExecutionAnalyticsForm() { onChange={(e) => handleInputChange("user_prompt", e.target.value) } - placeholder={configData.default_user_prompt} + placeholder={config.default_user_prompt} rows={8} className="resize-y" /> @@ -490,7 +489,7 @@ export function ExecutionAnalyticsForm() { onClick={() => { handleInputChange( "system_prompt", - configData.default_system_prompt, + config.default_system_prompt, ); }} > @@ -503,7 +502,7 @@ export function ExecutionAnalyticsForm() { onClick={() => { handleInputChange( "user_prompt", - configData.default_user_prompt, + config.default_user_prompt, ); }} > diff --git a/autogpt_platform/frontend/src/app/(platform)/auth/integrations/setup-wizard/page.tsx b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/setup-wizard/page.tsx index 5163c46d5b..3372772c89 100644 --- a/autogpt_platform/frontend/src/app/(platform)/auth/integrations/setup-wizard/page.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/auth/integrations/setup-wizard/page.tsx @@ -17,7 +17,6 @@ import type { import { CheckIcon, CircleIcon } from "@phosphor-icons/react"; import { useGetOauthGetOauthAppInfo } from "@/app/api/__generated__/endpoints/oauth/oauth"; import { okData } from "@/app/api/helpers"; -import { OAuthApplicationPublicInfo } from "@/app/api/__generated__/models/oAuthApplicationPublicInfo"; // All credential types - we accept any type of credential const ALL_CREDENTIAL_TYPES: CredentialsType[] = [ @@ -107,7 +106,7 @@ export default function IntegrationSetupWizardPage() { const state = searchParams.get("state"); const { data: appInfo } = useGetOauthGetOauthAppInfo(clientID || "", { - query: { enabled: !!clientID, select: okData }, + query: { enabled: !!clientID, select: okData }, }); // Parse providers from base64-encoded JSON diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/CronSchedulerDialog/useCronSchedulerDialog.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/CronSchedulerDialog/useCronSchedulerDialog.ts index 4d5f8bf254..1abfabbdba 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/CronSchedulerDialog/useCronSchedulerDialog.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/BuilderActions/components/CronSchedulerDialog/useCronSchedulerDialog.ts @@ -1,6 +1,6 @@ -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; import { usePostV1CreateExecutionSchedule } from "@/app/api/__generated__/endpoints/schedules/schedules"; import { useToast } from "@/components/molecules/Toast/use-toast"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { getTimezoneDisplayName } from "@/lib/timezone-utils"; import { parseAsInteger, parseAsString, useQueryStates } from "nuqs"; import { useEffect, useState } from "react"; @@ -28,11 +28,7 @@ export const useCronSchedulerDialog = ({ flowExecutionID: parseAsString, }); - const { data: userTimezone } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : undefined), - }, - }); + const userTimezone = useUserTimezone(); const timezoneDisplay = getTimezoneDisplayName(userTimezone || "UTC"); const { mutateAsync: createSchedule, isPending: isCreatingSchedule } = diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx index d312fd487d..c9cf5296c6 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/FlowEditor/Flow/Flow.tsx @@ -17,7 +17,6 @@ import { FloatingReviewsPanel } from "@/components/organisms/FloatingReviewsPane import { parseAsString, useQueryStates } from "nuqs"; import { CustomControls } from "./components/CustomControl"; import { useGetV1GetSpecificGraph } from "@/app/api/__generated__/endpoints/graphs/graphs"; -import { GraphModel } from "@/app/api/__generated__/models/graphModel"; import { okData } from "@/app/api/helpers"; import { TriggerAgentBanner } from "./components/TriggerAgentBanner"; import { resolveCollisions } from "./helpers/resolve-collision"; @@ -34,7 +33,7 @@ export const Flow = () => { {}, { query: { - select: okData, + select: okData, enabled: !!flowID, }, }, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx index 71888b62ee..de339431e8 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/BlockMenuSearch.tsx @@ -14,7 +14,7 @@ import { NoSearchResult } from "../NoSearchResult"; export const BlockMenuSearch = () => { const { - allSearchData, + searchResults, isFetchingNextPage, fetchNextPage, hasNextPage, @@ -39,7 +39,7 @@ export const BlockMenuSearch = () => { ); } - if (allSearchData.length === 0) { + if (searchResults.length === 0) { return ; } @@ -53,7 +53,7 @@ export const BlockMenuSearch = () => { loader={} className="space-y-2.5" > - {allSearchData.map((item: SearchResponseItemsItem, index: number) => { + {searchResults.map((item: SearchResponseItemsItem, index: number) => { const { type, data } = getSearchItemType(item); // backend give support to these 3 types only [right now] - we need to give support to integration and ai agent types in follow up PRs switch (type) { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts index 3eb14d3ca9..beff80a984 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/BlockMenuSearch/useBlockMenuSearch.ts @@ -1,19 +1,25 @@ -import { useBlockMenuStore } from "../../../../stores/blockMenuStore"; -import { useGetV2BuilderSearchInfinite } from "@/app/api/__generated__/endpoints/store/store"; -import { SearchResponse } from "@/app/api/__generated__/models/searchResponse"; import { useCallback, useEffect, useState } from "react"; +import { useBlockMenuStore } from "@/app/(platform)/build/stores/blockMenuStore"; import { useAddAgentToBuilder } from "../hooks/useAddAgentToBuilder"; -import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; -import { getV2GetSpecificAgent } from "@/app/api/__generated__/endpoints/store/store"; +import { + getPaginationNextPageNumber, + okData, + unpaginate, +} from "@/app/api/helpers"; +import { + getGetV2GetBuilderItemCountsQueryKey, + getGetV2GetBuilderSuggestionsQueryKey, +} from "@/app/api/__generated__/endpoints/default/default"; import { getGetV2ListLibraryAgentsQueryKey, getV2GetLibraryAgent, usePostV2AddMarketplaceAgent, } from "@/app/api/__generated__/endpoints/library/library"; import { - getGetV2GetBuilderItemCountsQueryKey, - getGetV2GetBuilderSuggestionsQueryKey, -} from "@/app/api/__generated__/endpoints/default/default"; + getV2GetSpecificAgent, + useGetV2BuilderSearchInfinite, +} from "@/app/api/__generated__/endpoints/store/store"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { getQueryClient } from "@/lib/react-query/queryClient"; import { useToast } from "@/components/molecules/Toast/use-toast"; import * as Sentry from "@sentry/nextjs"; @@ -40,7 +46,7 @@ export const useBlockMenuSearch = () => { >(null); const { - data: searchData, + data: searchQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -53,18 +59,7 @@ export const useBlockMenuSearch = () => { search_id: searchId, }, { - query: { - getNextPageParam: (lastPage) => { - const response = lastPage.data as SearchResponse; - const { pagination } = response; - if (!pagination) { - return undefined; - } - - const { current_page, total_pages } = pagination; - return current_page < total_pages ? current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); @@ -93,16 +88,15 @@ export const useBlockMenuSearch = () => { }); useEffect(() => { - if (!searchData?.pages?.length) { + if (!searchQueryData?.pages?.length) { return; } - const latestPage = searchData.pages[searchData.pages.length - 1]; - const response = latestPage?.data as SearchResponse; - if (response?.search_id && response.search_id !== searchId) { - setSearchId(response.search_id); + const lastPage = okData(searchQueryData.pages.at(-1)); + if (lastPage?.search_id && lastPage.search_id !== searchId) { + setSearchId(lastPage.search_id); } - }, [searchData, searchId, setSearchId]); + }, [searchQueryData, searchId, setSearchId]); useEffect(() => { if (searchId && !searchQuery) { @@ -110,11 +104,9 @@ export const useBlockMenuSearch = () => { } }, [resetSearchSession, searchId, searchQuery]); - const allSearchData = - searchData?.pages?.flatMap((page) => { - const response = page.data as SearchResponse; - return response.items; - }) ?? []; + const searchResults = searchQueryData + ? unpaginate(searchQueryData, "items") + : []; const handleAddLibraryAgent = async (agent: LibraryAgent) => { setAddingLibraryAgentId(agent.id); @@ -177,7 +169,7 @@ export const useBlockMenuSearch = () => { }; return { - allSearchData, + searchResults, isFetchingNextPage, fetchNextPage, hasNextPage, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts index 678f903936..c6dcd61e36 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/IntegrationBlocks/useIntegrationBlocks.ts @@ -1,6 +1,10 @@ +import { + getPaginatedTotalCount, + getPaginationNextPageNumber, + unpaginate, +} from "@/app/api/helpers"; import { useGetV2GetBuilderBlocksInfinite } from "@/app/api/__generated__/endpoints/default/default"; -import { BlockResponse } from "@/app/api/__generated__/models/blockResponse"; -import { useBlockMenuStore } from "../../../../stores/blockMenuStore"; +import { useBlockMenuStore } from "@/app/(platform)/build/stores/blockMenuStore"; const PAGE_SIZE = 10; @@ -8,7 +12,7 @@ export const useIntegrationBlocks = () => { const { integration } = useBlockMenuStore(); const { - data: blocks, + data: blocksQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -22,30 +26,16 @@ export const useIntegrationBlocks = () => { provider: integration, }, { - query: { - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as BlockResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allBlocks = - blocks?.pages?.flatMap((page) => { - const response = page.data as BlockResponse; - return response.blocks; - }) ?? []; + const allBlocks = blocksQueryData + ? unpaginate(blocksQueryData, "blocks") + : []; + const totalBlocks = getPaginatedTotalCount(blocksQueryData); - const totalBlocks = blocks?.pages[0] - ? (blocks.pages[0].data as BlockResponse).pagination.total_items - : 0; - - const status = blocks?.pages[0]?.status; + const status = blocksQueryData?.pages[0]?.status; return { allBlocks, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MarketplaceAgentsContent/useMarketplaceAgentsContent.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MarketplaceAgentsContent/useMarketplaceAgentsContent.ts index ff9b70b79a..c45f36ae87 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MarketplaceAgentsContent/useMarketplaceAgentsContent.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MarketplaceAgentsContent/useMarketplaceAgentsContent.ts @@ -1,3 +1,4 @@ +import { getPaginationNextPageNumber, unpaginate } from "@/app/api/helpers"; import { getGetV2GetBuilderItemCountsQueryKey } from "@/app/api/__generated__/endpoints/default/default"; import { getGetV2ListLibraryAgentsQueryKey, @@ -8,13 +9,12 @@ import { getV2GetSpecificAgent, useGetV2ListStoreAgentsInfinite, } from "@/app/api/__generated__/endpoints/store/store"; +import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { useToast } from "@/components/molecules/Toast/use-toast"; -import { StoreAgentsResponse } from "@/lib/autogpt-server-api"; import { getQueryClient } from "@/lib/react-query/queryClient"; import * as Sentry from "@sentry/nextjs"; import { useState } from "react"; import { useAddAgentToBuilder } from "../hooks/useAddAgentToBuilder"; -import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; export const useMarketplaceAgentsContent = () => { const { toast } = useToast(); @@ -22,7 +22,7 @@ export const useMarketplaceAgentsContent = () => { const { addAgentToBuilder } = useAddAgentToBuilder(); const { - data: listStoreAgents, + data: storeAgentsQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -36,26 +36,14 @@ export const useMarketplaceAgentsContent = () => { page_size: 10, }, { - query: { - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as StoreAgentsResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allAgents = - listStoreAgents?.pages?.flatMap((page) => { - const response = page.data as StoreAgentsResponse; - return response.agents; - }) ?? []; - - const status = listStoreAgents?.pages[0]?.status; + const allAgents = storeAgentsQueryData + ? unpaginate(storeAgentsQueryData, "agents") + : []; + const status = storeAgentsQueryData?.pages[0]?.status; const { mutateAsync: addMarketplaceAgent } = usePostV2AddMarketplaceAgent({ mutation: { diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MyAgentsContent/useMyAgentsContent.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MyAgentsContent/useMyAgentsContent.ts index 88645393d7..5ce19afe96 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MyAgentsContent/useMyAgentsContent.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/MyAgentsContent/useMyAgentsContent.ts @@ -1,5 +1,5 @@ +import { getPaginationNextPageNumber, unpaginate } from "@/app/api/helpers"; import { useGetV2ListLibraryAgentsInfinite } from "@/app/api/__generated__/endpoints/library/library"; -import { LibraryAgentResponse } from "@/app/api/__generated__/models/libraryAgentResponse"; import { useState } from "react"; import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { useAddAgentToBuilder } from "../hooks/useAddAgentToBuilder"; @@ -12,7 +12,7 @@ export const useMyAgentsContent = () => { const { toast } = useToast(); const { - data: agents, + data: agentsQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -26,26 +26,14 @@ export const useMyAgentsContent = () => { page_size: 10, }, { - query: { - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as LibraryAgentResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allAgents = - agents?.pages?.flatMap((page) => { - const response = page.data as LibraryAgentResponse; - return response.agents; - }) ?? []; - - const status = agents?.pages[0]?.status; + const allAgents = agentsQueryData + ? unpaginate(agentsQueryData, "agents") + : []; + const status = agentsQueryData?.pages[0]?.status; const handleAddBlock = async (agent: LibraryAgent) => { setSelectedAgentId(agent.id); diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedBlocksContent/usePaginatedBlocks.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedBlocksContent/usePaginatedBlocks.ts index 5348998021..b44fb871f3 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedBlocksContent/usePaginatedBlocks.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedBlocksContent/usePaginatedBlocks.ts @@ -1,5 +1,5 @@ +import { getPaginationNextPageNumber, unpaginate } from "@/app/api/helpers"; import { useGetV2GetBuilderBlocksInfinite } from "@/app/api/__generated__/endpoints/default/default"; -import { BlockResponse } from "@/app/api/__generated__/models/blockResponse"; interface UsePaginatedBlocksProps { type?: "all" | "input" | "action" | "output" | null; @@ -8,7 +8,7 @@ interface UsePaginatedBlocksProps { const PAGE_SIZE = 10; export const usePaginatedBlocks = ({ type }: UsePaginatedBlocksProps) => { const { - data: blocks, + data: blocksQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -22,26 +22,14 @@ export const usePaginatedBlocks = ({ type }: UsePaginatedBlocksProps) => { type, }, { - query: { - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as BlockResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allBlocks = - blocks?.pages?.flatMap((page) => { - const response = page.data as BlockResponse; - return response.blocks; - }) ?? []; - - const status = blocks?.pages[0]?.status; + const allBlocks = blocksQueryData + ? unpaginate(blocksQueryData, "blocks") + : []; + const status = blocksQueryData?.pages[0]?.status; return { allBlocks, diff --git a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedIntegrationList/usePaginatedIntegrationList.ts b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedIntegrationList/usePaginatedIntegrationList.ts index cf84ed94eb..3462b8f619 100644 --- a/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedIntegrationList/usePaginatedIntegrationList.ts +++ b/autogpt_platform/frontend/src/app/(platform)/build/components/NewControlPanel/NewBlockMenu/PaginatedIntegrationList/usePaginatedIntegrationList.ts @@ -1,11 +1,11 @@ +import { getPaginationNextPageNumber, unpaginate } from "@/app/api/helpers"; import { useGetV2GetBuilderIntegrationProvidersInfinite } from "@/app/api/__generated__/endpoints/default/default"; -import { ProviderResponse } from "@/app/api/__generated__/models/providerResponse"; const PAGE_SIZE = 10; export const usePaginatedIntegrationList = () => { const { - data: providers, + data: providersQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -18,26 +18,14 @@ export const usePaginatedIntegrationList = () => { page_size: PAGE_SIZE, }, { - query: { - getNextPageParam: (lastPage: any) => { - const pagination = (lastPage.data as ProviderResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allProviders = - providers?.pages?.flatMap((page: any) => { - const response = page.data as ProviderResponse; - return response.providers; - }) ?? []; - - const status = providers?.pages[0]?.status; + const allProviders = providersQueryData + ? unpaginate(providersQueryData, "providers") + : []; + const status = providersQueryData?.pages[0]?.status; return { allProviders, diff --git a/autogpt_platform/frontend/src/app/(platform)/chat/useChatSession.ts b/autogpt_platform/frontend/src/app/(platform)/chat/useChatSession.ts index 0a350f98bb..99f4efc093 100644 --- a/autogpt_platform/frontend/src/app/(platform)/chat/useChatSession.ts +++ b/autogpt_platform/frontend/src/app/(platform)/chat/useChatSession.ts @@ -11,6 +11,7 @@ import { import type { SessionDetailResponse } from "@/app/api/__generated__/models/sessionDetailResponse"; import { storage, Key } from "@/services/storage/local-storage"; import { isValidUUID } from "@/app/(platform)/chat/helpers"; +import { okData } from "@/app/api/helpers"; interface UseChatSessionArgs { urlSessionId?: string | null; @@ -70,6 +71,7 @@ export function useChatSession({ } = useGetV2GetSession(sessionId || "", { query: { enabled: !!sessionId, + select: okData, staleTime: Infinity, // Never mark as stale refetchOnMount: false, // Don't refetch on component mount refetchOnWindowFocus: false, // Don't refetch when window regains focus @@ -81,9 +83,8 @@ export function useChatSession({ const { mutateAsync: claimSessionMutation } = usePatchV2SessionAssignUser(); const session = useMemo(() => { - if (sessionData?.status === 200) { - return sessionData.data; - } + if (sessionData) return sessionData; + if (sessionId && justCreatedSessionIdRef.current === sessionId) { return { id: sessionId, diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/ScheduleAgentModal/components/TimezoneNotice/TimezoneNotice.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/ScheduleAgentModal/components/TimezoneNotice/TimezoneNotice.tsx index d5d7c011a6..97ee4605f2 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/ScheduleAgentModal/components/TimezoneNotice/TimezoneNotice.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/modals/ScheduleAgentModal/components/TimezoneNotice/TimezoneNotice.tsx @@ -1,15 +1,11 @@ -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { getTimezoneDisplayName } from "@/lib/timezone-utils"; import { InfoIcon } from "@phosphor-icons/react"; export function TimezoneNotice() { - const { data: userTimezone, isSuccess } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : undefined), - }, - }); + const userTimezone = useUserTimezone(); - if (!isSuccess) { + if (!userTimezone) { return null; } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AgentActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AgentActionsDropdown.tsx index e94878f070..834173cba4 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AgentActionsDropdown.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/AgentActionsDropdown.tsx @@ -1,7 +1,7 @@ "use client"; import { - getGetV1ListGraphExecutionsInfiniteQueryOptions, + getGetV1ListGraphExecutionsQueryKey, getV1GetGraphVersion, useDeleteV1DeleteGraphExecution, } from "@/app/api/__generated__/endpoints/graphs/graphs"; @@ -127,9 +127,7 @@ export function AgentActionsDropdown({ toast({ title: "Task deleted" }); await queryClient.refetchQueries({ - queryKey: - getGetV1ListGraphExecutionsInfiniteQueryOptions(agentGraphId) - .queryKey, + queryKey: getGetV1ListGraphExecutionsQueryKey(agentGraphId), }); if (onClearSelectedRun) onClearSelectedRun(); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/useSelectedRunActions.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/useSelectedRunActions.ts index 03fc0b4ae8..9bcfd9d964 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/useSelectedRunActions.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/components/SelectedRunActions/useSelectedRunActions.ts @@ -1,7 +1,7 @@ "use client"; import { - getGetV1ListGraphExecutionsInfiniteQueryOptions, + getGetV1ListGraphExecutionsQueryKey, usePostV1ExecuteGraphAgent, usePostV1StopGraphExecution, } from "@/app/api/__generated__/endpoints/graphs/graphs"; @@ -11,6 +11,7 @@ import { } from "@/app/api/__generated__/endpoints/presets/presets"; import type { GraphExecution } from "@/app/api/__generated__/models/graphExecution"; import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import { okData } from "@/app/api/helpers"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { useQueryClient } from "@tanstack/react-query"; import { useState } from "react"; @@ -58,9 +59,7 @@ export function useSelectedRunActions({ toast({ title: "Run stopped" }); await queryClient.invalidateQueries({ - queryKey: - getGetV1ListGraphExecutionsInfiniteQueryOptions(agentGraphId) - .queryKey, + queryKey: getGetV1ListGraphExecutionsQueryKey(agentGraphId), }); } catch (error: unknown) { toast({ @@ -97,12 +96,10 @@ export function useSelectedRunActions({ }, }); - const newRunId = res?.status === 200 ? (res?.data?.id ?? "") : ""; + const newRunId = okData(res)?.id; await queryClient.invalidateQueries({ - queryKey: - getGetV1ListGraphExecutionsInfiniteQueryOptions(agentGraphId) - .queryKey, + queryKey: getGetV1ListGraphExecutionsQueryKey(agentGraphId), }); if (newRunId && onSelectRun) onSelectRun(newRunId); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/useSelectedRunView.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/useSelectedRunView.ts index 342241ef89..e3e035cea0 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/useSelectedRunView.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedRunView/useSelectedRunView.ts @@ -3,14 +3,12 @@ import { useGetV1GetExecutionDetails } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { useGetV2GetASpecificPreset } from "@/app/api/__generated__/endpoints/presets/presets"; import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; -import type { GetV1GetExecutionDetails200 } from "@/app/api/__generated__/models/getV1GetExecutionDetails200"; -import type { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import { okData } from "@/app/api/helpers"; export function useSelectedRunView(graphId: string, runId: string) { - const query = useGetV1GetExecutionDetails(graphId, runId, { + const executionQuery = useGetV1GetExecutionDetails(graphId, runId, { query: { - refetchInterval: (q: any) => { + refetchInterval: (q) => { const isSuccess = q.state.data?.status === 200; if (!isSuccess) return false; @@ -33,22 +31,15 @@ export function useSelectedRunView(graphId: string, runId: string) { }, }); - const status = query.data?.status; + const run = okData(executionQuery.data); + const status = executionQuery.data?.status; - const run: GetV1GetExecutionDetails200 | undefined = - status === 200 - ? (query.data?.data as GetV1GetExecutionDetails200) - : undefined; - - const presetId = - run && "preset_id" in run && run.preset_id - ? (run.preset_id as string) - : undefined; + const presetId = run?.preset_id || undefined; const presetQuery = useGetV2GetASpecificPreset(presetId || "", { query: { enabled: !!presetId, - select: (res) => okData(res), + select: okData, }, }); @@ -60,8 +51,8 @@ export function useSelectedRunView(graphId: string, runId: string) { return { run, preset: presetQuery.data, - isLoading: query.isLoading || presetQuery.isLoading, - responseError: query.error || presetQuery.error, + isLoading: executionQuery.isLoading || presetQuery.isLoading, + responseError: executionQuery.error || presetQuery.error, httpError, } as const; } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx index 0672ddc033..678f711097 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/SelectedScheduleView.tsx @@ -1,12 +1,12 @@ "use client"; -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner"; import { Text } from "@/components/atoms/Text/Text"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { humanizeCronExpression } from "@/lib/cron-expression-utils"; import { isLargeScreen, useBreakpoint } from "@/lib/hooks/useBreakpoint"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { formatInTimezone, getTimezoneDisplayName } from "@/lib/timezone-utils"; import { AgentInputsReadOnly } from "../../modals/AgentInputsReadOnly/AgentInputsReadOnly"; import { LoadingSelectedContent } from "../LoadingSelectedContent"; @@ -36,11 +36,7 @@ export function SelectedScheduleView({ scheduleId, ); - const { data: userTzRes } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : undefined), - }, - }); + const userTimezone = useUserTimezone(); const breakpoint = useBreakpoint(); const isLgScreenUp = isLargeScreen(breakpoint); @@ -90,7 +86,7 @@ export function SelectedScheduleView({ run={undefined} scheduleRecurrence={ schedule - ? `${humanizeCronExpression(schedule.cron || "")} · ${getTimezoneDisplayName(schedule.timezone || userTzRes || "UTC")}` + ? `${humanizeCronExpression(schedule.cron || "")} · ${getTimezoneDisplayName(schedule.timezone || userTimezone || "UTC")}` : undefined } /> @@ -125,7 +121,7 @@ export function SelectedScheduleView({ {" "} {getTimezoneDisplayName( - schedule.timezone || userTzRes || "UTC", + schedule.timezone || userTimezone || "UTC", )} @@ -135,7 +131,7 @@ export function SelectedScheduleView({ {formatInTimezone( schedule.next_run_time, - userTzRes || "UTC", + userTimezone || "UTC", { year: "numeric", month: "long", @@ -148,7 +144,7 @@ export function SelectedScheduleView({ {" "} {getTimezoneDisplayName( - schedule.timezone || userTzRes || "UTC", + schedule.timezone || userTimezone || "UTC", )} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts index b006e775f9..427340a427 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/components/EditScheduleModal/useEditScheduleModal.ts @@ -1,7 +1,7 @@ "use client"; -import { getGetV1ListGraphExecutionsInfiniteQueryOptions } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { getGetV1ListExecutionSchedulesForAGraphQueryKey } from "@/app/api/__generated__/endpoints/schedules/schedules"; +import { getGetV1ListGraphExecutionsQueryKey } from "@/app/api/__generated__/endpoints/graphs/graphs"; import type { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { useMutation, useQueryClient } from "@tanstack/react-query"; @@ -94,8 +94,7 @@ export function useEditScheduleModal( await queryClient.invalidateQueries({ queryKey: getGetV1ListExecutionSchedulesForAGraphQueryKey(graphId), }); - const runsKey = getGetV1ListGraphExecutionsInfiniteQueryOptions(graphId) - .queryKey as any; + const runsKey = getGetV1ListGraphExecutionsQueryKey(graphId); await queryClient.invalidateQueries({ queryKey: runsKey }); setIsOpen(false); }, diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/useSelectedScheduleView.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/useSelectedScheduleView.ts index 01905eb296..66263e2dcc 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/useSelectedScheduleView.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedScheduleView/useSelectedScheduleView.ts @@ -2,30 +2,29 @@ import { useMemo } from "react"; import { useGetV1ListExecutionSchedulesForAGraph } from "@/app/api/__generated__/endpoints/schedules/schedules"; -import type { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; +import { okData } from "@/app/api/helpers"; export function useSelectedScheduleView(graphId: string, scheduleId: string) { - const query = useGetV1ListExecutionSchedulesForAGraph(graphId, { + const schedulesQuery = useGetV1ListExecutionSchedulesForAGraph(graphId, { query: { enabled: !!graphId, - select: (res) => - res.status === 200 ? (res.data as GraphExecutionJobInfo[]) : [], + select: okData, }, }); const schedule = useMemo( - () => query.data?.find((s) => s.id === scheduleId), - [query.data, scheduleId], + () => schedulesQuery.data?.find((s) => s.id === scheduleId), + [schedulesQuery.data, scheduleId], ); const httpError = - query.isSuccess && !schedule + schedulesQuery.isSuccess && !schedule ? { status: 404, statusText: "Not found" } : undefined; return { schedule, - isLoading: query.isLoading, - error: query.error || httpError, + isLoading: schedulesQuery.isLoading, + error: schedulesQuery.error || httpError, } as const; } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx index 1d50ec7c85..008d2cc379 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/components/SelectedTemplateActions.tsx @@ -2,10 +2,10 @@ import { getGetV2ListPresetsQueryKey, + getV2ListPresets, useDeleteV2DeleteAPreset, } from "@/app/api/__generated__/endpoints/presets/presets"; import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; -import type { LibraryAgentPresetResponse } from "@/app/api/__generated__/models/libraryAgentPresetResponse"; import { okData } from "@/app/api/helpers"; import { Button } from "@/components/atoms/Button/Button"; import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner"; @@ -56,15 +56,13 @@ export function SelectedTemplateActions({ queryKey, }); - const queryData = queryClient.getQueryData<{ - data: LibraryAgentPresetResponse; - }>(queryKey); + const queryData = + queryClient.getQueryData< + Awaited> + >(queryKey); - const presets = - okData(queryData)?.presets ?? []; - const templates = presets.filter( - (preset) => !preset.webhook_id || !preset.webhook, - ); + const presets = okData(queryData)?.presets ?? []; + const templates = presets.filter((preset) => !preset.webhook_id); setShowDeleteDialog(false); onDeleted?.(); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/useSelectedTemplateView.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/useSelectedTemplateView.ts index a0f34f54a2..66dd26f488 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/useSelectedTemplateView.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTemplateView/useSelectedTemplateView.ts @@ -1,6 +1,6 @@ "use client"; -import { getGetV1ListGraphExecutionsInfiniteQueryOptions } from "@/app/api/__generated__/endpoints/graphs/graphs"; +import { getGetV1ListGraphExecutionsQueryKey } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { getGetV2GetASpecificPresetQueryKey, getGetV2ListPresetsQueryKey, @@ -9,7 +9,6 @@ import { usePostV2ExecuteAPreset, } from "@/app/api/__generated__/endpoints/presets/presets"; import type { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta"; -import type { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import type { LibraryAgentPresetUpdatable } from "@/app/api/__generated__/models/libraryAgentPresetUpdatable"; import { okData } from "@/app/api/helpers"; import { useToast } from "@/components/molecules/Toast/use-toast"; @@ -34,7 +33,7 @@ export function useSelectedTemplateView({ const query = useGetV2GetASpecificPreset(templateId, { query: { enabled: !!templateId, - select: (res) => okData(res), + select: okData, }, }); @@ -83,15 +82,13 @@ export function useSelectedTemplateView({ mutation: { onSuccess: (response) => { if (response.status === 200) { - const execution = okData(response); + const execution = okData(response); if (execution) { toast({ title: "Task started", }); queryClient.invalidateQueries({ - queryKey: - getGetV1ListGraphExecutionsInfiniteQueryOptions(graphId) - .queryKey, + queryKey: getGetV1ListGraphExecutionsQueryKey(graphId), }); onRunCreated?.(execution); } diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/components/SelectedTriggerActions.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/components/SelectedTriggerActions.tsx index 0746027f37..a5b895c3fa 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/components/SelectedTriggerActions.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/components/SelectedTriggerActions.tsx @@ -2,10 +2,10 @@ import { getGetV2ListPresetsQueryKey, + getV2ListPresets, useDeleteV2DeleteAPreset, } from "@/app/api/__generated__/endpoints/presets/presets"; import type { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; -import type { LibraryAgentPresetResponse } from "@/app/api/__generated__/models/libraryAgentPresetResponse"; import { okData } from "@/app/api/helpers"; import { Button } from "@/components/atoms/Button/Button"; import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner"; @@ -52,15 +52,13 @@ export function SelectedTriggerActions({ queryKey, }); - const queryData = queryClient.getQueryData<{ - data: LibraryAgentPresetResponse; - }>(queryKey); + const queryData = + queryClient.getQueryData< + Awaited> + >(queryKey); - const presets = - okData(queryData)?.presets ?? []; - const triggers = presets.filter( - (preset) => preset.webhook_id && preset.webhook, - ); + const presets = okData(queryData)?.presets ?? []; + const triggers = presets.filter((preset) => preset.webhook_id); setShowDeleteDialog(false); onDeleted?.(); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/useSelectedTriggerView.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/useSelectedTriggerView.ts index 4669d850b2..235c653134 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/useSelectedTriggerView.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/selected-views/SelectedTriggerView/useSelectedTriggerView.ts @@ -6,7 +6,6 @@ import { useGetV2GetASpecificPreset, usePatchV2UpdateAnExistingPreset, } from "@/app/api/__generated__/endpoints/presets/presets"; -import type { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import type { LibraryAgentPresetUpdatable } from "@/app/api/__generated__/models/libraryAgentPresetUpdatable"; import { okData } from "@/app/api/helpers"; import { useToast } from "@/components/molecules/Toast/use-toast"; @@ -26,7 +25,7 @@ export function useSelectedTriggerView({ triggerId, graphId }: Args) { const query = useGetV2GetASpecificPreset(triggerId, { query: { enabled: !!triggerId, - select: (res) => okData(res), + select: okData, }, }); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx index 95cc7740f8..ba923bca68 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/components/TaskActionsDropdown.tsx @@ -1,7 +1,7 @@ "use client"; import { - getGetV1ListGraphExecutionsInfiniteQueryOptions, + getGetV1ListGraphExecutionsQueryKey, useDeleteV1DeleteGraphExecution, } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { @@ -51,9 +51,7 @@ export function TaskActionsDropdown({ agent, run, onDeleted }: Props) { toast({ title: "Task deleted" }); await queryClient.refetchQueries({ - queryKey: getGetV1ListGraphExecutionsInfiniteQueryOptions( - agent.graph_id, - ).queryKey, + queryKey: getGetV1ListGraphExecutionsQueryKey(agent.graph_id), }); setShowDeleteDialog(false); diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/helpers.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/helpers.ts deleted file mode 100644 index 096e40239b..0000000000 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/helpers.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { GraphExecutionsPaginated } from "@/app/api/__generated__/models/graphExecutionsPaginated"; -import type { InfiniteData } from "@tanstack/react-query"; - -function hasValidExecutionsData( - page: unknown, -): page is { data: GraphExecutionsPaginated } { - return ( - typeof page === "object" && - page !== null && - "data" in page && - typeof (page as { data: unknown }).data === "object" && - (page as { data: unknown }).data !== null && - "executions" in (page as { data: GraphExecutionsPaginated }).data - ); -} - -export function computeRunsCount( - infiniteData: InfiniteData | undefined, - runsLength: number, -): number { - const lastPage = infiniteData?.pages.at(-1); - if (!hasValidExecutionsData(lastPage)) return runsLength; - return lastPage.data.pagination?.total_items || runsLength; -} - -export function getNextRunsPageParam(lastPage: unknown): number | undefined { - if (!hasValidExecutionsData(lastPage)) return undefined; - - const { pagination } = lastPage.data; - const hasMore = - pagination.current_page * pagination.page_size < pagination.total_items; - return hasMore ? pagination.current_page + 1 : undefined; -} - -export function extractRunsFromPages( - infiniteData: InfiniteData | undefined, -) { - return ( - infiniteData?.pages.flatMap((page) => { - if (!hasValidExecutionsData(page)) return []; - return page.data.executions || []; - }) || [] - ); -} diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/useSidebarRunsList.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/useSidebarRunsList.ts index 7f7155bbdf..971b90c2e3 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/useSidebarRunsList.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/components/sidebar/SidebarRunsList/useSidebarRunsList.ts @@ -2,20 +2,18 @@ import { useEffect, useMemo } from "react"; +import { + okData, + getPaginationNextPageNumber, + getPaginatedTotalCount, + unpaginate, +} from "@/app/api/helpers"; import { useGetV1ListGraphExecutionsInfinite } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { useGetV2ListPresets } from "@/app/api/__generated__/endpoints/presets/presets"; import { useGetV1ListExecutionSchedulesForAGraph } from "@/app/api/__generated__/endpoints/schedules/schedules"; -import type { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; -import type { LibraryAgentPresetResponse } from "@/app/api/__generated__/models/libraryAgentPresetResponse"; -import { okData } from "@/app/api/helpers"; import { useExecutionEvents } from "@/hooks/useExecutionEvents"; import { useQueryClient } from "@tanstack/react-query"; import { parseAsString, useQueryStates } from "nuqs"; -import { - computeRunsCount, - extractRunsFromPages, - getNextRunsPageParam, -} from "./helpers"; function parseTab( value: string | null, @@ -66,7 +64,7 @@ export function useSidebarRunsList({ query: { enabled: !!graphId, refetchOnWindowFocus: false, - getNextPageParam: getNextRunsPageParam, + getNextPageParam: getPaginationNextPageNumber, }, }, ); @@ -74,7 +72,7 @@ export function useSidebarRunsList({ const schedulesQuery = useGetV1ListExecutionSchedulesForAGraph(graphId, { query: { enabled: !!graphId, - select: (r) => okData(r), + select: okData, }, }); @@ -83,13 +81,13 @@ export function useSidebarRunsList({ { query: { enabled: !!graphId, - select: (r) => okData(r)?.presets, + select: (r) => okData(r)?.presets, }, }, ); const runs = useMemo( - () => extractRunsFromPages(runsQuery.data), + () => (runsQuery.data ? unpaginate(runsQuery.data, "executions") : []), [runsQuery.data], ); @@ -104,7 +102,7 @@ export function useSidebarRunsList({ [allPresets], ); - const runsCount = computeRunsCount(runsQuery.data, runs.length); + const runsCount = getPaginatedTotalCount(runsQuery.data, runs.length); const schedulesCount = schedules.length; const templatesCount = templates.length; const triggersCount = triggers.length; diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/useNewAgentLibraryView.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/useNewAgentLibraryView.ts index 394edb1a6d..b4cc2baca8 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/useNewAgentLibraryView.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/NewAgentLibraryView/useNewAgentLibraryView.ts @@ -2,7 +2,6 @@ import { useGetV2GetLibraryAgent } from "@/app/api/__generated__/endpoints/libra import { useGetV2GetASpecificPreset } from "@/app/api/__generated__/endpoints/presets/presets"; import { GraphExecutionJobInfo } from "@/app/api/__generated__/models/graphExecutionJobInfo"; import { GraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta"; -import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; import { LibraryAgentPreset } from "@/app/api/__generated__/models/libraryAgentPreset"; import { okData } from "@/app/api/helpers"; import { useParams } from "next/navigation"; @@ -31,11 +30,7 @@ export function useNewAgentLibraryView() { data: agent, isSuccess, error, - } = useGetV2GetLibraryAgent(agentId, { - query: { - select: okData, - }, - }); + } = useGetV2GetLibraryAgent(agentId, { query: { select: okData } }); const [{ activeItem, activeTab: activeTabRaw }, setQueryStates] = useQueryStates({ @@ -53,7 +48,7 @@ export function useNewAgentLibraryView() { } = useGetV2GetASpecificPreset(activeItem ?? "", { query: { enabled: Boolean(activeTab === "templates" && activeItem), - select: okData, + select: okData, }, }); const activeTemplate = diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/agent-schedule-details-view.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/agent-schedule-details-view.tsx index 414aa3863b..61161088fc 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/agent-schedule-details-view.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/agent-schedule-details-view.tsx @@ -23,7 +23,7 @@ import LoadingBox from "@/components/__legacy__/ui/loading"; import { useToastOnFail } from "@/components/molecules/Toast/use-toast"; import { humanizeCronExpression } from "@/lib/cron-expression-utils"; import { formatScheduleTime } from "@/lib/timezone-utils"; -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { PlayIcon } from "lucide-react"; import { AgentRunStatus } from "./agent-run-status-chip"; @@ -48,11 +48,7 @@ export function AgentScheduleDetailsView({ const toastOnFail = useToastOnFail(); // Get user's timezone for displaying schedule times - const { data: userTimezone } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : undefined), - }, - }); + const userTimezone = useUserTimezone(); const infoStats: { label: string; value: React.ReactNode }[] = useMemo(() => { return [ diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog.tsx b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog.tsx index e998823a89..30c3e7d777 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler-dialog.tsx @@ -4,8 +4,8 @@ import { Button } from "@/components/__legacy__/ui/button"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { CronScheduler } from "@/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/components/cron-scheduler"; import { Dialog } from "@/components/molecules/Dialog/Dialog"; -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; import { getTimezoneDisplayName } from "@/lib/timezone-utils"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { InfoIcon } from "lucide-react"; // Base type for cron expression only @@ -50,11 +50,7 @@ export function CronSchedulerDialog(props: CronSchedulerDialogProps) { ); // Get user's timezone - const { data: userTimezone } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : undefined), - }, - }); + const userTimezone = useUserTimezone(); const timezoneDisplay = getTimezoneDisplayName(userTimezone || "UTC"); // Reset state when dialog opens diff --git a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/use-agent-runs.ts b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/use-agent-runs.ts index f997726e21..c74a37e6d0 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/use-agent-runs.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/agents/[id]/components/OldAgentLibraryView/use-agent-runs.ts @@ -1,15 +1,20 @@ +import { + GraphExecutionMeta as LegacyGraphExecutionMeta, + GraphID, + GraphExecutionID, +} from "@/lib/autogpt-server-api"; +import { getQueryClient } from "@/lib/react-query/queryClient"; +import { + getPaginatedTotalCount, + getPaginationNextPageNumber, + unpaginate, +} from "@/app/api/helpers"; import { getV1ListGraphExecutionsResponse, getV1ListGraphExecutionsResponse200, useGetV1ListGraphExecutionsInfinite, } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { GraphExecutionsPaginated } from "@/app/api/__generated__/models/graphExecutionsPaginated"; -import { getQueryClient } from "@/lib/react-query/queryClient"; -import { - GraphExecutionMeta as LegacyGraphExecutionMeta, - GraphID, - GraphExecutionID, -} from "@/lib/autogpt-server-api"; import { GraphExecutionMeta as RawGraphExecutionMeta } from "@/app/api/__generated__/models/graphExecutionMeta"; export type GraphExecutionMeta = Omit< @@ -44,15 +49,7 @@ export const useAgentRunsInfinite = (graphID?: GraphID) => { { page: 1, page_size: 20 }, { query: { - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as GraphExecutionsPaginated) - .pagination; - const hasMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return hasMore ? pagination.current_page + 1 : undefined; - }, + getNextPageParam: getPaginationNextPageNumber, // Prevent query from running if graphID is not available (yet) ...(!graphID @@ -80,15 +77,8 @@ export const useAgentRunsInfinite = (graphID?: GraphID) => { queryClient, ); - const agentRuns = - queryResults?.pages.flatMap((page) => { - const response = page.data as GraphExecutionsPaginated; - return response.executions; - }) ?? []; - - const agentRunCount = ( - queryResults?.pages.at(-1)?.data as GraphExecutionsPaginated | undefined - )?.pagination.total_items; + const agentRuns = queryResults ? unpaginate(queryResults, "executions") : []; + const agentRunCount = getPaginatedTotalCount(queryResults); const upsertAgentRun = (newAgentRun: GraphExecutionMeta) => { queryClient.setQueryData( diff --git a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts index 8ae2c659a6..e9db9a02da 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/components/LibraryAgentList/useLibraryAgentList.ts @@ -1,7 +1,11 @@ "use client"; +import { + getPaginatedTotalCount, + getPaginationNextPageNumber, + unpaginate, +} from "@/app/api/helpers"; import { useGetV2ListLibraryAgentsInfinite } from "@/app/api/__generated__/endpoints/library/library"; -import { LibraryAgentResponse } from "@/app/api/__generated__/models/libraryAgentResponse"; import { useLibraryPageContext } from "../state-provider"; import { useLibraryAgentsStore } from "@/hooks/useLibraryAgents/store"; import { getInitialData } from "./helpers"; @@ -11,7 +15,7 @@ export const useLibraryAgentList = () => { const { agents: cachedAgents } = useLibraryAgentsStore(); const { - data: agents, + data: agentsQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -26,27 +30,15 @@ export const useLibraryAgentList = () => { { query: { initialData: getInitialData(cachedAgents, searchTerm, 8), - getNextPageParam: (lastPage) => { - const pagination = (lastPage.data as LibraryAgentResponse).pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, + getNextPageParam: getPaginationNextPageNumber, }, }, ); - const allAgents = - agents?.pages?.flatMap((page) => { - const response = page.data as LibraryAgentResponse; - return response.agents; - }) ?? []; - - const agentCount = agents?.pages?.[0] - ? (agents.pages[0].data as LibraryAgentResponse).pagination.total_items - : 0; + const allAgents = agentsQueryData + ? unpaginate(agentsQueryData, "agents") + : []; + const agentCount = getPaginatedTotalCount(agentsQueryData); return { allAgents, diff --git a/autogpt_platform/frontend/src/app/(platform)/library/hooks/useFavoriteAgents.ts b/autogpt_platform/frontend/src/app/(platform)/library/hooks/useFavoriteAgents.ts index 633ad72712..933670ca80 100644 --- a/autogpt_platform/frontend/src/app/(platform)/library/hooks/useFavoriteAgents.ts +++ b/autogpt_platform/frontend/src/app/(platform)/library/hooks/useFavoriteAgents.ts @@ -1,10 +1,15 @@ "use client"; +import { + getPaginatedTotalCount, + getPaginationNextPageNumber, + unpaginate, +} from "@/app/api/helpers"; import { useGetV2ListFavoriteLibraryAgentsInfinite } from "@/app/api/__generated__/endpoints/library/library"; export function useFavoriteAgents() { const { - data: agents, + data: agentsQueryData, fetchNextPage, hasNextPage, isFetchingNextPage, @@ -15,36 +20,14 @@ export function useFavoriteAgents() { page_size: 10, }, { - query: { - getNextPageParam: (lastPage) => { - // Only paginate on successful responses - if (!lastPage || lastPage.status !== 200) return undefined; - - const pagination = lastPage.data.pagination; - const isMore = - pagination.current_page * pagination.page_size < - pagination.total_items; - - return isMore ? pagination.current_page + 1 : undefined; - }, - }, + query: { getNextPageParam: getPaginationNextPageNumber }, }, ); - const allAgents = - agents?.pages?.flatMap((page) => { - // Only process successful responses - if (!page || page.status !== 200) return []; - const response = page.data; - return response?.agents || []; - }) ?? []; - - const agentCount = (() => { - const firstPage = agents?.pages?.[0]; - // Only count from successful responses - if (!firstPage || firstPage.status !== 200) return 0; - return firstPage.data?.pagination?.total_items || 0; - })(); + const allAgents = agentsQueryData + ? unpaginate(agentsQueryData, "agents") + : []; + const agentCount = getPaginatedTotalCount(agentsQueryData); return { allAgents, diff --git a/autogpt_platform/frontend/src/app/(platform)/monitoring/components/SchedulesTable.tsx b/autogpt_platform/frontend/src/app/(platform)/monitoring/components/SchedulesTable.tsx index f069510b01..ad35db11b1 100644 --- a/autogpt_platform/frontend/src/app/(platform)/monitoring/components/SchedulesTable.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/monitoring/components/SchedulesTable.tsx @@ -15,11 +15,11 @@ import { ScrollArea } from "@/components/__legacy__/ui/scroll-area"; import { ClockIcon, Loader2 } from "lucide-react"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { humanizeCronExpression } from "@/lib/cron-expression-utils"; +import { useUserTimezone } from "@/lib/hooks/useUserTimezone"; import { formatScheduleTime, getTimezoneAbbreviation, } from "@/lib/timezone-utils"; -import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; import { Select, SelectContent, @@ -66,11 +66,7 @@ export const SchedulesTable = ({ const [selectedFilter, setSelectedFilter] = useState(""); // Graph ID // Get user's timezone for displaying schedule times - const { data: userTimezone } = useGetV1GetUserTimezone({ - query: { - select: (res) => (res.status === 200 ? res.data.timezone : "UTC"), - }, - }); + const userTimezone = useUserTimezone() ?? "UTC"; const filteredAndSortedSchedules = [...schedules] .filter( diff --git a/autogpt_platform/frontend/src/app/(platform)/monitoring/page.tsx b/autogpt_platform/frontend/src/app/(platform)/monitoring/page.tsx index 5e70245ac9..3b5aa46839 100644 --- a/autogpt_platform/frontend/src/app/(platform)/monitoring/page.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/monitoring/page.tsx @@ -7,6 +7,7 @@ import { useGetV1ListExecutionSchedulesForAUser, useDeleteV1DeleteExecutionSchedule, } from "@/app/api/__generated__/endpoints/schedules/schedules"; +import { okData } from "@/app/api/helpers"; import { Card } from "@/components/__legacy__/ui/card"; import { SchedulesTable } from "@/app/(platform)/monitoring/components/SchedulesTable"; @@ -34,8 +35,7 @@ const Monitor = () => { useGetV1ListExecutionSchedulesForAUser(); const deleteScheduleMutation = useDeleteV1DeleteExecutionSchedule(); - const schedules = - schedulesResponse?.status === 200 ? schedulesResponse.data : []; + const schedules = okData(schedulesResponse) ?? []; const removeSchedule = useCallback( async (scheduleId: string) => { diff --git a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/api-keys/components/APIKeySection/useAPISection.ts b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/api-keys/components/APIKeySection/useAPISection.ts index 5fe691f025..d4ad54162e 100644 --- a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/api-keys/components/APIKeySection/useAPISection.ts +++ b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/api-keys/components/APIKeySection/useAPISection.ts @@ -4,6 +4,7 @@ import { useDeleteV1RevokeApiKey, useGetV1ListUserApiKeys, } from "@/app/api/__generated__/endpoints/api-keys/api-keys"; +import { okData } from "@/app/api/helpers"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { getQueryClient } from "@/lib/react-query/queryClient"; @@ -13,11 +14,7 @@ export const useAPISection = () => { const { data: apiKeys, isLoading } = useGetV1ListUserApiKeys({ query: { - select: (res) => { - if (res.status !== 200) return undefined; - - return res.data.filter((key) => key.status === "ACTIVE"); - }, + select: (res) => okData(res)?.filter((key) => key.status === "ACTIVE"), }, }); diff --git a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/oauth-apps/components/useOAuthApps.ts b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/oauth-apps/components/useOAuthApps.ts index 5b5afc5783..cf9749c53a 100644 --- a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/oauth-apps/components/useOAuthApps.ts +++ b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/oauth-apps/components/useOAuthApps.ts @@ -7,7 +7,6 @@ import { usePostOauthUploadAppLogo, getGetOauthListMyOauthAppsQueryKey, } from "@/app/api/__generated__/endpoints/oauth/oauth"; -import { OAuthApplicationInfo } from "@/app/api/__generated__/models/oAuthApplicationInfo"; import { okData } from "@/app/api/helpers"; import { useToast } from "@/components/molecules/Toast/use-toast"; import { getQueryClient } from "@/lib/react-query/queryClient"; @@ -19,7 +18,7 @@ export const useOAuthApps = () => { const [uploadingAppId, setUploadingAppId] = useState(null); const { data: oauthAppsResponse, isLoading } = useGetOauthListMyOauthApps({ - query: { select: okData }, + query: { select: okData }, }); const { mutateAsync: updateStatus } = usePatchOauthUpdateAppStatus({ diff --git a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/settings/page.tsx b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/settings/page.tsx index f0eb8a6b8c..8b4d48de83 100644 --- a/autogpt_platform/frontend/src/app/(platform)/profile/(user)/settings/page.tsx +++ b/autogpt_platform/frontend/src/app/(platform)/profile/(user)/settings/page.tsx @@ -6,6 +6,7 @@ import { useGetV1GetNotificationPreferences, useGetV1GetUserTimezone, } from "@/app/api/__generated__/endpoints/auth/auth"; +import { okData } from "@/app/api/helpers"; import { Text } from "@/components/atoms/Text/Text"; import { ErrorCard } from "@/components/molecules/ErrorCard/ErrorCard"; import { useSupabase } from "@/lib/supabase/hooks/useSupabase"; @@ -24,7 +25,7 @@ export default function SettingsPage() { } = useGetV1GetNotificationPreferences({ query: { enabled: !!user, - select: (res) => (res.status === 200 ? res.data : null), + select: okData, }, }); @@ -32,9 +33,7 @@ export default function SettingsPage() { useGetV1GetUserTimezone({ query: { enabled: !!user, - select: (res) => { - return res.status === 200 ? String(res.data.timezone) : "not-set"; - }, + select: (res) => okData(res)?.timezone ?? "not-set", }, }); diff --git a/autogpt_platform/frontend/src/app/api/helpers.ts b/autogpt_platform/frontend/src/app/api/helpers.ts index 2ed45c9517..e9a708ba4c 100644 --- a/autogpt_platform/frontend/src/app/api/helpers.ts +++ b/autogpt_platform/frontend/src/app/api/helpers.ts @@ -1,7 +1,12 @@ +import type { InfiniteData } from "@tanstack/react-query"; import { getV1IsOnboardingEnabled, getV1OnboardingState, } from "./__generated__/endpoints/onboarding/onboarding"; +import { Pagination } from "./__generated__/models/pagination"; + +export type OKData = + (TResponse & { status: 200 })["data"]; /** * Narrow an orval response to its success payload if and only if it is a `200` status with OK shape. @@ -9,13 +14,15 @@ import { * Usage with React Query select: * ```ts * const { data: agent } = useGetV2GetLibraryAgent(agentId, { - * query: { select: okData }, + * query: { select: okData }, * }); * * data // is now properly typed as LibraryAgent | undefined * ``` */ -export function okData(res: unknown): T | undefined { +export function okData( + res: TResponse | undefined, +): OKData | undefined { if (!res || typeof res !== "object") return undefined; // status must exist and be exactly 200 @@ -26,7 +33,88 @@ export function okData(res: unknown): T | undefined { // check presence to safely return it as T; the generic T is enforced at call sites. if (!("data" in (res as Record))) return undefined; - return (res as { data: T }).data; + return res.data; +} + +export function getPaginatedTotalCount( + infiniteData: InfiniteData | undefined, + fallbackCount?: number, +): number { + const lastPage = infiniteData?.pages.at(-1); + if (!hasValidPaginationInfo(lastPage)) return fallbackCount ?? 0; + return lastPage.data.pagination.total_items ?? fallbackCount ?? 0; +} + +export function getPaginationNextPageNumber( + lastPage: + | { data: { pagination?: Pagination; [key: string]: any } } + | undefined, +): number | undefined { + if (!hasValidPaginationInfo(lastPage)) return undefined; + + const { pagination } = lastPage.data; + const hasMore = + pagination.current_page * pagination.page_size < pagination.total_items; + return hasMore ? pagination.current_page + 1 : undefined; +} + +/** Make one list from a paginated infinite query result. */ +export function unpaginate< + TResponse extends { status: number; data: any }, + TPageDataKey extends { + // Only allow keys for which the value is an array: + [K in keyof OKData]: OKData[K] extends any[] + ? K + : never; + }[keyof OKData] & + string, + TItemData extends OKData[TPageDataKey][number], +>( + infiniteData: InfiniteData, + pageListKey: TPageDataKey, +): TItemData[] { + return ( + infiniteData?.pages.flatMap((page) => { + if (!hasValidListPage(page, pageListKey)) return []; + return page.data[pageListKey] || []; + }) || [] + ); +} + +function hasValidListPage( + page: unknown, + pageListKey: TKey, +): page is { status: 200; data: { [key in TKey]: any[] } } { + return ( + typeof page === "object" && + page !== null && + "status" in page && + page.status === 200 && + "data" in page && + typeof page.data === "object" && + page.data !== null && + pageListKey in page.data && + Array.isArray((page.data as Record)[pageListKey]) + ); +} + +function hasValidPaginationInfo( + page: unknown, +): page is { data: { pagination: Pagination; [key: string]: any } } { + return ( + typeof page === "object" && + page !== null && + "data" in page && + typeof page.data === "object" && + page.data !== null && + "pagination" in page.data && + typeof page.data.pagination === "object" && + page.data.pagination !== null && + "total_items" in page.data.pagination && + "total_pages" in page.data.pagination && + "current_page" in page.data.pagination && + "page_size" in page.data.pagination + ); } type ResponseWithData = { status: number; data: unknown }; diff --git a/autogpt_platform/frontend/src/app/api/openapi.json b/autogpt_platform/frontend/src/app/api/openapi.json index 61a3600892..2ead2189ed 100644 --- a/autogpt_platform/frontend/src/app/api/openapi.json +++ b/autogpt_platform/frontend/src/app/api/openapi.json @@ -4624,7 +4624,7 @@ "get": { "tags": ["v2", "executions", "review", "v2", "executions", "review"], "summary": "Get Pending Reviews for Execution", - "description": "Get all pending reviews for a specific graph execution.\n\nRetrieves all reviews with status \"WAITING\" for the specified graph execution\nthat belong to the authenticated user. Results are ordered by creation time\n(oldest first) to preserve review order within the execution.\n\nArgs:\n graph_exec_id: ID of the graph execution to get reviews for\n user_id: Authenticated user ID from security dependency\n\nReturns:\n List of pending review objects for the specified execution\n\nRaises:\n HTTPException:\n - 403: If user doesn't own the graph execution\n - 500: If authentication fails or database error occurs\n\nNote:\n Only returns reviews owned by the authenticated user for security.\n Reviews with invalid status are excluded with warning logs.", + "description": "Get all pending reviews for a specific graph execution.\n\nRetrieves all reviews with status \"WAITING\" for the specified graph execution\nthat belong to the authenticated user. Results are ordered by creation time\n(oldest first) to preserve review order within the execution.\n\nArgs:\n graph_exec_id: ID of the graph execution to get reviews for\n user_id: Authenticated user ID from security dependency\n\nReturns:\n List of pending review objects for the specified execution\n\nRaises:\n HTTPException:\n - 404: If the graph execution doesn't exist or isn't owned by this user\n - 500: If authentication fails or database error occurs\n\nNote:\n Only returns reviews owned by the authenticated user for security.\n Reviews with invalid status are excluded with warning logs.", "operationId": "getV2Get pending reviews for execution", "security": [{ "HTTPBearerJWT": [] }], "parameters": [ @@ -4650,11 +4650,10 @@ } } }, - "400": { "description": "Invalid graph execution ID" }, "401": { "$ref": "#/components/responses/HTTP401NotAuthenticatedError" }, - "403": { "description": "Access denied to graph execution" }, + "404": { "description": "Graph execution not found" }, "422": { "description": "Validation Error", "content": { @@ -5349,7 +5348,11 @@ "responses": { "200": { "description": "Successful Response", - "content": { "application/json": { "schema": {} } } + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/GraphMeta" } + } + } }, "401": { "$ref": "#/components/responses/HTTP401NotAuthenticatedError" diff --git a/autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts b/autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts index 66386882c6..f6478f6c2b 100644 --- a/autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts +++ b/autogpt_platform/frontend/src/components/contextual/GoogleDrivePicker/useGoogleDrivePicker.ts @@ -15,6 +15,7 @@ import { normalizePickerResponse, scopesIncludeDrive, } from "./helpers"; +import { okData } from "@/app/api/helpers"; const defaultScopes = ["https://www.googleapis.com/auth/drive.file"]; @@ -126,9 +127,9 @@ export function useGoogleDrivePicker(options: Props) { ); const response = await queryClient.fetchQuery(queryOptions); + const cred = okData(response); - if (response.status === 200 && response.data) { - const cred = response.data; + if (cred) { if (cred.type === "oauth2") { const oauthCred = cred as OAuth2Credentials; if (oauthCred.access_token) { diff --git a/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx b/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx index 2766f2d477..896840ba08 100644 --- a/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx +++ b/autogpt_platform/frontend/src/components/contextual/PublishAgentModal/components/AgentSelectStep/AgentSelectStep.tsx @@ -34,7 +34,7 @@ export function AgentSelectStep({ }: Props) { const { // Data - agents, + myAgents, isLoading, error, // State @@ -99,7 +99,7 @@ export function AgentSelectStep({ description="Select your project that you'd like to publish" /> - {agents.length === 0 ? ( + {myAgents.length === 0 ? (
Uh-oh.. It seems like you don't have any agents in your @@ -130,7 +130,7 @@ export function AgentSelectStep({
- {agents.map((agent) => ( + {myAgents.map((agent) => (
(null); - const { data: myAgents, isLoading, error } = useGetV2GetMyAgents(); - - const agents: Agent[] = - (myAgents?.status === 200 && - myAgents.data.agents - .map( - (agent): Agent => ({ - name: agent.agent_name, - id: agent.agent_id, - version: agent.agent_version, - lastEdited: agent.last_edited.toLocaleDateString(), - imageSrc: agent.agent_image || "https://picsum.photos/300/200", - description: agent.description || "", - recommendedScheduleCron: agent.recommended_schedule_cron ?? null, - }), - ) - .sort( - (a: Agent, b: Agent) => - new Date(b.lastEdited).getTime() - new Date(a.lastEdited).getTime(), - )) || - []; + const { + data: _myAgents, + isLoading, + error, + } = useGetV2GetMyAgents(undefined, { + query: { + select: (res) => + okData(res) + ?.agents.map( + (agent): Agent => ({ + name: agent.agent_name, + id: agent.agent_id, + version: agent.agent_version, + lastEdited: agent.last_edited.toLocaleDateString(), + imageSrc: agent.agent_image || "https://picsum.photos/300/200", + description: agent.description || "", + recommendedScheduleCron: agent.recommended_schedule_cron ?? null, + }), + ) + .sort( + (a: Agent, b: Agent) => + new Date(b.lastEdited).getTime() - + new Date(a.lastEdited).getTime(), + ), + }, + }); + const myAgents = _myAgents ?? []; const handleAgentClick = ( _: string, @@ -70,7 +77,7 @@ export function useAgentSelectStep({ const handleNext = () => { if (selectedAgentId && selectedAgentVersion) { - const selectedAgent = agents.find( + const selectedAgent = myAgents.find( (agent) => agent.id === selectedAgentId, ); if (selectedAgent) { @@ -86,7 +93,7 @@ export function useAgentSelectStep({ return { // Data - agents, + myAgents, isLoading, error, // State diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/useAgentActivityDropdown.ts b/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/useAgentActivityDropdown.ts index df8402906b..9dbd8aaf7e 100644 --- a/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/useAgentActivityDropdown.ts +++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/AgentActivityDropdown/useAgentActivityDropdown.ts @@ -4,6 +4,7 @@ import { useExecutionEvents } from "@/hooks/useExecutionEvents"; import { useLibraryAgents } from "@/hooks/useLibraryAgents/useLibraryAgents"; import type { GraphExecution } from "@/lib/autogpt-server-api/types"; import { useCallback, useEffect, useMemo, useState } from "react"; +import { okData } from "@/app/api/helpers"; import { NotificationState, categorizeExecutions, @@ -26,7 +27,7 @@ export function useAgentActivityDropdown() { isSuccess: executionsSuccess, error: executionsError, } = useGetV1ListAllExecutions({ - query: { select: (res) => (res.status === 200 ? res.data : null) }, + query: { select: okData }, }); // Get all graph IDs from agentInfoMap diff --git a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx index 49790547e4..863b9f601f 100644 --- a/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx +++ b/autogpt_platform/frontend/src/components/layout/Navbar/components/NavbarView.tsx @@ -7,6 +7,7 @@ import { useBreakpoint } from "@/lib/hooks/useBreakpoint"; import { useSupabase } from "@/lib/supabase/hooks/useSupabase"; import { Flag, useGetFlag } from "@/services/feature-flags/use-get-flag"; import { useMemo } from "react"; +import { okData } from "@/app/api/helpers"; import { getAccountMenuItems, loggedInLinks, loggedOutLinks } from "../helpers"; import { AccountMenu } from "./AccountMenu/AccountMenu"; import { AgentActivityDropdown } from "./AgentActivityDropdown/AgentActivityDropdown"; @@ -29,7 +30,7 @@ export function NavbarView({ isLoggedIn, previewBranchName }: NavbarViewProps) { const { data: profile, isLoading: isProfileLoading } = useGetV2GetUserProfile( { query: { - select: (res) => (res.status === 200 ? res.data : null), + select: okData, enabled: isLoggedIn && !!user, // Include user ID in query key to ensure cache invalidation when user changes queryKey: ["/api/store/profile", user?.id], diff --git a/autogpt_platform/frontend/src/components/organisms/FloatingReviewsPanel/FloatingReviewsPanel.tsx b/autogpt_platform/frontend/src/components/organisms/FloatingReviewsPanel/FloatingReviewsPanel.tsx index 12014e50fe..2b04c0ed9a 100644 --- a/autogpt_platform/frontend/src/components/organisms/FloatingReviewsPanel/FloatingReviewsPanel.tsx +++ b/autogpt_platform/frontend/src/components/organisms/FloatingReviewsPanel/FloatingReviewsPanel.tsx @@ -7,6 +7,7 @@ import { cn } from "@/lib/utils"; import { Text } from "@/components/atoms/Text/Text"; import { useGetV1GetExecutionDetails } from "@/app/api/__generated__/endpoints/graphs/graphs"; import { AgentExecutionStatus } from "@/app/api/__generated__/models/agentExecutionStatus"; +import { okData } from "@/app/api/helpers"; import { useGraphStore } from "@/app/(platform)/build/stores/graphStore"; import { useShallow } from "zustand/react/shallow"; @@ -29,13 +30,11 @@ export function FloatingReviewsPanel({ { query: { enabled: !!(graphId && executionId), + select: okData, }, }, ); - const executionStatus = - executionDetails?.status === 200 ? executionDetails.data.status : undefined; - // Get graph execution status from the store (updated via WebSocket) const graphExecutionStatus = useGraphStore( useShallow((state) => state.graphExecutionStatus), @@ -49,7 +48,7 @@ export function FloatingReviewsPanel({ if (executionId) { refetch(); } - }, [executionStatus, executionId, refetch]); + }, [executionDetails?.status, executionId, refetch]); // Refetch when graph execution status changes to REVIEW useEffect(() => { @@ -62,7 +61,7 @@ export function FloatingReviewsPanel({ !executionId || (!isLoading && pendingReviews.length === 0 && - executionStatus !== AgentExecutionStatus.REVIEW) + executionDetails?.status !== AgentExecutionStatus.REVIEW) ) { return null; } diff --git a/autogpt_platform/frontend/src/components/organisms/PendingReviewsList/PendingReviewsList.tsx b/autogpt_platform/frontend/src/components/organisms/PendingReviewsList/PendingReviewsList.tsx index ddc9bab972..3253b0ee6d 100644 --- a/autogpt_platform/frontend/src/components/organisms/PendingReviewsList/PendingReviewsList.tsx +++ b/autogpt_platform/frontend/src/components/organisms/PendingReviewsList/PendingReviewsList.tsx @@ -44,8 +44,8 @@ export function PendingReviewsList({ const reviewActionMutation = usePostV2ProcessReviewAction({ mutation: { - onSuccess: (data: any) => { - if (data.status !== 200) { + onSuccess: (res) => { + if (res.status !== 200) { toast({ title: "Failed to process reviews", description: "Unexpected response from server", @@ -54,18 +54,18 @@ export function PendingReviewsList({ return; } - const response = data.data; + const result = res.data; - if (response.failed_count > 0) { + if (result.failed_count > 0) { toast({ title: "Reviews partially processed", - description: `${response.approved_count + response.rejected_count} succeeded, ${response.failed_count} failed. ${response.error || "Some reviews could not be processed."}`, + description: `${result.approved_count + result.rejected_count} succeeded, ${result.failed_count} failed. ${result.error || "Some reviews could not be processed."}`, variant: "destructive", }); } else { toast({ title: "Reviews processed successfully", - description: `${response.approved_count} approved, ${response.rejected_count} rejected`, + description: `${result.approved_count} approved, ${result.rejected_count} rejected`, variant: "default", }); } diff --git a/autogpt_platform/frontend/src/hooks/useAgentSafeMode.ts b/autogpt_platform/frontend/src/hooks/useAgentSafeMode.ts index 654ef858b6..07a2b33674 100644 --- a/autogpt_platform/frontend/src/hooks/useAgentSafeMode.ts +++ b/autogpt_platform/frontend/src/hooks/useAgentSafeMode.ts @@ -7,6 +7,7 @@ import { import { useToast } from "@/components/molecules/Toast/use-toast"; import { GraphModel } from "@/app/api/__generated__/models/graphModel"; import { LibraryAgent } from "@/app/api/__generated__/models/libraryAgent"; +import { okData } from "@/app/api/helpers"; import { useQueryClient } from "@tanstack/react-query"; import { Graph } from "@/lib/autogpt-server-api/types"; @@ -47,15 +48,19 @@ export function useAgentSafeMode(graph: GraphModel | LibraryAgent | Graph) { const { data: libraryAgent, isLoading } = useGetV2GetLibraryAgentByGraphId( graphId, {}, - { query: { enabled: !isAgent && shouldShowToggle } }, + { + query: { + enabled: !isAgent && shouldShowToggle, + select: okData, + }, + }, ); const [localSafeMode, setLocalSafeMode] = useState(null); useEffect(() => { - if (!isAgent && libraryAgent?.status === 200) { - const backendValue = - libraryAgent.data?.settings?.human_in_the_loop_safe_mode; + if (!isAgent && libraryAgent) { + const backendValue = libraryAgent.settings?.human_in_the_loop_safe_mode; if (backendValue !== undefined) { setLocalSafeMode(backendValue); } diff --git a/autogpt_platform/frontend/src/hooks/usePendingReviews.ts b/autogpt_platform/frontend/src/hooks/usePendingReviews.ts index 111b50a491..8257814fcf 100644 --- a/autogpt_platform/frontend/src/hooks/usePendingReviews.ts +++ b/autogpt_platform/frontend/src/hooks/usePendingReviews.ts @@ -2,12 +2,13 @@ import { useGetV2GetPendingReviews, useGetV2GetPendingReviewsForExecution, } from "@/app/api/__generated__/endpoints/executions/executions"; +import { okData } from "@/app/api/helpers"; export function usePendingReviews() { const query = useGetV2GetPendingReviews(); return { - pendingReviews: (query.data?.status === 200 ? query.data.data : []) || [], + pendingReviews: okData(query.data) || [], isLoading: query.isLoading, error: query.error, refetch: query.refetch, @@ -18,7 +19,7 @@ export function usePendingReviewsForExecution(graphExecId: string) { const query = useGetV2GetPendingReviewsForExecution(graphExecId); return { - pendingReviews: (query.data?.status === 200 ? query.data.data : []) || [], + pendingReviews: okData(query.data) || [], isLoading: query.isLoading, error: query.error, refetch: query.refetch, diff --git a/autogpt_platform/frontend/src/lib/hooks/useUserTimezone.ts b/autogpt_platform/frontend/src/lib/hooks/useUserTimezone.ts new file mode 100644 index 0000000000..7d5cef3a04 --- /dev/null +++ b/autogpt_platform/frontend/src/lib/hooks/useUserTimezone.ts @@ -0,0 +1,8 @@ +import { okData } from "@/app/api/helpers"; +import { useGetV1GetUserTimezone } from "@/app/api/__generated__/endpoints/auth/auth"; + +export function useUserTimezone(): "not-set" | string | undefined { + return useGetV1GetUserTimezone({ + query: { select: (res) => okData(res)?.timezone }, + }).data; +} diff --git a/autogpt_platform/frontend/src/lib/react-query/queryClient.ts b/autogpt_platform/frontend/src/lib/react-query/queryClient.ts index 836c505c2f..512629e65b 100644 --- a/autogpt_platform/frontend/src/lib/react-query/queryClient.ts +++ b/autogpt_platform/frontend/src/lib/react-query/queryClient.ts @@ -21,6 +21,10 @@ function makeQueryClient() { let browserQueryClient: QueryClient | undefined = undefined; +/** Only for use *outside client component context* + * (so in server components, API helpers, etc.). + * + * In the context of client components, you should always use `useQueryClient()`. */ export function getQueryClient() { if (isServer) { // Server: create new client every time (so one user's data doesn't leak to another)