mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
add better error handling in all components
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { AlertCircle, RefreshCw } from "lucide-react";
|
||||
import React from "react";
|
||||
|
||||
interface ErrorStateProps {
|
||||
title?: string;
|
||||
message?: string;
|
||||
error?: string | Error | null;
|
||||
onRetry?: () => void;
|
||||
retryLabel?: string;
|
||||
className?: string;
|
||||
showIcon?: boolean;
|
||||
}
|
||||
|
||||
const ErrorState: React.FC<ErrorStateProps> = ({
|
||||
title = "Something went wrong",
|
||||
message,
|
||||
error,
|
||||
onRetry,
|
||||
retryLabel = "Retry",
|
||||
className,
|
||||
showIcon = true,
|
||||
}) => {
|
||||
const errorMessage = error
|
||||
? error instanceof Error
|
||||
? error.message
|
||||
: String(error)
|
||||
: message || "An unexpected error occurred. Please try again.";
|
||||
|
||||
const classes =
|
||||
"flex h-full w-full flex-col items-center justify-center text-center space-y-4";
|
||||
|
||||
return (
|
||||
<div className={cn(classes, className)}>
|
||||
{showIcon && <AlertCircle className="h-12 w-12" strokeWidth={1.5} />}
|
||||
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-zinc-800">{title}</p>
|
||||
<p className="text-sm text-zinc-600">{errorMessage}</p>
|
||||
</div>
|
||||
|
||||
{onRetry && (
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
onClick={onRetry}
|
||||
className="mt-2 h-7 text-xs"
|
||||
>
|
||||
<RefreshCw className="mr-1 h-3 w-3" />
|
||||
{retryLabel}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorState;
|
||||
@@ -6,25 +6,36 @@ import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { BlockCategoryResponse } from "@/lib/autogpt-server-api";
|
||||
import { useBlockMenuContext } from "../block-menu-provider";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
const AllBlocksContent: React.FC = () => {
|
||||
const { addNode } = useBlockMenuContext();
|
||||
const [categories, setCategories] = useState<BlockCategoryResponse[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loadingCategories, setLoadingCategories] = useState<Set<string>>(
|
||||
new Set(),
|
||||
);
|
||||
|
||||
const api = useBackendAPI();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBlocks = async () => {
|
||||
const fetchBlocks = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await api.getBlockCategories();
|
||||
setCategories(response);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch block categories:", err);
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Failed to load block categories",
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchBlocks();
|
||||
}, [api]);
|
||||
|
||||
@@ -71,6 +82,18 @@ const AllBlocksContent: React.FC = () => {
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load blocks"
|
||||
error={error}
|
||||
onRetry={fetchBlocks}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200">
|
||||
<div className="w-full space-y-3 px-4 pb-4">
|
||||
@@ -93,7 +116,6 @@ const AllBlocksContent: React.FC = () => {
|
||||
|
||||
<div className="space-y-2">
|
||||
{category.blocks.map((block, idx) => (
|
||||
// It might go fail for agent block
|
||||
<Block
|
||||
key={`${category.name}-${idx}`}
|
||||
title={block.name}
|
||||
|
||||
@@ -1,30 +1,73 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, Fragment } from "react";
|
||||
import IntegrationBlock from "../IntegrationBlock";
|
||||
import { useBlockMenuContext } from "../block-menu-provider";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { Block } from "@/lib/autogpt-server-api";
|
||||
import ErrorState from "../ErrorState";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
|
||||
const IntegrationBlocks: React.FC = ({}) => {
|
||||
const { integration, setIntegration, addNode } = useBlockMenuContext();
|
||||
const [blocks, setBlocks] = useState<Block[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const api = useBackendAPI();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchBlocks = async () => {
|
||||
if (integration) {
|
||||
setIsLoading(true);
|
||||
const fetchBlocks = async () => {
|
||||
if (integration) {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await api.getBuilderBlocks({ provider: integration });
|
||||
setBlocks(response.blocks);
|
||||
setIsLoading(false);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch integration blocks:", err);
|
||||
setError(
|
||||
err instanceof Error
|
||||
? err.message
|
||||
: "Failed to load integration blocks",
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchBlocks();
|
||||
}, [api, integration]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full space-y-3 p-4">
|
||||
{[0, 1, 3].map((blockIndex) => (
|
||||
<Fragment key={blockIndex}>
|
||||
{blockIndex > 0 && (
|
||||
<Skeleton className="my-4 h-[1px] w-full text-zinc-100" />
|
||||
)}
|
||||
{[0, 1, 2].map((index) => (
|
||||
<IntegrationBlock.Skeleton key={`${blockIndex}-${index}`} />
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load integration blocks"
|
||||
error={error}
|
||||
onRetry={fetchBlocks}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2.5">
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -49,30 +92,19 @@ const IntegrationBlocks: React.FC = ({}) => {
|
||||
{blocks.length}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="space-y-3">
|
||||
{Array(5)
|
||||
.fill(0)
|
||||
.map((_, index) => (
|
||||
<IntegrationBlock.Skeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{blocks.map((block, index) => (
|
||||
<IntegrationBlock
|
||||
key={index}
|
||||
title={block.name}
|
||||
description={block.description}
|
||||
icon_url={`/integrations/${integration}.png`}
|
||||
onClick={() => {
|
||||
addNode(block);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-3">
|
||||
{blocks.map((block, index) => (
|
||||
<IntegrationBlock
|
||||
key={index}
|
||||
title={block.name}
|
||||
description={block.description}
|
||||
icon_url={`/integrations/${integration}.png`}
|
||||
onClick={() => {
|
||||
addNode(block);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,50 +1,59 @@
|
||||
import React from "react";
|
||||
import MarketplaceAgentBlock from "../MarketplaceAgentBlock";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { usePagination } from "@/hooks/usePagination";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
const MarketplaceAgentsContent: React.FC = () => {
|
||||
const { data: agents, loading, loadingMore, hasMore, error, scrollRef, refresh } = usePagination({
|
||||
request: { apiType: 'store-agents' },
|
||||
const {
|
||||
data: agents,
|
||||
loading,
|
||||
loadingMore,
|
||||
hasMore,
|
||||
error,
|
||||
scrollRef,
|
||||
refresh,
|
||||
} = usePagination({
|
||||
request: { apiType: "store-agents" },
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full space-y-3 p-4">
|
||||
{[0, 1, 2, 3, 4].map((index) => (
|
||||
<MarketplaceAgentBlock.Skeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load marketplace agents"
|
||||
error={error}
|
||||
onRetry={refresh}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200 transition-all duration-200"
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200"
|
||||
>
|
||||
<div className="w-full space-y-3 px-4 pb-4">
|
||||
{loading
|
||||
? Array(5)
|
||||
.fill(null)
|
||||
.map((_, index) => (
|
||||
<MarketplaceAgentBlock.Skeleton key={index} />
|
||||
))
|
||||
: agents.map((agent) => (
|
||||
<MarketplaceAgentBlock
|
||||
key={agent.slug}
|
||||
title={agent.agent_name}
|
||||
image_url={agent.agent_image}
|
||||
creator_name={agent.creator}
|
||||
number_of_runs={agent.runs}
|
||||
/>
|
||||
))}
|
||||
{error && (
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3">
|
||||
<p className="text-sm text-red-600 mb-2">
|
||||
Error loading marketplace agents: {error}
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={refresh}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{agents.map((agent) => (
|
||||
<MarketplaceAgentBlock
|
||||
key={agent.slug}
|
||||
title={agent.agent_name}
|
||||
image_url={agent.agent_image}
|
||||
creator_name={agent.creator}
|
||||
number_of_runs={agent.runs}
|
||||
/>
|
||||
))}
|
||||
{loadingMore && hasMore && (
|
||||
<>
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
|
||||
@@ -1,50 +1,59 @@
|
||||
import React from "react";
|
||||
import UGCAgentBlock from "../UGCAgentBlock";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { usePagination } from "@/hooks/usePagination";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
const MyAgentsContent: React.FC = () => {
|
||||
const { data: agents, loading, loadingMore, hasMore, error, scrollRef, refresh } = usePagination({
|
||||
request: { apiType: 'library-agents' },
|
||||
const {
|
||||
data: agents,
|
||||
loading,
|
||||
loadingMore,
|
||||
hasMore,
|
||||
error,
|
||||
scrollRef,
|
||||
refresh,
|
||||
} = usePagination({
|
||||
request: { apiType: "library-agents" },
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full space-y-3 p-4">
|
||||
{[0, 1, 2, 3, 4].map((index) => (
|
||||
<UGCAgentBlock.Skeleton key={index} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load library agents"
|
||||
error={error}
|
||||
onRetry={refresh}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200 transition-all duration-200"
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200"
|
||||
>
|
||||
<div className="w-full space-y-3 px-4 pb-4">
|
||||
{loading
|
||||
? Array(5)
|
||||
.fill(null)
|
||||
.map((_, index) => (
|
||||
<UGCAgentBlock.Skeleton key={index} />
|
||||
))
|
||||
: agents.map((agent) => (
|
||||
<UGCAgentBlock
|
||||
key={agent.id}
|
||||
title={agent.name}
|
||||
edited_time={agent.updated_at}
|
||||
version={agent.graph_version}
|
||||
image_url={agent.image_url}
|
||||
/>
|
||||
))}
|
||||
{error && (
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3">
|
||||
<p className="text-sm text-red-600 mb-2">
|
||||
Error loading library agents: {error}
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={refresh}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{agents.map((agent) => (
|
||||
<UGCAgentBlock
|
||||
key={agent.id}
|
||||
title={agent.name}
|
||||
edited_time={agent.updated_at}
|
||||
version={agent.graph_version}
|
||||
image_url={agent.image_url}
|
||||
/>
|
||||
))}
|
||||
{loadingMore && hasMore && (
|
||||
<>
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from "react";
|
||||
import React, { Fragment } from "react";
|
||||
import BlocksList from "./BlocksList";
|
||||
import Block from "../Block";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { BlockRequest } from "@/lib/autogpt-server-api";
|
||||
import { usePagination } from "@/hooks/usePagination";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
interface PaginatedBlocksContentProps {
|
||||
blockRequest: BlockRequest;
|
||||
@@ -14,34 +14,54 @@ const PaginatedBlocksContent: React.FC<PaginatedBlocksContentProps> = ({
|
||||
blockRequest,
|
||||
pageSize = 10,
|
||||
}) => {
|
||||
const { data: blocks, loading, loadingMore, hasMore, error, scrollRef, refresh } = usePagination({
|
||||
request: { apiType: 'blocks', ...blockRequest },
|
||||
const {
|
||||
data: blocks,
|
||||
loading,
|
||||
loadingMore,
|
||||
hasMore,
|
||||
error,
|
||||
scrollRef,
|
||||
refresh,
|
||||
} = usePagination({
|
||||
request: { apiType: "blocks", ...blockRequest },
|
||||
pageSize,
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full space-y-3 p-4">
|
||||
{[0, 1, 3].map((categoryIndex) => (
|
||||
<Fragment key={categoryIndex}>
|
||||
{categoryIndex > 0 && (
|
||||
<div className="my-4 h-[1px] w-full bg-zinc-100" />
|
||||
)}
|
||||
{[0, 1, 2].map((blockIndex) => (
|
||||
<Block.Skeleton key={`${categoryIndex}-${blockIndex}`} />
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="w-full px-4 pb-4">
|
||||
<ErrorState
|
||||
title="Failed to load blocks"
|
||||
error={error}
|
||||
onRetry={refresh}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200 transition-all duration-200"
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200"
|
||||
>
|
||||
<BlocksList blocks={blocks} loading={loading} />
|
||||
{error && (
|
||||
<div className="w-full px-4 pb-4">
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3">
|
||||
<p className="text-sm text-red-600 mb-2">
|
||||
Error loading blocks: {error}
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={refresh}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{loadingMore && hasMore && (
|
||||
<div className="w-full space-y-3 px-4 pb-4">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
@@ -53,4 +73,4 @@ const PaginatedBlocksContent: React.FC<PaginatedBlocksContentProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default PaginatedBlocksContent;
|
||||
export default PaginatedBlocksContent;
|
||||
|
||||
@@ -1,54 +1,63 @@
|
||||
import React from "react";
|
||||
import Integration from "../Integration";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useBlockMenuContext } from "../block-menu-provider";
|
||||
import { usePagination } from "@/hooks/usePagination";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
const PaginatedIntegrationList: React.FC = () => {
|
||||
const { setIntegration } = useBlockMenuContext();
|
||||
const { data: providers, loading, loadingMore, hasMore, error, scrollRef, refresh } = usePagination({
|
||||
request: { apiType: 'providers' },
|
||||
const {
|
||||
data: providers,
|
||||
loading,
|
||||
loadingMore,
|
||||
hasMore,
|
||||
error,
|
||||
scrollRef,
|
||||
refresh,
|
||||
} = usePagination({
|
||||
request: { apiType: "providers" },
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="w-full space-y-3 p-4">
|
||||
{[0, 1, 3].map((integrationIndex) => (
|
||||
<Integration.Skeleton key={integrationIndex} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load integrations"
|
||||
error={error}
|
||||
onRetry={refresh}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<div
|
||||
ref={scrollRef}
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200 transition-all duration-200"
|
||||
className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200"
|
||||
>
|
||||
<div className="w-full px-4 pb-4">
|
||||
<div className="space-y-3">
|
||||
{loading
|
||||
? Array(5)
|
||||
.fill(null)
|
||||
.map((_, index) => (
|
||||
<Integration.Skeleton key={index} />
|
||||
))
|
||||
: providers.map((integration, index) => (
|
||||
<Integration
|
||||
key={index}
|
||||
title={integration.name}
|
||||
icon_url={`/integrations/${integration.name}.png`}
|
||||
description={integration.description}
|
||||
number_of_blocks={integration.integration_count}
|
||||
onClick={() => setIntegration(integration.name)}
|
||||
/>
|
||||
))}
|
||||
{error && (
|
||||
<div className="rounded-lg border border-red-200 bg-red-50 p-3">
|
||||
<p className="text-sm text-red-600 mb-2">
|
||||
Error loading integrations: {error}
|
||||
</p>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={refresh}
|
||||
className="h-7 text-xs"
|
||||
>
|
||||
Retry
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{providers.map((integration, index) => (
|
||||
<Integration
|
||||
key={index}
|
||||
title={integration.name}
|
||||
icon_url={`/integrations/${integration.name}.png`}
|
||||
description={integration.description}
|
||||
number_of_blocks={integration.integration_count}
|
||||
onClick={() => setIntegration(integration.name)}
|
||||
/>
|
||||
))}
|
||||
{loadingMore && hasMore && (
|
||||
<>
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
@@ -62,4 +71,4 @@ const PaginatedIntegrationList: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default PaginatedIntegrationList;
|
||||
export default PaginatedIntegrationList;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
SuggestionsResponse,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
const SuggestionContent: React.FC = () => {
|
||||
const { setIntegration, setDefaultState, setSearchQuery, addNode } =
|
||||
@@ -16,27 +17,43 @@ const SuggestionContent: React.FC = () => {
|
||||
const [suggestionsData, setSuggestionsData] =
|
||||
useState<SuggestionsResponse | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const api = useBackendAPI();
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSuggestions = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await api.getSuggestions();
|
||||
setSuggestionsData(response);
|
||||
console.log(response);
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const fetchSuggestions = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
const response = await api.getSuggestions();
|
||||
setSuggestionsData(response);
|
||||
console.log(response);
|
||||
} catch (err) {
|
||||
console.error("Error fetching data:", err);
|
||||
setError(
|
||||
err instanceof Error ? err.message : "Failed to load suggestions",
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchSuggestions();
|
||||
}, [api]);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className="h-full p-4">
|
||||
<ErrorState
|
||||
title="Failed to load suggestions"
|
||||
error={error}
|
||||
onRetry={fetchSuggestions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="scrollbar-thumb-rounded h-full overflow-y-auto pt-4 transition-all duration-200 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-transparent hover:scrollbar-thumb-zinc-200">
|
||||
<div className="w-full space-y-6 pb-4">
|
||||
|
||||
Reference in New Issue
Block a user